Sitemap

The Magic Behind Docker-in-Docker (DinD)

2 min readJul 18, 2025

Docker-in-Docker (DinD) is a popular technique in CI/CD pipelines to enable containerized builds.

Press enter or click to view image in full size
Photo by Debby Hudson on Unsplash

But why is DinD necessary?
Does it actually run a Docker container inside another Docker container?

Let’s say you use Gitlab CI (or Jenkins, Circle CI etc.). In your .gitlab-ci.yml file, you define a task like this:

image: ubuntu:25.10

services:
- docker:dind

variables:
DOCKER_HOST: tcp://docker:2375/
DOCKER_TLS_CERTDIR: ""

stages:
- test123

run-tests123:
stage: test123
before_script:
- apt-get update && apt-get install -y docker.io
script:
- docker pull ailhan/web-debug:latest
- docker run ailhan/web-debug:latest ./runtests.sh

The problem definition

You want to download the ailhan/web-debug image, run it as a container, and perform some tests.

Forget about the above-mentioned example yaml file.

You run CI jobs in a Docker container or a Kubernetes pod.

You want to get the latest container image from artifactory and run some tests.

When your CI job runs inside a container or Kubernetes pod, it cannot directly launch sibling Docker containers because Docker requires access to the host’s Docker daemon, which is not accessible inside the container by default.

There should be a mechanism that allows you to launch another Docker container on the host machine.

The solution

This is where DinD (Docker-in-Docker) comes into play.

It sounds like we will run a Docker container within a Docker container.

Actually, it’s not exactly running a container fully nested inside another container.

We will run the CI job (run-tests123) inside a special container (docker:dind), which allows you to run another Docker container on the host machine.

DinD doesn’t allow you to run a Docker container fully nested inside another container. Instead, it runs a Docker daemon inside a special container (docker:dind) with elevated privileges.

Your CI job connects to the Docker daemon running inside the DinD container, which acts like a Docker host and lets you launch sibling containers.

DinD allows you to create another container (ubuntu:25.10) on the host machine.

We install the Docker CLI inside the Ubuntu container to communicate with the Docker daemon running inside the DinD container.

Thanks to the environment variable DOCKER_HOST, it will connect to the Docker daemon on the host machine.

After that, we will be able to run ailhan/web-debug container and perform the tests.

What’s the magic behind the Docker-in-Docker container?

It’s actually a simple container. It simply installs Docker and runs the container with the --privleged flag. The --privileged flag grants the container extended privileges, allowing it to interact closely with the host system and its resources (for more details, see cgroups).

This allows the CI Job to run another container on the host machine.

Here’s the docker-in-docker’s Dockerfile:
https://github.com/jpetazzo/dind/blob/master/fedora/Dockerfile

In 2013, Docker implemented the --privileged flag that makes DinD possible:

https://github.com/moby/moby/commit/280901e5fbd0c2dabd14d7a9b69a073f6e8f87e4

--

--

No responses yet