Jenkins in Docker: run Docker inside a Jenkins container
Set up Jenkins in Docker and enable the Jenkins container to build, run, and push Docker images by bind-mounting the host Docker socket. Step-by-step guide.
Jenkins is an open-source CI/CD tool with a large plugin ecosystem for automating builds, tests, and deployments. Running Jenkins inside a Docker container solves configuration file conflicts that occur when multiple projects share a Jenkins installation on the same host.
The new challenge that creates: if you want to build and push Docker images from within Jenkins, the Jenkins container needs access to Docker. This article covers how to set that up using a custom Jenkins image that bind-mounts the host's Docker socket into the container.
The source code and Dockerfile for the NodeJS application used in this tutorial are on GitHub.
Prerequisites
- Working knowledge of Docker and the terminal
- A Docker Hub account
Why not Docker-in-Docker?
The most common suggestion for running Docker inside a container is Docker-in-Docker (DinD) — running a Docker daemon inside the Jenkins container itself. The original DinD approach required the -privileged flag, which gives the container full access to the host kernel and introduces security risks including data corruption when multiple containers share /var/lib/docker.
Modern alternatives like rootless containers and tools such as sysbox address some of these issues, but for a straightforward CI use case, bind-mounting the host Docker socket is simpler, more stable, and does not require elevated privileges.
Create a custom Jenkins image
Create a Dockerfile with the following content:
FROM jenkins/jenkins:lts
USER root
RUN apt-get update -qq && \
apt-get install -y 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" \
> /etc/apt/sources.list.d/docker.list && \
apt-get update -qq && \
apt-get install -y docker-ce docker-ce-cli containerd.io
RUN usermod -aG docker jenkins
What each section does:
FROM jenkins/jenkins:ltsuses the official long-term support Jenkins image as the base- The
RUNblock installs Docker using the current recommended method from Docker's official documentation — downloading the GPG key into/etc/apt/keyringsand adding the Docker apt repository usermod -aG docker jenkinsadds the Jenkins user to thedockergroup so it can run Docker commands withoutsudo
Build the image:
docker image build -t custom-jenkins-docker .
Run the Jenkins container
Run the custom image with two volume mounts:
/var/run/docker.sock:/var/run/docker.sock— binds the host Docker daemon socket into the container, giving the Jenkins Docker CLI a daemon to talk tojenkins_home:/var/jenkins_home— persists Jenkins configuration and job data across container restarts
docker run -it -p 8080:8080 -p 50000:50000 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v jenkins_home:/var/jenkins_home \
custom-jenkins-docker
Visit http://localhost:8080 to complete the Jenkins setup.
Configure Jenkins
The setup wizard asks for an initial admin password. Retrieve it from the container logs printed after the docker run command.


Select Install suggested plugins when prompted.

Create your admin user and finish the setup wizard.

Dockerize a Node.js app with Jenkins
Install required plugins
Go to Manage Jenkins → Manage Plugins → Available and install:
- NodeJS Plugin — enables Node.js build steps
- CloudBees Docker Build and Publish plugin — builds Dockerfiles and pushes images to Docker Hub

Configure the NodeJS plugin
Go to Manage Jenkins → Global Tool Configuration and add a NodeJS installation.

Create a build job
On the Jenkins dashboard, click New Item, select Freestyle project, give it a name, and click OK.

Under Source Code Management, select Git and enter the repository URL:
https://github.com/Kikiodazie/Backend-RESTful-API.git
Leave Credentials blank — the repository is public.

Under Build, add a Docker Build and Publish build step.

Set the Repository Name to your_dockerhub_username/your_repo_name, for example kikiodazie/node-docker.
Leave Registry credentials blank for now — authentication is handled in the next step.

Authenticate with Docker Hub inside the container
The Jenkins container needs to be logged into Docker Hub to push images. Get a shell inside the running container:
docker exec -it <container_name_or_id> /bin/bash
Inside the container, log in to Docker Hub:
docker login
Enter your Docker Hub credentials when prompted.

Run the build
Back in Jenkins, click Build Now. Jenkins will clone the repository, build the Docker image from its Dockerfile, and push it to your Docker Hub account.
View the output in Build History → Console Output.


The image is now built and published to Docker Hub from inside the Jenkins container.
Where to go next
From here you can add build triggers on GitHub push events using a webhook, parameterize the repository name and Docker Hub credentials as Jenkins environment variables, or extend the pipeline to run tests before the Docker build step. The Jenkins Docker installation documentation covers additional configuration options including HTTPS and agent setup.
FAQs
1, What is the difference between Docker-in-Docker and bind-mounting the Docker socket?
Docker-in-Docker runs a full Docker daemon inside the container, which historically required the -privileged flag and introduced security and data corruption risks. Bind-mounting the host socket (/var/run/docker.sock) gives the container's Docker CLI access to the host daemon directly — no privileged mode required, no separate daemon to manage.
2, Why do I need a custom Jenkins image instead of the official one?
The official jenkins/jenkins:lts image does not include Docker. The custom image adds Docker CE to the Jenkins base image and adds the Jenkins user to the Docker group, which is what enables Jenkins to run Docker commands as part of a build job.
3, What does usermod -aG docker jenkins do?
It adds the jenkins user to the docker group. On Linux, the Docker daemon socket is owned by the docker group. Without this, the Jenkins user cannot communicate with the socket and all Docker commands in build jobs will fail with a permissions error.
4, Is bind-mounting the Docker socket secure?
It gives any process inside the container the same access to the Docker daemon as the host user running the container, which means a compromised build job could affect other containers or the host. For production CI environments, use dedicated Docker-in-Docker solutions with appropriate isolation, or a remote Docker daemon with TLS authentication.
5, Can I use this setup with a Jenkins pipeline instead of a freestyle project?
Yes. Once the custom image is running with the socket bind-mount, you can use Docker commands in both freestyle build steps and declarative or scripted Jenkinsfile pipelines. The docker CLI is available in the container regardless of how Jenkins invokes it.