Run Jenkins in a Docker container — part 1 — Docker-in-Docker


Guide for developers to get up and running with Jenkins running in Docker (on Windows).

Dave Sugden

This small series of guides will walk through three solutions for installing Jenkins in a Docker container on Windows, along with the configuration necessary to spin up dynamic build slaves also using Docker containers.

Running locally on a personal device is perfect for individual users, freelancers, or developers looking to do local Jenkinsfile or Shared Library development and testing before pushing to a central CI/CD platform.

“You said three solutions?” Yes — this article demonstrates using Docker-in-Docker (further reading at dind). Part 2 is using a socat container and Part 3 is to run Jenkins as root. Jump to those articles below.

Run Jenkins in a Docker container – part 2 – socat

Command line is all well and good, but it’s much easier to define as a docker compose yaml file. Here is the yaml for…

medium.com

Run Jenkins in a Docker container – part 3 – run as root user

This small series of guides will walk through three solutions for installing Jenkins in a Docker container on Windows…

medium.com

The steps we will go through;

  1. Command line, step-by-step to set up Jenkins.
  2. Configure Jenkins via the Console UI and set up the “docker” plugin.
  3. Verify the set up via a couple of test jobs.
  4. Translate the command lines into a Docker Compose template.

Prerequisites

We assume you have Docker installed — for this demo I am running on a Windows 10 laptop with WSL enabled (Hyper-V is also okay).

Volumes

Before we start up, create a volume that you will use for your Jenkins home directory — that way it will persist between restarts.

docker volume create jenkins-data

We’re going to create another volume for persisting and sharing the certificates so that Jenkins can talk to Docker-in-Docker.

docker volume create jenkins-docker-certs

Networking

We’re going to use a bridge network called jenkins which we create by running the command docker network create jenkins. In the rest of our configuration, we will attach all our containers to this network.

In order to give Jenkins access to the Docker daemon running on the host machine (Windows), we will use Docker-in-Docker.

docker container run –name jenkins-docker
–detach –restart unless-stopped
–privileged
–network jenkins –network-alias docker
–env DOCKER_TLS_CERTDIR=”/certs”
–volume jenkins-docker-certs:/certs/client
–volume jenkins-data:/var/jenkins_home
docker:dind

After running this command, a Docker-in-Docker container will be listening on port 2376 and since we gave it the network alias of docker then we will be able to reach it from Jenkins on tcp://docker:2376.

Notes:

  • on initial start-up, Docker will create client and server certificates under /certs — you will need these later when configuring the docker cloud.
  • variation. to skip TLS and use port 2375, set DOCKER_TLS_CERTDIR=””

Running Jenkins

We’re going to use the jenkinsci/blueocean image that comes pre-built with Blue Ocean. You will see that we specify tcp://docker:2376 as the Docker host and for security we need to verify certificates to the host — since we share the same volume we can find them in /certs/client (created by the host) which we map as read-only.

docker container run –name jenkins-blueocean
–detach –restart unless-stopped
–network jenkins
–env DOCKER_HOST=”tcp://docker:2376″
–env DOCKER_CERT_PATH=/certs/client
–env DOCKER_TLS_VERIFY=1
–volume jenkins-docker-certs:/certs/client:ro
–volume jenkins-data:/var/jenkins_home
–publish 8080:8080 –publish 50000:50000
jenkinsci/blueocean

Variation. Should you have chosen to skip TLS and are using port 2375 instead then these are the environment variables to use.

–env DOCKER_HOST=”tcp://docker:2375″
–env DOCKER_CERT_PATH=””
–env DOCKER_TLS_VERIFY=””

Now that Jenkins is started, head over to http://localhost:8080 to go through the initial set up wizard.

Jenkins Set Up Wizard

We won’t go through the Jenkins set up wizard in any detail — the important thing to note however is how to access your admin user unlock code, which you can find this from your running container via the following command:

docker exec jenkins-blueocean cat /var/jenkins_home/secrets/initialAdminPassword

Configuring Docker Cloud

Once you have your Jenkins set up complete, we need to set up running our Jenkins slaves as Docker containers. Head over to “Manage Plugins” and install the docker plugin.

Once installed, go to Manage Nodes and Clouds and then Configure Clouds and Add a new cloud. The type of “docker” should automatically appear in the dropdown.

You want to set the Docker Host URI to tcp://docker:2376 and then run a Test Connection. Unfortunately, you will see the following (misleading?) error — “Client sent an HTTP request to an HTTPS server” — and to solve this we need to set up the Server Credentials.

(if you decided to skip TLS and are using port 2375, your test should have worked and you will be able to jump over the next steps).

Click on the “Add” drop down and create an “X.509 Client Certificate”.

Remember that /certs directory? At start-up the Docker-in-Docker container generates client/server keys and we need three pieces of information to successfully talk to it over TLS.

  1. Client Key.
  2. Client Certificate.
  3. Server CA Certificate.

We can obtain these by running the following commands:

docker exec jenkins-docker cat /certs/client/key.pemdocker exec jenkins-docker cat /certs/client/cert.pemdocker exec jenkins-docker cat /certs/server/ca.pem

After creating your Credential, repeat the Test Connection and you should now be successful.

This is great — now we can reach the Docker daemon.

Configuring Docker Slaves/Agents

Next step is to set up an agent to run our pipelines against. Once you start developing, you can start building your own build containers and attaching these instead. For now, we shall use the jenkins/agent image.

Relevant fields below include giving it a label and name. The label allows you to associate a job to a particular agent — so you can always run a Maven build on an Agent that has maven installed, for example.

Our Connect Method will be Attach Docker Container. This runs the Docker container on the host machine (in our case, our host is Docker-in-Docker so that means we are running slaves inside the Docker-in-Docker container).

Save everything and you are now ready to create a test job.

Verifying it all works

To check that all is set up and working correctly, create a new freestyle job.

You want to select the agent that this job will run on.

And down under build, write a simple “hello world” message as a test.

Save and build your new job. Jenkins will download the image for your container and run the job upon it. On completion you should get output such as that shown below.

All done. Success!

What else?

If during execution you are interested to see which containers are running on your Docker-in-Docker container, run the following command.

docker exec -it jenkins-docker docker ps

Docker Compose

Command line is all well and good, but it’s much easier to define as a docker compose yaml file. Start up with docker-compose up -d.

version: ‘3.8’networks:
jenkins-network:
name: jenkinsvolumes:
data:
name: jenkins-data
certs:
name: jenkins-docker-certsservices: dind:
container_name: jenkins-docker
image: docker:dind
privileged: true
restart: unless-stopped
networks:
jenkins-network:
aliases:
– docker
volumes:
– data:/var/jenkins_home
– certs:/certs/client
environment:
– DOCKER_TLS_CERTDIR=/certs

jenkins:
container_name: jenkins-blueocean
image: jenkinsci/blueocean
restart: unless-stopped
networks:
– jenkins-network
ports:
– 8080:8080
– 50000:50000
volumes:
– data:/var/jenkins_home
– certs:/certs/client:ro
environment:
– DOCKER_HOST=tcp://docker:2376
– DOCKER_CERT_PATH=/certs/client
– DOCKER_TLS_VERIFY=1

This article discusses the pros and cons of Docker-in-Docker and argues against using it for CI systems like Jenkins.

I’ve followed up this article with two other approaches, parts 2 and 3 of this small series, that discuss alternatives that avoid using Docker-in-Docker.

Run Jenkins in a Docker container – part 2 – socat

Command line is all well and good, but it’s much easier to define as a docker compose yaml file. Here is the yaml for…

medium.com

Run Jenkins in a Docker container – part 3 – run as root user

This small series of guides will walk through three solutions for installing Jenkins in a Docker container on Windows…

medium.com

Thank you for reading this article and I hope you found time to read parts 2 and 3 as well — I hope you found them useful and via one of the articles you settled on a technique that suited your personal set up.

All source code for these articles can be found on GitHub.

You can follow me on Twitter and connect on LinkedIn.

Dave Sugden – Site Reliability Engineering (UK Lead) – Equifax UK | LinkedIn

View Dave Sugden’s profile on LinkedIn, the world’s largest professional community. Dave has 3 jobs listed on their…

linkedin.com


Leave a Comment

Your email address will not be published. Required fields are marked *