This post explains running jenkins in docker as a container and persisting the jenkins docker using docker volume. We will also explore using docker-compose
to simplify the process.
Terms
jenkins
– a ci/cd tooldocker
– container management platformdocker-compose
– tool to easily manage docker containers
Prerequisites
To get follow along, you need the following:
- Computer with
docker
anddocker-compose
installed - Access to terminal
- Access to run
docker
anddocker-compose
in the instance - Willingness to learn
Running Jenkins in docker
For the jenkins to run in docker, the jenkins docker image should exist in local machine. You can either pull the image manually using docker pull
or let docker download the image on the fly from docker hub on the fly.
To run jenkins in docker, we can either:
- Run it in the command line with using
docker run
command - Use
docker-compose
by adding the instructions in thedocker-compose.yaml
file
1. Running with docker-run
Use the command below to run jenkins on docker in the terminal:
docker run \
--name my-jenkins \
-p 8080:8080 \
jenkins/jenkins:latest
From the above command:
- The
--name
flag is used to assign the container created a friendly name. If not provided, a random name will be used. The-n
flag can also be used insead of--name
like-n my-jenkins
. You can update this to any name you wish to call your jenkins container like this--name different-name
- The
-p
command is used to specify port mapping, i.e. we want the container port to be exposed so it appears to be running locally. In the command, we are exposing container port 8080 where jenkins runs to out local machine so we can accesss it locally likehttp:127.0.0.1:8080/
. The format is-p [host-port:container-port]
. You can change thehost-port
to any port you want if for any reason you don’t want to use port8080
- the
jenkins/jenkins:latest
specifies the image to be used to run the container.
When you run the command above, docker will check if the image exist locally before creating it. If it doesn’t, it will pull the image first.
Result:
➜ docker run \
--name my-jenkins \
-p 8080:8080 \
jenkins/jenkins:latest
Unable to find image 'jenkins/jenkins:latest' locally
latest: Pulling from jenkins/jenkins
627b765e08d1: Pull complete
1910f590fd77: Pull complete
12178ff0ce06: Pull complete
fa1287d2553e: Pull complete
824d3abd3861: Pull complete
b2164a6d9edf: Pull complete
abed7b0f6892: Pull complete
46cbf2263be9: Pull complete
41682f248dd3: Pull complete
d6c9dfc4f3f8: Pull complete
9d078d5ad4ea: Pull complete
30562efa2608: Pull complete
49737ecd24c3: Pull complete
ebcf5270e311: Pull complete
cf5b02cd3b00: Pull complete
729f3c13e0f3: Pull complete
ee4db5d041b1: Pull complete
6c0166b3b956: Pull complete
Digest: sha256:61c0370cf163087387eaf9571b1a547fdb305648cd1bb96fb28155c424ef0d12
Status: Downloaded newer image for jenkins/jenkins:latest
Running from: /usr/share/jenkins/jenkins.war
webroot: EnvVars.masterEnvVars.get("JENKINS_HOME")
*************************************************************
*************************************************************
*************************************************************
Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:
be8c2b8833924aa4b7ce15c61767c5c5
This may also be found at: /var/jenkins_home/secrets/initialAdminPassword
*************************************************************
*************************************************************
*************************************************************
Once the container is up and running, verify by checking docker processes using the docker ps
command:
➜ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
28e8aee17ce9 jenkins/jenkins:latest "/sbin/tini -- /usr/…" About a minute ago Up About a minute 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 50000/tcp my-jenkins
To access the Jenkins service, visit http://127.0.0.1:8080
in your page. You will be prompted to do the initial jenkins set up by providing initial jenkins password, Adding plugins you want, and then setting up initial user and specifying the jenkins url.
jenkins data
The above jenkins will run fine. The only problem is containers are stateless and when its either stopped or if the host machine restarts and the data will be lost.
Jenkins stores its data in its home, the JENKINS_HOME
env var is exported and its value is the current jenkins home. We can log in to the container and investigate this:
➜ docker exec -it my-jenkins /bin/bash
jenkins@28e8aee17ce9:/$ echo ${JENKINS_HOME}
/var/jenkins_home
jenkins@28e8aee17ce9:/$ ls /var/jenkins_home
config.xml hudson.model.UpdateCenter.xml jenkins.telemetry.Correlator.xml logs nodes secret.key secrets updates users
copy_reference_file.log identity.key.enc jobs nodeMonitors.xml plugins secret.key.not-so-secret tini_pub.gpg userContent war
jenkins@28e8aee17ce9:/$
There is also a shorthand to run the command in a non interactive version without logging in to the container:
docker exec my-jenkins ls /var/jenkins_home
Persisting Jenkins Data
To persist the jenkins data, you can either copy it to your host machine so you be copying it back when you bring up a new instance. docker cp
is used to copy data from and to the container.
This is the format
docker cp <container id>:/path/in/container /path/in/host
Command:
➜ docker cp my-jenkins:/var/jenkins_home ./jenkins_home
➜ ls jenkins_home
config.xml jenkins.telemetry.Correlator.xml nodes secrets users
copy_reference_file.log jobs plugins tini_pub.gpg war
hudson.model.UpdateCenter.xml logs secret.key updates
identity.key.enc nodeMonitors.xml secret.key.not-so-secret userContent
Using docker volumes
Docker volume allows you to persist data generated by and used by Docker containers.
The -v
command line option can be used with docker run
to specify directories to be mounted locally. We can use the following command to mount the jenkins home /var/jenkins_home
to the local ./jenkins_home
firectory.
docker run \
--name my-jenkins \
-p 8080:8080 \
-v ~/jenkins_home:/var/jenkins_home \
jenkins/jenkins:latest
Confirming
❯ docker run -d \
--name my-jenkins \
-p 8080:8080 \
-v ~/jenkins_home:/var/jenkins_home \
jenkins/jenkins:latest
45e90dcd6fe7cd21697d885ac691c4f8f47d3f76793a666840ea87020c5a33ae
➜ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
45e90dcd6fe7 jenkins/jenkins:latest "/sbin/tini -- /usr/…" 12 seconds ago Up 10 seconds 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 50000/tcp my-jenkins
To know where in the filesystem is the jenkins_home location can be found, use the docker volume command.
➜ docker volume inspect jenkins_home
[
{
"CreatedAt": "2021-08-11T11:13:55Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/jenkins_home/_data",
"Name": "jenkins_home",
"Options": null,
"Scope": "local"
}
]
Running Jenkins with Docker Compose
With Docker Compose, you can easily deploy one or more instances of Jenkins. You need to create a Docker Compose file and have docker-compose
command installed.
The Docker Compose expects a docker-compose.yaml
file by default in the current working directory but you can use a different name for the yaml file then use -f <file-name>.yaml
to instruct docker-compose
to use it.
This is a docker-compose.yaml
file to launch jenkins:
version: '3.9'
services:
jenkins:
image: jenkins/jenkins:latest
container_name: my-jenkins
ports:
- 8080:8080
volumes:
- ~/jenkins_data:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
In the above:
version
– is the docker-compose versionservices
– defines the containers we want to launchimage
– base image for creating docker container instancecontainer_name
– is the friendly name for our containerports
– for the ports exposed. Its the port mapping between the Docker host and the containervolumes
– port mapping between the Docker host and the
Starting the jenkins instance
use the command below
Start the instance in daemon mode -d
. This command docker-compose up -d
:
➜ docker-compose up -d
Creating network "xxx_default" with the default driver
Creating my-jenkins ... done
Check docker processes using the docker-compose ps
command
➜ docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------------
my-jenkins /sbin/tini -- /usr/local/b ... Up 50000/tcp, 0.0.0.0:8080->8080/tcp,:
::8080->8080/tcp
Get the initial password:
docker exec my-jenkins cat /var/jenkins_home/secrets/initialAdminPassword
Stopping jenkins when needed:
➜ docker-compose stop
Stopping my-jenkins ... done
➜ docker-compose rm
Going to remove my-jenkins
Are you sure? [yN] y
Removing my-jenkins ... done
Cleaning up
Stop and remove the docker container
➜ docker stop my-jenkins
my-jenkins
❯ docker rm my-jenkins
my-jenkins