iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🐰

A Rabbit's Guide to DinD and DooD

に公開

dind and dood even a rabbit can understand

1. Introduction

Hello everyone! Today, I will explain dind (docker-in-docker) and dood (docker-outside-of-docker), concepts in the Docker world that can be a bit confusing, in a way that even a rabbit can understand 🐰

Docker has become widely popular as a container technology and is a daily tool for many developers and operators. Because of its convenience, the need to "use Docker from within a Docker container" has increased. For example, when you want to containerize CI/CD pipelines or unify development environments with containers while still performing Docker builds.

However, "using Docker from within a container" sounds simple but is actually a complex challenge. Two widely known approaches to solve this are dind and dood.

In this article, we aim to:

  • Understand the basic concepts of dind and dood
  • Grasp the mechanisms and characteristics of each through diagrams
  • Learn specific implementation methods and use cases
  • Gain criteria for deciding which one to choose in different situations

By reading this article, you'll be able to overcome the seemingly complex challenge of "using Docker from within a container" as lightly as a rabbit hops!

Let's dive into the world of Docker!

2. Basic Concepts of dind and dood

First, let's review the basic structure of Docker to understand the difference between dind and dood.

Basic Structure of Docker

Docker mainly consists of two components:

  1. Docker Daemon (dockerd) - The server-side component that handles creating, running, and managing containers.
  2. Docker CLI - The client-side component where users enter commands to give instructions to the Docker Daemon.

Normally, when we run a docker command in the terminal, the Docker CLI sends a command to the Docker Daemon, and the process is executed. The two communicate through a Socket (most often /var/run/docker.sock).

Now, when the requirement "I want to use Docker from within a container" arises, there are two major approaches depending on how it's implemented: dind and dood.

What is dind (Docker in Docker)?

dind stands for Docker in Docker, and as the name implies, it is a method of "building another Docker environment within a Docker container."

It starts an independent Docker daemon inside the container to build a complete Docker environment self-contained within that container. In other words, imagine creating an independent Docker world completely isolated from the host's Docker environment.

What is dood (Docker outside of Docker)?

dood stands for Docker outside of Docker, and it is a method of "using the host-side Docker daemon from within a container."

Only the Docker CLI is installed inside the container, and by sending commands to the host-side Docker Daemon, it effectively operates the host's Docker environment. In other words, imagine sharing and using the host's Docker environment from within the container.

Basic Differences

The basic difference between dind and dood lies in where the Docker daemon is running.

DinD (Docker in Docker) Conceptual Diagram

DinD Conceptual Diagram

In dind, an independent Docker daemon is started inside the container, running Docker in a completely isolated environment. Images and containers created within the container are not visible from the host side. To implement this method, the container must be run in privileged mode (--privileged).

DooD (Docker outside of Docker) Conceptual Diagram

DooD Conceptual Diagram

In dood, the host-side Docker daemon's socket file (/var/run/docker.sock) is mounted inside the container, allowing the container to operate the host-side Docker environment. Images and containers created from within the container are actually created on the host side and can be seen from the host side.

From here, let's take a closer look at each method.

3. Details of Docker in Docker (DinD)

Mechanism and Structure

DinD is, as its name suggests, an approach to "run Docker inside a Docker container." It involves installing and starting a complete Docker daemon inside the container to build an independent Docker environment.

While standard Docker has restrictions on accessing some host kernel functions from within a container, DinD bypasses these restrictions by using privileged mode, enabling the Docker daemon to start inside the container.

The characteristics of DinD are as follows:

  1. A complete Docker environment is built inside the container.
  2. It is completely isolated from the host's Docker environment.
  3. Images and containers created inside the container exist only within the container.
  4. When the container stops, the images and containers created inside it also disappear.

Implementation Method

Using the Official Docker-in-Docker Image

The easiest way to implement this is to use the docker:dind image officially provided by Docker.

# Start the DinD container
docker run --name dind-container --privileged -d docker:dind

# Enter the container
docker exec -it dind-container sh

# Execute Docker commands inside the container
docker ps
docker images

The important part here is the --privileged flag. By adding this flag, you permit the container to run in privileged mode, allowing it to access host devices directly.

Building DinD with a General Image

If you want to achieve DinD with an image other than docker:dind (e.g., Ubuntu, CentOS, etc.), you need to install Docker inside the container.

# Example: Start a CentOS container in privileged mode
docker run --name centos-dind --privileged -d centos:7

# Enter the container
docker exec -it centos-dind bash

# Add the repository for Docker installation
yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# Install Docker
yum install -y docker-ce docker-ce-cli containerd.io

# Start Docker
systemctl start docker

# Verify Docker operation
docker ps

Pros and Cons

Pros

  1. Complete isolation environment: Since it is completely separated from the host-side Docker environment, there is no need to worry about interference between containers.
  2. Clean environment: It is suitable for testing and experimentation as you can start from a clean state every time.
  3. Independent configuration: Docker daemon settings can be configured independently of the host, making it ideal for test environments requiring specific configurations.
  4. Sandbox environment: It provides an independent Docker environment for each project, preventing influence between different projects.

Cons

  1. Necessity of privileged mode: The required --privileged flag increases security risks.
  2. Resource consumption: Running a Docker daemon inside a container consumes significant resources (memory, CPU).
  3. Double storage usage: Images and containers occupy storage space on both the host and within the container.
  4. Performance: Overhead from nested containerization may lead to decreased performance.
  5. Functional limitations: Some Docker features may not work as expected (e.g., volume mounting).

Actual Use Cases

Scenarios where DinD is particularly useful include:

  1. Running Docker in CI/CD environments: When each job requires an independent Docker environment.
  2. Multi-tenant environments: When providing separate Docker environments for multiple users.
  3. Docker development itself: Developing and testing Docker itself (this was the original purpose of DinD).
  4. Isolated experimental environments: Safely conducting Docker-related experiments.
  5. Educational environments: Platforms that provide independent Docker environments to individual users for learning.

A common example is running a GitLab CI/CD Runner as a Docker container and performing Docker builds within it.

4. Details of Docker outside of Docker (DooD)

Mechanism and Structure

DooD (Docker outside of Docker) is an approach that "uses the host-side Docker daemon from within a container." Only the Docker CLI is installed inside the container, and it operates by sending commands to the host-side Docker Daemon.

Specifically, this is achieved by mounting the socket file (usually /var/run/docker.sock) used for communication with the host-side Docker daemon into the container. As a result, all Docker CLI commands inside the container are forwarded to and executed by the host-side Docker Daemon.

The characteristics of DooD are as follows:

  1. Only the Docker CLI is installed inside the container.
  2. The host-side Docker environment is shared and utilized.
  3. Images and containers created from within the container are created on the host side and are visible from the host.
  4. Even if the container stops, images and containers created through its operations remain on the host side.

Implementation Method

Using a Docker CLI Image

The easiest implementation method is to use an image that includes the Docker CLI and mount the host's Docker socket.

# Start the DooD container (mount docker.sock)
docker run --name dood-container -v /var/run/docker.sock:/var/run/docker.sock -d docker:cli

# Enter the container
docker exec -it dood-container sh

# Execute Docker commands inside the container
# These commands are executed against the host-side Docker environment
docker ps
docker images

The important part here is the -v /var/run/docker.sock:/var/run/docker.sock option. This option mounts the host-side Docker socket inside the container, allowing access to the host-side Docker daemon from within the container.

How to build DooD with a general image

To achieve DooD with an arbitrary base image (e.g., Ubuntu, CentOS, etc.), you install only the Docker CLI and mount the host's Docker socket.

# Example: Start an Ubuntu container and mount docker.sock
docker run --name ubuntu-dood -v /var/run/docker.sock:/var/run/docker.sock -d ubuntu:20.04

# Enter the container
docker exec -it ubuntu-dood bash

# Install necessary packages
apt-get update
apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release

# Add Docker repository
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

# Install only the Docker CLI (no daemon needed)
apt-get update
apt-get install -y docker-ce-cli

# Verify Docker operation (the host-side Docker daemon will be used)
docker ps

Pros and Cons

Pros

  1. Simple implementation: It can be achieved simply by mounting the socket file without needing privileged mode.
  2. Resource efficiency: Since only one Docker Daemon runs on the host side, it consumes fewer resources (memory, CPU).
  3. Storage efficiency: Images are only stored on the host side, so no double usage of storage occurs.
  4. Persistence: Even if you stop or delete the container, any containers or images created remain on the host side.
  5. Full functionality: You can utilize all features of the host-side Docker.

Cons

  1. Security risk: Mounting the Docker socket effectively gives the container high privileges over the host, posing a security risk.
  2. Environment sharing: Since the environment is not isolated, if multiple containers use the same Docker daemon, they may interfere with each other.
  3. Lack of a clean environment: Because it uses the host-side Docker, you cannot start from a clean environment every time.
  4. Impact on the host side: Operations inside the container directly affect the host's Docker environment.
  5. User permission issues: If the user inside the container does not belong to the docker group, permission issues may occur.

Actual Use Cases

Scenarios where DooD is particularly useful include:

  1. Local development environments: When you want to use Docker from containerized development tools on a developer's machine.
  2. CI/CD tools: When running CI/CD tools (Jenkins, GitLab, etc.) in a container while also performing builds on Docker.
  3. Operations automation tools: When executing automation tools like Ansible, Terraform, or Puppet in a container while needing to operate Docker.
  4. Management tools: When running UIs or tools for Docker management in a container.
  5. Monitoring tools: When running tools that monitor Docker containers from within a container.

A representative example is running a CI tool including Jenkins inside a container and using Docker during the build process. It is also commonly used when containerizing a development environment and performing Docker builds from there.

5. Comparison of DinD and DooD

In this section, we will compare DinD and DooD from various perspectives to provide criteria for deciding which one to choose.

Comparison Table of DinD and DooD

Comparison of Functional Aspects

  • Isolation: DinD provides an independent Docker environment for each container, resulting in high isolation. DooD is a shared environment, so isolation is low.
  • Data Persistence: In DinD, all data is lost when the container is deleted, whereas in DooD, it remains on the host side.
  • Volume Mounting: Volume mounting can become complex in DinD. Specifically, mounting host paths may require double mapping. In DooD, volume mounting can be done just like on the host side.
  • Networking: DinD uses nested container networks, which can become complex. DooD allows the host-side network to be used as is.

Comparison of Performance

  • Startup Time: DinD takes longer to start because it requires starting a daemon process. DooD starts quickly.
  • Memory Usage: DinD consumes more memory because it runs a separate Docker daemon. DooD is basically just the CLI, so it is lightweight.
  • Disk Usage: In DinD, disk usage may increase because images can be stored in two places. In DooD, images are stored in only one place on the host side.
  • CPU Utilization: DinD tends to have higher CPU utilization because the daemon process is running. DooD is relatively light as it only handles CLI requests.

Comparison of Security Aspects

Both have security concerns for their respective reasons:

  • DinD: Because the --privileged flag is used, the container can access host resources with high privileges.
  • DooD: By mounting docker.sock, the container gains full control over the host environment. This essentially carries the same risk as privileged mode.

In both cases, it is dangerous to run untrusted code inside these containers. In environments where security is paramount, other methods should be considered.

Selection Criteria by Usage Scenario

It is better to choose DinD in cases such as:

  • When a completely isolated Docker environment is required.
  • When you want to isolate environments for each user in a multi-tenant environment.
  • For test environments where you want to start from a clean state.
  • When performing development or testing of Docker itself.

It is better to choose DooD in cases such as:

  • When resource efficiency is important.
  • When you want to handle the same images and containers as on the host side.
  • When you want a simple implementation.
  • When you want to operate the local machine's Docker from a development environment.

6. Implementation Examples

Implementation Example of DinD in a CI/CD Pipeline

Let's look at an example of using DinD in GitLab CI/CD. The following is an example of .gitlab-ci.yml.

# GitLab CI/CD DinD implementation example
build_image:
  image: docker:dind
  stage: build
  services:
    - docker:dind
  variables:
    DOCKER_HOST: tcp://docker:2376
    DOCKER_TLS_CERTDIR: "/certs"
    DOCKER_TLS_VERIFY: 1
    DOCKER_CERT_PATH: "/certs/client"
  before_script:
    - docker info
  script:
    - docker build -t my-app:$CI_COMMIT_SHORT_SHA .
    - docker push my-app:$CI_COMMIT_SHORT_SHA

In this configuration, the GitLab CI runner starts the DinD service and executes the Docker build within it. By setting the DOCKER_HOST variable, it connects to the DinD service.

Implementation Example of DooD in a CI/CD Pipeline

The following is a Dockerfile and configuration example for using DooD in Jenkins.

# Dockerfile for using DooD in Jenkins
FROM jenkins/jenkins:lts

USER root

# Install Docker CLI
RUN apt-get update && \
    apt-get -y install apt-transport-https ca-certificates curl gnupg2 software-properties-common && \
    curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - && \
    add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" && \
    apt-get update && \
    apt-get -y install docker-ce-cli

USER jenkins

And when starting the Jenkins container using this image, mount docker.sock as follows:

docker run -p 8080:8080 -p 50000:50000 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v jenkins_home:/var/jenkins_home \
  jenkins-with-docker-cli

With this, you can now operate the host-side Docker from within jobs in Jenkins.

Common Troubles and Solutions

Common Problems with DinD

  1. Volume Mounting Issues

    Problem: When trying to mount a host directory from Docker inside the container, the path is not found.

    Solution: To mount a host directory in DinD, you first need to mount the directory from the host to the DinD container, and then mount it from the DinD container to the internal container.

  2. Performance Issues

    Problem: DinD is slow and consumes significant resources.

    Solution: Performance can be improved by using a cache volume to persist the location where image layers are stored.

    docker run --privileged --name dind \
      -v dind-cache:/var/lib/docker \
      -d docker:dind
    

Common Problems with DooD

  1. Permission Issues

    Problem: No permission to access docker.sock.

    Solution: You need to add the user inside the container to the host-side docker group or run the container as root. However, running as root increases security risks.

    FROM ubuntu:20.04
    
    RUN apt-get update && apt-get install -y docker-ce-cli
    
    # Match the container's docker group ID with the host side
    RUN groupadd -g 999 docker && usermod -aG docker myuser
    
    USER myuser
    
  2. Path Resolution Issues

    Problem: Volume mounting does not work as intended because paths differ between the container and the host side.

    Solution: Use relative paths instead of absolute paths, or map paths using environment variables.

7. Application Examples in CI/CD Pipelines

Usage in Jenkins

The scenario of running Jenkins in a container and performing Docker builds from there is very common.

Jenkins Configuration with DinD

version: '3'
services:
  jenkins:
    image: jenkins/jenkins:lts
    ports:
      - "8080:8080"
    volumes:
      - jenkins_home:/var/jenkins_home
  docker:
    image: docker:dind
    privileged: true
    environment:
      - DOCKER_TLS_CERTDIR=/certs
    volumes:
      - jenkins-docker-certs:/certs/client
      - jenkins-docker-data:/var/lib/docker
    expose:
      - "2376"

volumes:
  jenkins_home:
  jenkins-docker-certs:
  jenkins-docker-data:

In jobs within Jenkins, you connect to the DinD service by setting the DOCKER_HOST environment variable.

Jenkins Configuration with DooD

version: '3'
services:
  jenkins:
    image: jenkins-with-docker-cli
    ports:
      - "8080:8080"
    volumes:
      - jenkins_home:/var/jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock

volumes:
  jenkins_home:

Usage in GitHub Actions

You can also use dind and dood in GitHub Actions.

GitHub Actions Configuration with DinD

name: Build with DinD

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
      
      - name: Setup Docker
        uses: docker/setup-buildx-action@v1
        with:
          driver-opts: image=moby/buildkit:master
      
      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          context: .
          push: false
          tags: myapp:latest

GitHub Actions Configuration with DooD

name: Build with DooD

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
      
      - name: Build image
        run: |
          docker build -t myapp:latest .
          docker run --rm myapp:latest

Usage in Other CI/CD Tools

Most major CI/CD tools, such as TravisCI, CircleCI, and GitLab CI/CD, support both dind and dood. The general guidelines for choosing are:

  • If complete isolation is required, choose DinD.
  • If simplicity and performance are important, choose DooD.

would be a good choice.

8. Summary

In this article, we explained two approaches for using Docker from within a container: Docker in Docker (DinD) and Docker outside of Docker (DooD).

Where to use dind and dood

  • DinD is suitable when a completely isolated Docker environment is required. It is especially geared toward multi-tenant environments where multiple users need independent environments or for running tests from a clean state. However, it has drawbacks such as the need for privileged mode and high resource consumption.

  • DooD is suitable when simple implementation and efficient resource utilization are required. It is geared toward local development environments or cases where you want to share host-side Docker resources. However, care must be taken regarding security risks and the impact of sharing the environment.

Finally

Both approaches have their own pros and cons. It is important to choose the method that fits your use case. In environments where security is paramount, both methods must be used with caution.

We hope this article helps you make a choice as light and bouncy as a rabbit when you operate Docker from within a Docker container in the future! 🐰

Reference Resources

Discussion