Hello. So, you need to run Docker inside Docker for your CI server, or some other legitimate reason? Sorry, this isn’t the blog for you. (If that is legitimately what you’re looking for, might I suggest this blog?)
I want to know if it’s possible to recursively run Docker-in-Docker. And I’m not talking running sibling containers via mounting the
/var/run/docker.sock or anything sane. I want proper containers inside containers inside containers. Success for me is if I can run a command that indefinitely spins up child container until my computer breaks.
Part 1: Proving the concept
So, first things first, let’s mosey on over the official docker-in-docker image on the docker hub. Feel free to ignore the bothersome
Docker inside Docker is generally not recommended
And let’s give it a whirl with
docker run -it --privileged docker:dind
Amazingly, on the first try, after it does it’s thing we actually get a running docker daemon:
INFO[2021-10-22T15:41:30.526668700Z] Default bridge (docker0) is assigned with an IP address 172.18.0.0/16. Daemon option --bip can be used to set a preferred IP address INFO[2021-10-22T15:41:30.567729100Z] Loading containers: done. INFO[2021-10-22T15:41:30.584627900Z] Docker daemon commit=79ea9d3 graphdriver(s)=overlay2 version=20.10.9 INFO[2021-10-22T15:41:30.584825900Z] Daemon has completed initialization INFO[2021-10-22T15:41:30.648761900Z] API listen on /var/run/docker.sock INFO[2021-10-22T15:41:30.653327200Z] API listen on [::]:2376
Now, lets verify that this is a functional docker instance and is not running sibling containers
Functional docker instance
In a new shell, a quick:
docker exec -it strange_kalam /bin/sh
/ # docker run -it ubuntu bash Unable to find image 'ubuntu:latest' locally latest: Pulling from library/ubuntu 7b1a6ab2e44d: Pull complete Digest: sha256:626ffe58f6e7566e00254b638eb7e0f3b11d4da9675088f4781a50ae288f3322 Status: Downloaded newer image for ubuntu:latest root@4b8dc3537c11:/#
Shows me that it’s working properly!
Verify it’s not running a sibling container
ubuntu image still running from above, we can open yet another new shell and just double check that that container isn’t running on the hosts docker instance:
❯ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d509c72b66d2 docker:dind "dockerd-entrypoint.…" 6 minutes ago Up 6 minutes 2375-2376/tcp strange_kalam
No other container are running on the host beyond that
docker:dind. Wonderful! Now we’re cooking with gas.
Part 2: It’s all about execution
So, what I’d like is a single docker run command which starts off this insanity. To do this, I’m going to create my own image based on the
docker:dind one which only adds one tiny-winy change: Recursion.
Let’s start look at the existing
docker:dind Dockerfile, all I really care about is the bit at the end since I’ll need to wrap the existing entrypoint:
With this knowledge, I can write a quick little
FROM docker:dind # Because I'm not brave enough to write vanilla /bin/sh RUN apk add bash # Copy in entrypoint-wrapper.sh COPY entrypoint-wrapper.sh /usr/local/bin/ ENTRYPOINT [ "entrypoint-wrapper.sh" ]
#!/bin/bash # turn on bash's job control set -m # Start the dockerd daemon and put it in the background dockerd-entrypoint.sh & # Wait until the daemon comes up while ! docker ps do echo "Waiting for docker daemon..." sleep 2 done # Run this image again inside the container docker run --privileged aaronnbrock/docker-in-docker-in-docker
Build and push it to the docker hub
And… does it work? Well, only one way for you to find out, give this command a try:
docker run --privileged aaronnbrock/docker-in-docker-in-docker
So, what did we learn today? Well, I don’t know, I’ll leave that one up to you…