Experiment: Start Jenkins servers recursively with Docker

Remy DeWolf
4 min readDec 19, 2017

--

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…

What we want to achieve: running nested Jenkins servers using docker

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:

See full Dockerfile in github

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.

Check the full job config.xml in github

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.

Build the job to start another Jenkins server

Look for the “Jenkins is fully up and running” message.

It takes a few seconds to start a new Jenkins

There is now, a second instance of Jenkins up at port 8081.

Running the job will now start a Jenkins server on port 8082

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.

Running docker ps on the host shows all the containers started.

All the docker daemons are actually referring to the host, to confirm this we can run docker ps in one of the container:

Running docker ps in one of the instance gives the same output

Under the hood, the containers were started on the host.

All containers were started in the same Docker daemon, 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.

--

--

No responses yet