Setup Jenkins on Docker: Windows/Linux Tutorial & Best Practices

What Is Jenkins?

Jenkins is an open-source automation server that enables developers to build, test, and deploy their software reliably. The idea behind Jenkins is continuous integration (CI), where developers integrate code into a shared repository several times a day. Each commit prompts an automated build and testing process, making it easier to detect errors early. 

DevOps teams often use Jenkins to improve software development pipelines, ensuring swift identification of defects and boosting productivity. Jenkins supports various version control tools like Git, SVN, and Mercurial, and integrates well with numerous testing and deployment technologies. It has over 2,000 plugins, allowing users to customize workflows to fit their needs.

What Is Docker?

Docker is an open-source platform to automate the deployment, scaling, and management of applications using containerization. Containers encapsulate applications and their dependencies into a portable, lightweight unit, ensuring consistent runtime environments. This eliminates the “works on my machine” problem, as containers can run uniformly across diverse environments.

Docker simplifies application deployment by allowing developers to package applications with everything needed to run, including libraries, binaries, and configuration files. It supports microservices architecture, enabling the development of modular, loosely coupled services that can be independently deployed and scaled.

Jenkins is increasingly used in containerized environments, and a common use case is to setup Jenkins on a Docker container. We’ll show how to do this and provide some best practices for successfully deploying Jenkins on Docker.

Tutorial: Setup Jenkins on Docker

The instructions in this tutorial are adapted from the Jenkins documentation.

Prerequisites

Before setting up Jenkins on Docker, ensure your system meets the following requirements:

Minimum hardware requirements:
  • RAM: 256 MB
  • Drive space: 1 GB (10 GB recommended when running Jenkins as a Docker container)
  • RAM: 4 GB or more
  • Drive space: 50 GB or more
Software requirements:
  • Java: Java 17 or Java 21
  • Web browser:
    • Chrome: Latest regular release (L1), Version N-1 or latest patch (L2)
    • Firefox: Latest regular or ESR release (L1), Version N-1 or latest patch (L2)
    • Edge: Latest regular release (L1), Version N-1 or latest patch (L2)
    • Safari: Latest regular release (L1), Version N-1 or latest patch (L2)
  • Operating systems:
    • Windows: 64-bit (amd-64) Windows Server versions, .NET Framework 4.0 or above required for Jenkins 2.238 and up  
    • Linux: 64-bit (amd64) Linux versions (Debian, OpenSUSE) 
  • Servlet containers: Automated tests are run for L1 servlet containers, no guarantees for L2, L3 unsupported
Install Docker:
  • Ensure Docker is installed on your system. Follow the instructions provided in the Docker documentation to install Docker on your operating system. 
  • For Linux systems, configure Docker to be managed as a non-root user and set it to start on boot by following the steps in Docker’s Post-installation documentation.

Download and Run Jenkins in Docker

On macOS and Linux

To set up Jenkins Docker on Linux or macOS, follow these steps:

  1. Create a bridge network: Open a terminal window and create a Docker bridge network:
docker network create jenkins
  1. Run Docker-in-Docker (dind) container: This is a technique that allows Docker to run inside a Docker container. This setup is often used in CI/CD pipelines to build, test, and deploy applications in isolated environments without requiring Docker on the host system. Execute the following command to run a Docker-in-Docker container:
docker run \
  --name jenkins-docker \
  --rm \
  --detach \
  --privileged \
  --network jenkins \
  --network-alias docker \
  --env DOCKER_TLS_CERTDIR=/certs \
  --volume jenkins-docker-certs:/certs/client \
  --volume jenkins-data:/var/jenkins_home \
  --publish 2376:2376 \
  docker:dind \
  --storage-driver overlay2

Explanation of options used:

  • --name jenkins-docker: Names the Docker container “jenkins-docker”.
  • --rm: Automatically removes the container when it is shut down.
  • --detach: Runs the container in the background.
  • --privileged: Grants the container extended privileges.
  • --network jenkins: Connects the container to the “jenkins” network.
  • --network-alias docker: Sets an alias for the container within the network.
  • --env DOCKER_TLS_CERTDIR=/certs: Specifies the directory for TLS certificates.
  • --volume jenkins-docker-certs:/certs/client: Maps the /certs/client directory to a Docker volume.
  • --volume jenkins-data:/var/jenkins_home: Maps the Jenkins home directory to a Docker volume.
  • --publish 2376:2376: Exposes port 2376 on the host.
  1. Create and customize Dockerfile: Create a Dockerfile with the following content to customize the Jenkins Docker image:
FROM jenkins/jenkins:2.452.3-jdk17
USER root
RUN apt-get update && apt-get install -y lsb-release
RUN curl -fsSLo /usr/share/keyrings/docker-archive-keyring.asc \
  https://download.docker.com/linux/debian/gpg
RUN echo "deb [arch=$(dpkg --print-architecture) \
  signed-by=/usr/share/keyrings/docker-archive-keyring.asc] \
  https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
RUN apt-get update && apt-get install -y docker-ce-cli
USER jenkins
RUN jenkins-plugin-cli --plugins "blueocean docker-workflow"
  1. Build and run Jenkins image: Build the Docker image:
docker build -t myjenkins-blueocean:2.452.3-1 .

Run the Jenkins container using the custom image:

docker run \
  --name jenkins-blueocean \
  --restart=on-failure \
  --detach \
  --network jenkins \
  --env DOCKER_HOST=tcp://docker:2376 \
  --env DOCKER_CERT_PATH=/certs/client \
  --env DOCKER_TLS_VERIFY=1 \
  --publish 8080:8080 \
  --publish 50000:50000 \
  --volume jenkins-data:/var/jenkins_home \
  --volume jenkins-docker-certs:/certs/client:ro \
  Myjenkins-blueocean:2.452.3-1

Explanation of options used:

  • --name jenkins-blueocean: Names the Docker container “jenkins-blueocean”.
  • --restart=on-failure: Restarts the container if it stops.
  • --detach: Runs the container in the background.
  • --network jenkins: Connects the container to the “jenkins” network.
  • --env DOCKER_HOST=tcp://docker:2376: Specifies the Docker host.
  • --env DOCKER_CERT_PATH=/certs/client: Specifies the path to Docker TLS certificates.
  • --env DOCKER_TLS_VERIFY=1: Enables TLS verification.
  • --publish 8080:8080: Maps port 8080 on the container to port 8080 on the host.
  • --publish 50000:50000: Maps port 50000 on the container to port 50000 on the host.
  • --volume jenkins-data:/var/jenkins_home: Maps the Jenkins home directory to a Docker volume.
  • --volume jenkins-docker-certs:/certs/client:ro: Maps the /certs/client directory to a Docker volume with read-only access.

On Windows

To set up Jenkins Docker on a Windows system, follow these steps:

  1. Switch to Linux containers: Ensure Docker for Windows is configured to run Linux containers. Refer to the Docker documentation for instructions on switching to Linux containers.
  2. Create a bridge network: Open a command prompt window and create a Docker bridge network:
docker network create jenkins
  1. Run Docker-in-Docker (dind) container: Execute the following command to run a Docker-in-Docker container:
docker run --name jenkins-docker --rm --detach ^
  --privileged --network jenkins --network-alias docker ^
  --env DOCKER_TLS_CERTDIR=/certs ^
  --volume jenkins-docker-certs:/certs/client ^
  --volume jenkins-data:/var/jenkins_home ^
  --publish 2376:2376 ^
  docker:dind
  1. Create and customize Dockerfile: Create a Dockerfile with the following content to customize the Jenkins Docker image:
FROM jenkins/jenkins:2.452.3-jdk17
USER root
RUN apt-get update && apt-get install -y lsb-release
RUN curl -fsSLo /usr/share/keyrings/docker-archive-keyring.asc \
  https://download.docker.com/linux/debian/gpg
RUN echo "deb [arch=$(dpkg --print-architecture) \
  signed-by=/usr/share/keyrings/docker-archive-keyring.asc] \
  https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
RUN apt-get update && apt-get install -y docker-ce-cli
USER jenkins
RUN jenkins-plugin-cli --plugins "blueocean docker-workflow"
  1. Build and run Jenkins image: Build the Docker image:
docker build -t myjenkins-blueocean:2.452.3-1 .

Run the Jenkins container using the custom image:

docker run --name jenkins-blueocean --restart=on-failure --detach ^
  --network jenkins --env DOCKER_HOST=tcp://docker:2376 ^
  --env DOCKER_CERT_PATH=/certs/client --env DOCKER_TLS_VERIFY=1 ^
  --volume jenkins-data:/var/jenkins_home ^
  --volume jenkins-docker-certs:/certs/client:ro ^
  --publish 8080:8080 --publish 50000:50000 myjenkins-blueocean:2.452.3-1

Access the Docker Container

To access your Jenkins Docker container, use the following command:

docker exec -it jenkins-blueocean bash

Access the Docker Logs

View the Jenkins console log using:

docker logs <my-docker-container>

Replace <my-docker-container> with the name of your Jenkins container, which can be found using docker ps.

Access the Jenkins Home Directory

To access the Jenkins home directory, use:

docker container exec -it <my-docker-container> bash

This allows you to inspect and manage Jenkins data and configurations within the container.

Unlock Jenkins

When accessing a new Jenkins instance for the first time, you need to unlock it using an automatically generated password. Follow these steps to unlock Jenkins:

  1. Access Jenkins: Open your web browser and navigate to http://localhost:8080 (or the port you configured for Jenkins). Wait for the Unlock Jenkins page to appear.
  2. Locate the initial admin password: The initial admin password is stored within the Jenkins home directory. To retrieve it, you can use the following command, which will print the password in the console:
sudo cat /var/jenkins_home/secrets/initialAdminPassword

If you are running Jenkins in a Docker container, use the command:

sudo docker exec <my_container_name_or_id> cat \ 
/var/jenkins_home/secrets/initialAdminPassword
  1. Copy and paste the password: Copy the alphanumeric password displayed in the console.
  2. Enter the password in the web interface: On the Unlock Jenkins page, paste or enter the copied password into the Administrator password field and select Continue.

This password is necessary to complete the initial setup of Jenkins. Once entered, you can proceed with the setup wizard, which includes creating the first admin user and configuring Jenkins according to your requirements.

Best Practices for Running Jenkins on Docker

1. Use a Dedicated Docker Network

It is recommended to set up a dedicated Docker network for Jenkins to isolate it from other containers. This prevents potential conflicts between containers and ensures better network management. By using a custom network, you can control how Jenkins interacts with other services, such as agents or databases, and manage traffic flow more efficiently.

In addition, a dedicated network simplifies the configuration of DNS resolution within Docker, as you can set network aliases for containers. This setup ensures Jenkins can easily communicate with other necessary services, reducing the chances of networking issues during builds and deployments.

2. Secure Your Jenkins Setup

Security is crucial when running Jenkins on Docker, especially in production environments. Use Docker’s built-in security features, such as enabling user namespaces, to map Jenkins processes inside the container to non-root users on the host machine. This limits the potential damage if a container is compromised.

Additionally, ensure that sensitive information such as credentials, passwords, or API keys is managed using Docker secrets. These secrets should be mounted into the container at runtime, rather than hardcoded into Dockerfiles or scripts, to protect sensitive data from exposure in images or logs.

3. Optimize Resource Usage with Docker Limits

To ensure Jenkins performs reliably and doesn’t consume excessive resources, set memory and CPU limits on the Docker container. This helps prevent Jenkins from overwhelming the host machine, especially during high load periods with multiple builds. You can use the --memory and --cpus options when running the Docker container to control how much memory and CPU it can use.

Additionally, consider using Docker’s --restart=on-failure option to automatically restart Jenkins in case of crashes or failures. This reduces downtime and ensures Jenkins remains available, even under unexpected circumstances.

4. Backup Jenkins Data with Persistent Volumes

Using Docker volumes is crucial for persisting Jenkins data, including job configurations, plugins, and build history. By mapping the Jenkins home directory (/var/jenkins_home) to a Docker volume, you can ensure that critical data survives container restarts or migrations. This setup allows you to seamlessly move Jenkins to different servers or restore from backups without losing any configurations or build history.

Regularly backup these volumes and consider storing them in a separate storage location. This practice ensures you can quickly recover Jenkins in case of hardware failure or data corruption.

5. Automate Jenkins Container Updates

To keep Jenkins secure and up to date, automate the process of pulling the latest stable Jenkins Docker image or rebuilding your custom images with the latest security patches. However, be cautious with automatic updates, especially in production environments, as new versions of Jenkins or plugins might introduce breaking changes.

Instead, schedule periodic updates, test them in a staging environment, and implement rolling updates in production. This minimizes downtime and reduces the risk of update-related issues while keeping Jenkins secure and functional.

6. Monitor Jenkins with Docker Logs and Metrics

Effective monitoring is key to maintaining a healthy Jenkins environment. Use Docker’s built-in logging features to capture Jenkins logs for troubleshooting and performance monitoring. Redirect logs to external monitoring solutions like Elasticsearch or Grafana to keep track of Jenkins’ health and to identify issues like slow builds or plugin failures.

Additionally, you can leverage Docker’s metrics API to monitor resource usage, including CPU, memory, and network traffic for Jenkins containers. This enables proactive management, helping you optimize performance and resolve issues before they impact your pipeline.

Related content: Read our guide to Jenkins pipeline

Codefresh: A Modern Alternative to Jenkins Based on Argo CD

You can’t get to continuous delivery or deployment without first solving continuous integration. Codefresh automatically creates a Delivery Pipeline, which is a workflow along with the events that trigger it. We’ve added a pipeline creation wizard that will create all the component configurations so you can spend less time with YAML and more time getting work done. 

At the end of the pipeline creation wizard, Codefresh commits the configuration to git and allows its built-in Argo CD instance to deploy them to Kubernetes.

The Delivery pipeline model also allows the creation of a single reusable pipeline that lets DevOps teams build once and use everywhere. Each step in a workflow operates in its own container and pod. This allows pipelines to take advantage of the distributed architecture of Kubernetes to easily scale both on the number of running workflows and within each workflow itself.

Teams that adopt Codefresh deploy more often, with greater confidence, and are able to resolve issues in production much more quickly. This is because we unlock the full potential of Argo to create a single cohesive software supply chain. For users of traditional CI/CD tooling, the fresh approach to software delivery is dramatically easier to adopt, more scalable, and much easier to manage with the unique hybrid model.

Learn more about Codefresh.

The World’s Most Modern CI/CD Platform

A next generation CI/CD platform designed for cloud-native applications, offering dynamic builds, progressive delivery, and much more.

Check It Out