Running Jenkins in Docker With Docker Compose

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 tool
  • docker – container management platform
  • docker-compose – tool to easily manage docker containers

Prerequisites

To get follow along, you need the following:

  • Computer with docker and docker-compose installed
  • Access to terminal
  • Access to run docker and docker-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:

  1. Run it in the command line with using docker run command
  2. Use docker-compose by adding the instructions in the docker-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 like http:127.0.0.1:8080/. The format is -p [host-port:container-port]. You can change the host-port to any port you want if for any reason you don’t want to use port 8080
  • 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:

&#x279C; docker cp my-jenkins:/var/jenkins_home ./jenkins_home
&#x279C; 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

&#x276F; docker run -d \
    --name my-jenkins \
    -p 8080:8080 \
    -v ~/jenkins_home:/var/jenkins_home \
    jenkins/jenkins:latest
45e90dcd6fe7cd21697d885ac691c4f8f47d3f76793a666840ea87020c5a33ae

&#x279C; docker ps
CONTAINER ID   IMAGE                    COMMAND                  CREATED          STATUS          PORTS                                                  NAMES
45e90dcd6fe7   jenkins/jenkins:latest   "/sbin/tini -- /usr/&#x2026;"   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.

&#x279C; 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: &#039;3.9&#039;
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 version
  • services – defines the containers we want to launch
  • image – base image for creating docker container instance
  • container_name – is the friendly name for our container
  • ports – for the ports exposed. Its the port mapping between the Docker host and the container
  • volumes – 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:

&#x279C; 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

&#x279C; 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:

&#x279C; docker-compose stop
Stopping my-jenkins ... done

&#x279C; 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

&#x279C; docker stop my-jenkins
my-jenkins

&#x276F; docker rm my-jenkins
my-jenkins
comments powered by Disqus
Citizix Ltd
Built with Hugo
Theme Stack designed by Jimmy