How to Set Up Jenkins in Docker with Docker-in-Docker (DinD) on Ubuntu ?

Arief ShaikArief Shaik
6 min read

What Is Jenkins with Docker-in-Docker (DinD)?

Jenkins with Docker-in-Docker (DinD) is a setup where:

  • Jenkins itself runs inside a Docker container

  • Inside that Jenkins container, your pipelines can also run Docker commands

  • This is possible thanks to a second container: Docker-in-Docker, or DinD

🔁 Basically:
A Jenkins container talks to a Docker daemon inside another container, so it can build/run Docker images from within a pipeline.


Why Use Docker-in-Docker (DinD) with Jenkins?

Here are the key reasons for using DinD in this setup:

  1. No need to modify the host system
    You don’t have to install Jenkins directly on the host and add the Jenkins user to the docker group on your machine.

  2. Isolated and secure environment
    DinD runs in its own container, providing better isolation and reducing the risk of Jenkins directly accessing the host Docker daemon.

  3. Jenkins can run Docker commands inside the container
    By connecting Jenkins to the DinD container, it can execute docker build, docker run, etc., inside its own CI pipelines.

  4. Reusable and portable setup
    This containerized setup can be replicated on any machine — perfect for testing, learning, or CI/CD automation.

  5. Supports multiple Jenkins agents
    You can scale Jenkins with multiple agents, each connecting to its own DinD container — useful for parallel builds or larger workflows.

  6. Clean environment
    Every time you restart the containers, you start with a fresh and controlled environment — no leftover images or containers from previous builds (unless persisted intentionally).


What Is Docker-in-Docker (DinD)?

Docker-in-Docker (DinD) means running the Docker Engine inside a container. It allows you to run Docker commands like docker build, docker run, or docker push from within another container.

In this Jenkins setup:

  • Jenkins uses Docker CLI to talk to a DinD container

  • The DinD container runs a real Docker daemon, isolated from your host

Why Jenkins inside Docker?

  • Easy to isolate and run Jenkins as a container

  • Quick to deploy, clean to remove

  • No need to install Jenkins directly on your host system.


Prerequisites

Make sure you have:

  • Ubuntu 20.04+ or 24.04 LTS

  • Docker installed (sudo apt install docker.io)

  • A user added to Docker group (sudo usermod -aG docker $USER)

  • Activate the new group membership in your current shell session without logging out and back (newgrp docker )

Step 1 : Create a bridge network in Docker using the following command

docker network create jenkins

Step 2 : Download and run the docker:dind Docker image using the following command

docker run \
  --name jenkins-docker \
  --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

Breakdown:

  • --name jenkins-docker: Names the container jenkins-docker.

  • --detach: Runs the container in the background (detached mode).

  • --privileged: Grants extended privileges (required for Docker-in-Docker).

  • --network jenkins: Connects to the jenkins Docker network.

  • --network-alias docker: Creates a network alias docker (used by Jenkins to access Docker).

  • --env DOCKER_TLS_CERTDIR=/certs: Enables TLS and stores certificates in /certs.

  • --volume jenkins-docker-certs:/certs/client: Mounts volume for TLS client certs.

  • --volume jenkins-data:/var/jenkins_home: Mounts Jenkins home directory to persist data.

  • --publish 2376:2376: Exposes Docker daemon over port 2376 (TLS-secured).

  • docker:dind: Uses the official Docker-in-Docker image.

  • --storage-driver overlay2: Sets the Docker storage driver to overlay2 for better performance and layering.

Step 3 : Create a custom Jenkins Docker Image

create a Dockerfile with the following content:

FROM jenkins/jenkins:2.504.2-jdk21
USER root
RUN apt-get update && apt-get install -y lsb-release ca-certificates curl && \
    install -m 0755 -d /etc/apt/keyrings && \
    curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc && \
    chmod a+r /etc/apt/keyrings/docker.asc && \
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
    https://download.docker.com/linux/debian $(. /etc/os-release && echo \"$VERSION_CODENAME\") stable" \
    | tee /etc/apt/sources.list.d/docker.list > /dev/null && \
    apt-get update && apt-get install -y docker-ce-cli && \
    apt-get clean && rm -rf /var/lib/apt/lists/*
USER jenkins
RUN jenkins-plugin-cli --plugins "blueocean docker-workflow json-path-api"

Step 4 : Build the Image by assigning a custom name

docker build -t myjenkins-blueocean:2.504.2-1 .

Step 5 : Run the Jenkins image as a container

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.504.2-1

Breakdown:

  • --name jenkins-blueocean: Names the container jenkins-blueocean.

  • --restart=on-failure: Automatically restarts the container if it crashes.

  • --detach: Runs the container in the background.

  • --network jenkins: Connects it to the same custom Docker network (jenkins) as the Docker daemon.

  • --env DOCKER_HOST=tcp://docker:2376: Tells Jenkins where to find the Docker daemon (via the alias docker).

  • --env DOCKER_CERT_PATH=/certs/client: Path to TLS client certs (read-only).

  • --env DOCKER_TLS_VERIFY=1: Enables TLS verification.

  • --publish 8080:8080: Exposes Jenkins web UI on port 8080.

  • --publish 50000:50000: Exposes the port for Jenkins agent communication.

  • --volume jenkins-data:/var/jenkins_home: Persists Jenkins configuration and job data.

  • --volume jenkins-docker-certs:/certs/client:ro: Mounts Docker TLS certs in read-only mode.

  • myjenkins-blueocean:2.504.2-1: Uses your custom-built Jenkins Blue Ocean image.

Step 6: Post-installation setup wizard

After downloading, installing and running Jenkins using one of the procedures above (except for installation with Jenkins Operator), the post-installation setup wizard begins.

This setup wizard takes you through a few quick "one-off" steps to unlock Jenkins, customize it with plugins and create the first administrator user through which you can continue accessing Jenkins.

Unlocking Jenkins

When you first access a new Jenkins controller, you are asked to unlock it using an automatically-generated password.

  1. Browse to http://localhost:8080 (or whichever port you configured for Jenkins when installing it) and wait until the Unlock Jenkins page appears.

Step 8 : Accessing the Docker container

Run the following command in bash to access the container

docker exec -it jenkins-blueocean bash

now run the following command to get the initial password

cat /var/jenkins_home/secrets/initialAdminPassword

Step 9: Install Suggested Plugins

This will install common plugins like Git, Pipeline, etc. You can always install more later.

Step 10: Create Admin User

Fill in the form to create your first Jenkins user and complete the setup.

keep the Jenkins URL as it is and click on save and finish.

Jenkins is ready

click on start using Jenkins.

Note

  • The Jenkins container uses persistent storage through Docker volumes. This means your Jenkins data (like jobs, plugins, configurations) will be saved even if the container stops or restarts.

  • If the Jenkins container stops, you can simply restart it using:

      docker start jenkins-blueocean
      docker start jenkins-docker
    

    And it will resume from where it left off — no data lost.

  • The jenkins-blueocean is the jenkins container

  • the jenkins-docker is the Docker-in-Docker (DinD) container.

  • In order for Jenkins to run Docker commands inside jobs, both the Jenkins container and the Docker-in-Docker (DinD) container must be running on the same Docker network.

Conclusion :

In this guide, you learned how to install and configure Jenkins on Ubuntu , giving you a solid foundation to start building CI/CD pipelines. Jenkins is a powerful tool that automates your build, test, and deployment workflows and setting it up properly is your first big step into the world of DevOps.

Whether you're just exploring automation or aiming to master continuous integration, Jenkins will be a core part of your DevOps toolkit.

#jenkins #devops #ubuntu #cicd #linux #docker #jenkins-dockers

0
Subscribe to my newsletter

Read articles from Arief Shaik directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Arief Shaik
Arief Shaik

I’m a passionate DevOps and cloud enthusiast with hands-on experience in building and automating modern infrastructure using tools like Docker, Terraform, Jenkins, and GitHub Actions. My core skill set includes Java, Python, shell scripting, and deploying containerized applications on Azure and AWS. I actively work on real-world projects involving CI/CD, infrastructure as code, cloud deployment, and Linux automation. Driven by curiosity and consistency, I enjoy turning complex problems into simple, automated solutions. I’m always exploring new technologies and looking to contribute to open-source projects and collaborate with the developer community.