CI as Code Part II: Stateless Jenkins With Dynamic Docker Slaves


This article continues on from part one of this series, which looks at ‘CI as code’ using Docker to set up isolated and reproducible phoenix deployments of Jenkins deployments

Here I add dynamic Docker containers as on-demand Jenkins nodes in a Docker cloud.


This is now baked into v2.0 of the git repo.


Here’s a video of the stateless setup of the Docker cloud, and the job ‘docker-test’ which dynamically provisions a Docker container to run as a Jenkins slave.

What it does

  1. Starts up Jenkins container with a server config config.xml preloaded
  2. ‘jenkinssetup’ container waits for Jenkins to be up and ready
  3. Sets up global credentials
  4. Updates Jenkins’ config.xml with the credentials id
  5. Restart Jenkins and wait for jenkins to be ready
  6. Kick off install of plugins
  7. Periodically restart Jenkins until plugins confirmed installed
  8. Upload job configurations


The Docker plugins for Jenkins are generally poorly documented and fiddly to set up. And between them there’s quite a few, so the Docker options in a job available can get quite confusing. This took a little bit of trial and error before I could reliably get it to work.

To allow dynamic Docker provisioning, I used the standard docker plugin, mainly because it was the only one I ended up getting working with my Jenkins-in-docker-compose approach.

To get a dynamic on-demand Docker instance provisioned for every build, you have to set up a Docker cloud with the details of the Docker host to contact to spin up the container. This cloud is given a label, which you use in your job to specify that it should be run in a Docker container.

Currently co-authoring a book on Docker:

Get 39% off with the code 39miell


Note: If you want to recreate this you must have an opened-up Docker daemon.
See here for a great guide on this. Once that’s done you may need to change the
docker host address in the docker.xml field to point to your opened up Docker
daemon. Usually this is with the IP address outputted from ‘ip route’ in your
running containers. The default in the git repo is fine, assuming you have opened
it up on port 4243.

Like what you read? Give Ian Miell a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.