#Publish a container image using another service's rootfs

1 messages · Page 1 of 1 (latest)

obsidian junco
#

I'm trying to leverage Dagger to: 1) start a docker-in-docker container; 2) start a docker cli container to ask the docker-in-docker dockerd to pull an image; 3) snapshot the docker-in-docker container as a docker image w/ the graph / snapshotter files in place.

I'm getting stuck on (3) because it appears that Dagger thinks I want the cache layers of the dind container instead of the container's backing volume state.

Here's what I have so far:

import { NetworkProtocol, connect } from "@dagger.io/dagger";

connect(
  async (client) => {
    const varLibDocker = client.cacheVolume("docker");

    // Set up my docker in docker container
    const dindPort = 4567;
    const dindContainer = client
      .container()
      .from("docker:24-dind")
      .withEnvVariable("DOCKER_TLS_CERTDIR", "")
      .withExec(["dockerd", `--host=tcp://0.0.0.0:${dindPort}`], {
        insecureRootCapabilities: true,
      })
      .withMountedCache("/var/lib/docker", varLibDocker)
      .withExposedPort(dindPort, {
        protocol: NetworkProtocol.Tcp,
      });

    // Get a service reference to the dind container
    const dind = dindContainer.asService();

    // Use another container
    await client
      .container()
      .from("docker:24")
      .withServiceBinding("dind", dind)
      .withExec([
        "docker",
        `--host=tcp://dind:${dindPort}`,
        "pull",
        "node:20-alpine",
      ])
      .sync();

    // Dont' need the service anymore
    await dind.stop();

    // Now create a new dind container and add the seeded dind
    // container's /var/lib/docker.
    // This seems to restart the dindContainer.
    await client
      .container()
      .from("docker:24-dind")
      .withDirectory(
        "/var/lib/docker",
        dindContainer.rootfs().directory("/var/lib/docker")
      )
      .publish("plnkr-dind:latest");
  },
  { LogOutput: process.stderr }
);
obsidian junco
#

I got this mostly working but couldn't figure out how if dagger itself can push the image to the docker engine to which it's connected or not.

import { NetworkProtocol, connect } from "@dagger.io/dagger";

connect(
  async (client) => {
    const varLibDocker = client.directory();

    // Set up my docker in docker container
    const dindPort = 4567;
    const dindContainer = client
      .container()
      .from("docker:24-dind")
      .withEnvVariable("DOCKER_TLS_CERTDIR", "")
      .withDirectory("/var/lib/docker", varLibDocker)
      .withExposedPort(dindPort, {
        protocol: NetworkProtocol.Tcp,
      });

    // Get a service reference to the dind container
    const dind = dindContainer
      .withExec(["dockerd", `--host=tcp://0.0.0.0:${dindPort}`], {
        insecureRootCapabilities: true,
      })
      .asService();

    // Use another container
    await client
      .container()
      .from("docker:24")
      .withServiceBinding("dind", dind)
      .withExec([
        "docker",
        `--host=tcp://dind:${dindPort}`,
        "pull",
        "node:20-alpine",
      ])
      .sync();

    // Dont' need the service anymore
    await dind.stop();

    // Now create a new dind container and add the seeded dind
    // container's /var/lib/docker.
    // This seems to restart the dindContainer.
    await client
      .container()
      .from("docker:24-dind")
      .withDirectory("/var/lib/docker", varLibDocker)
      .export("./.build/plnkr-dind.tar");
  },
  { LogOutput: process.stderr }
);
#

False alarm. The resulting image loaded via docker load -i doesn't seem to have the /var/lib/docker contents.

obsidian junco
#

Added some logging and getting an empty 2nd array when I would have expected the entries from the dind container's mounted /var/lib/docker directory. ```js
import { NetworkProtocol, connect } from "@dagger.io/dagger";

connect(
async (client) => {
const varLibDocker = client.directory();

// Set up my docker in docker container
const dindPort = 4567;

// Get a service reference to the dind container
const dind = client
  .container()
  .from("docker:24-dind")
  .withEnvVariable("DOCKER_TLS_CERTDIR", "")
  .withMountedDirectory("/var/lib/docker", varLibDocker)
  .withExposedPort(dindPort, {
    protocol: NetworkProtocol.Tcp,
  })
  .withExec(
    ["dockerd", `--host=tcp://0.0.0.0:${dindPort}`, "--storage-driver=vfs"],
    {
      insecureRootCapabilities: true,
    }
  )
  .asService();

await dind.start();

// Empty array (expected)
console.log("ENTRIES BEFORE", await varLibDocker.entries());

// Use another container
await client
  .container()
  .from("docker:24")
  .withServiceBinding("dind", dind)
  .withExec([
    "docker",
    `--host=tcp://dind:${dindPort}`,
    "pull",
    "node:20-alpine",
  ])
  .sync();

// Dont' need the service anymore
await dind.stop();

// Empty array (unexpeted)
console.log("ENTRIES AFTER", await varLibDocker.entries());

// Now create a new dind container and add the seeded dind
// container's /var/lib/docker.
// This seems to restart the dindContainer.
await client
  .container()
  .from("docker:24-dind")
  .withDirectory("/var/lib/docker", varLibDocker)
  .export("./.build/plnkr-dind.tar");

},
{ LogOutput: process.stderr }
);

obsidian junco
#

It seems that once I create a service out of a container, I can no longer reference the container without having two copies: 1) the container; and 2) the service.

smoky widget