š§ Problem Statement
Imagine you're running a Jenkins server inside a Docker container. Everything works fineāuntil your CI pipeline tries to execute docker build or docker push. Suddenly, your workflow fails. But why
š Root Cause
Docker commands like build or push are executed by the Docker daemon (dockerd), which is the core engine of Docker running on the host system. Communication with this daemon happens through a Unix socket called docker.sock.
When a Docker client (like the Jenkins container) sends a command, itās routed via docker.sock to the Docker daemon, which performs the actual operation and returns the result.
Hereās the catch: you cannot run the Docker daemon itself inside a Docker container in the traditional way. Why? Letās break it down.
ā Why Canāt You Run Docker Daemon Inside a Docker Container in Straight Forward approach ?
The Docker daemon needs deep access to the host systemāincluding the kernel and several privileged operations that arenāt typically available inside a container. Since containers are isolated environments sharing the host's kernel, running a full Docker server inside another container breaks this isolation model and leads to permission and capability issues.
In short:
Docker requires host-level access.
Containers are not meant to emulate full virtual machines.
Running dockerd inside a container is not straightforward and can introduce security and stability risks.
ā
Solution
From our earlier discussion, we learned that Docker commands need to be routed through docker.sock, which communicates with the Docker daemon. Since docker.sock is part of the Docker server component running on the host, we must tell our application containerālike Jenkinsāhow to access it.
There are two common approaches to enable Docker commands from inside a container:
š 1. Mounting the Hostās Docker Socket
In this approach, we directly mount the hostās docker.sock into the Jenkins container:
docker run -d \
--name jenkins-docker \
-p 8080:8080 \
-p 50000:50000 \
-v jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
jenkins/jenkins:lts
This allows Jenkins to communicate with the host's Docker daemon just as if it were running natively on the host.
ā
Pros:
ā Cons:
Security risk: You're giving full control of the hostās Docker engine to the container.
If compromised, the Jenkins container can perform any operation on your host, including modifying or deleting containers and images.
š³ 2. Using a Docker-in-Docker (DinD) Container
A more secure and isolated approach is to use a Docker-in-Docker (DinD) container. This is a special Docker image that runs its own Docker daemon inside a container.
Here's how it works:
- You run a DinD container (based on the official
docker:dind image).
docker run -d \
--name dind \
--privileged \
--network jenkins-net \
-e DOCKER_TLS_CERTDIR= "" \
-p 2375:2375 \
docker:dind
You configure your Jenkins container to point to this DinD containerās Docker daemon instead of the host's.
You set the DOCKER_HOST environment variable in your Jenkins container to the DinD containerās Docker socket, e.g.:
docker run -d \
--name jenkins-docker \
--network jenkins-net \
-p 8080:8080 \
-p 50000:50000 \
-v jenkins_home:/var/jenkins_home \
-e DOCKER_HOST=tcp://dind:2375 \
jenkins/jenkins:lts
ā
-e DOCKER_HOST=tcp://dind:2375: Tells Jenkins to send Docker commands to the DinD container (hostname dind on port 2375).
ā
Pros:
Isolates Docker operations from the host.
Limits Docker access to the DinD environment only.
Safer for shared or multi-tenant CI setups.
ā Cons:
Slightly more complex to set up.
Performance overhead compared to using the host daemon.
Security concerns still exist (DinD requires privileged mode), but it's safer than exposing the hostās socket.
This setup disables TLS and runs the DinD container in privileged mode. Thatās fine for testing, learning, or internal CI setups, but not recommended for production.
š Important Note: Make sure both the Jenkins container and the DinD container are running on the same Docker network so they can communicate.