Build and test Docker images with DIND

I was recently asked how one could build and then test a container using a docker-in-docker service container. Below is a contrived example that demonstrates how this is technically possible. The example is completely self contained, which means you can copy this and run with drone exec, if you want.

So what are the pros and cons to this approach? The pro is that your pipeline is isolated from the host machine. The cons are that pipelines are ephemeral which means docker layers are not persisted between builds. Also the dind images runs in privileged mode, which means a bad actor could break out of the container runtime and access your host machine. This should only be used in trusted environments (behind the firewall, private repositories, etc).

kind: pipeline
type: docker
name: default

steps:
  # this code will create a dummy Dockerfile. This is just
  # here so that our yaml file is self-contained.
  - name: setup
    image: golang
    commands:
      - |
        cat <<EOF > index.html
        hello world
        EOF
      - |
        cat <<EOF > Dockerfile
        FROM busybox
        ADD index.html /www/index.html
        EXPOSE 8000
        CMD httpd -p 8000 -h /www; tail -f /dev/null
        EOF

  - name: build
    image: docker:17.05.0-ce-dind
    environment:
      - DOCKER_HOST=tcp://docker:2375
    commands:
      - sleep 5
      - docker ps
      - docker build -t hello-world .
  
  # start the container using a detached (non-blocking)
  # step. Bonus we can see our container logs in the
  # build output.
  - name: run
    image: docker:17.05.0-ce-dind
    detach: true
    environment:
      - DOCKER_HOST=tcp://docker:2375
    commands:
      - docker run -p 8000:8000 hello-world

  # this container just runs a docker ps to verify
  # our container is running. Just for demo purposes,
  # not really needed.
  - name: check_running
    image: docker:17.05.0-ce-dind
    environment:
      - DOCKER_HOST=tcp://docker:2375
    commands:
      - sleep 5
      - docker ps

  # curl the container to test it is up and running.
  # notice that we use `docker:8000` since the container
  # is running in the docker service container.
  - name: test
    image: golang # because I know it has curl installed
    commands:
      - curl -v http://docker:8000

services:
  docker:
    image: docker:17.05.0-ce-dind
    privileged: true
3 Likes

Sounds great. Looks like there is no arm v7 dind image build.

I recommend opening an issue with the Docker team for this. As I recall, they did not ship arm or arm64 images because the official install script (https://get.docker.com/) did not support those architectures. This has since changed, so perhaps now they would consider shipping an armv7 image.

EDIT: apparently I created an issue for this a while back. See publish arm32v7 image · Issue #67 · docker-library/docker · GitHub

EDIT: according the the library/docker manifest it looks like they have official linux arm images available for download. If you run docker pull docker:18.02.0-ce-dind on arm it should pull the arm version of the image. They appear to officially support arm v6 and v8.

{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
   "manifests": [
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 2406,
         "digest": "sha256:1e5a88ca67d389706577b035a366f0a42e7b5c69da519ab0bf649c76680b1bd5",
         "platform": {
            "architecture": "amd64",
            "os": "linux"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 2613,
         "digest": "sha256:e3e527e8d528a33aa671105d95d01a30a81c9d1a75ed07587f58461b674c0038",
         "platform": {
            "architecture": "arm",
            "os": "linux",
            "variant": "v6"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 2613,
         "digest": "sha256:8188e6c6e5959a8e2a1320101298fb6a9e5e0ad5354a4f98149ee4d4ef886ad1",
         "platform": {
            "architecture": "arm64",
            "os": "linux",
            "variant": "v8"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 2613,
         "digest": "sha256:e8f8be64fec739a4ac26a51a86b41905ffb71d3afa15b2ceaf5ef81fe04aae78",
         "platform": {
            "architecture": "ppc64le",
            "os": "linux"
         }
      },
      {
         "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
         "size": 2613,
         "digest": "sha256:e1a478d4dd9eae57f4de02467da6cb2ab948c10ab0b501ebd5688fc4619b88c6",
         "platform": {
            "architecture": "s390x",
            "os": "linux"
         }
      }
   ]
}

Ok, pull command worked on armv7 scaleway machine. I will try then you approach for testing docker images as we use amd64 and armv7 agents.
Thanks for helping!

If I followed the recommendations from the dockerhub page:
Docker hub page
specifically under the heading

Custom daemon flags
Is there a way in the yaml to set the storage-driver or a custom dns?

docker run --privileged --name some-overlay-docker -d docker:dind --storage-driver=overlay

This is cool, I’m already trying it on 1.0.0.rc3

I’ve noticed, however, that detached steps go on forever, and the pipeline never ends. Is this the normal behavior?

My plan is to:

  1. Restore a cache using the Drone S3 cache plugin.
  2. Start Docker DIND, mounting the cache as the DIND storage, so I can preserve cached layers.
  3. Run my tests - using docker-compose within the Drone build.

For that, it looks like I need to start DIND as a step rather than as a service… but whenever the following steps finish, the DIND step keeps running forever!

I’ve noticed, however, that detached steps go on forever, and the pipeline never ends. Is this the normal behavior?

nope, you can see an example of a detached step configuration here: hello-world/.drone.yml at test-detached · drone/hello-world · GitHub

and live results here where the pipeline completes successfully here:

For that, it looks like I need to start DIND as a step rather than as a service

we provide a sample configuration that starts the dind container as a service at the following link. note that a docker run command would need to be run in detached mode, since it is a blocking command. https://docs.drone.io/pipeline/docker/examples/services/docker_dind/

1 Like