Experiment: Start Jenkins servers recursively with Docker
Have you ever heard of running Docker within Docker?
Now, imagine you have a Jenkins container which can run Docker, would that image be able to start itself? We could repeat the process and have the new container to start another instance, and repeat…
1. Configure Docker in Docker for the Jenkins image
First let’s modify the official Jenkins Dockerfile to install docker. This image extends a Linux Debian distribution, we can configure the Debian repo and use apt-get to install docker.
Here are the instructions added to the Dockerfile:
2. Allow Jenkins to start another Jenkins instance
Now that Jenkins is able to run a Docker command, let’s configure a job to start another instance of Jenkins. The requirements are:
- Always run the same docker command to start Jenkins, so it can be repeated.
- The TCP server port has to be different for each new server.
Here is a simple shell script that would do the job. An environment variable is used to store the TCP port, it is incremented when running the new container.
3. Expose the Docker socket to your CI container
We want the container to be able to start container, the easiest way to achieve this is to mount to the Docker socket using a volume.
Start the Jenkins container with the param-v/var/run/docker.sock:/var/run/docker.sock
4. Run the experiment
This Docker image was uploaded to dockerhub and can be started from command line.
$ docker run -p 8080:8080 -e JENKINS_PORT=8080 --rm -v /var/run/docker.sock:/var/run/docker.sock --name jenkins remydewolf/jenkins-in-jenkins
This will start Jenkins at http://localhost:8080
Once Jenkins is up, we can start another Jenkins instance by building start-new-jenkins.
Look for the “Jenkins is fully up and running” message.
There is now, a second instance of Jenkins up at port 8081.
To run the experiment, we can repeat this process a few times.
How does it work?
When starting the container from Jenkins, it is actually started on the host daemon. We can confirm this by running docker ps.
All the docker daemons are actually referring to the host, to confirm this we can run docker ps in one of the container:
Under the hood, the containers were started on the host.
In conclusion, here is a quote from Jérôme Petazzoni about this solution:
This looks like Docker-in-Docker, feels like Docker-in-Docker, but it’s not Docker-in-Docker: when this container will create more containers, those containers will be created in the top-level Docker. You will not experience nesting side effects, and the build cache will be shared across multiple invocations.
For more info on this topic, check out these great resources: