Docker in Docker in Docker in...
Intro
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?)
Goal
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
And a:
/ # 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
With the 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:
ENTRYPOINT ["dockerd-entrypoint.sh"]
With this knowledge, I can write a quick little Dockerfile
+ entrypoint-wrapper.sh
:
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
Conclusion
So, what did we learn today? Well, I don’t know, I’ll leave that one up to you…