3 Best Ways to Run Docker in Docker Container

Docker is a popular tool for building, running, and managing containers. But what if you want to run Docker inside a Docker container, for instance, in a CI pipeline? How can you achieve that?

In this article, I will show you three different methods to run Docker in a Docker container and explain the pros and cons of each. I will also share with you some use cases and tips for using Docker in Docker effectively.

Key Takeaways

  • Mounting the host’s Docker socket is simple and does not require any special privileges or configuration, but it gives the container full access to the host’s Docker daemon, which can be a security risk.
  • Using the docker:dind image creates a separate namespace for the inner Docker daemon and its containers, which avoids interference with the host’s daemon or other containers, but it requires privileged mode, which gives the container complete access to the host system.
  • Using Nestybox Sysbox runtime enables containers to act as lightweight VMs that can run system-level software such as Docker without requiring privileged mode or special configuration.

Why Run Docker in Docker?

Below are some of the scenarios where you might want to run Docker inside a Docker container:

  • CI/CD pipelines: If you use a containerized CI/CD system, such as Jenkins, GitLab CI, or GitHub Actions, you might need to build and push Docker images as part of your pipeline stages. Running Docker in Docker allows you to do that without installing Docker on your CI/CD agents or using a separate VM.
  • Sandboxed environments: If you want to experiment with Docker commands or test your Dockerfiles without affecting your host system, you can use a Docker in Docker container as a sandbox. This way, you can isolate your experiments from your production environment and avoid potential conflicts or errors.
  • Portability: A Docker in Docker setup can be easily shared and distributed since it packages up the Docker engine and environment. This makes the Dockerized app portable and self-contained.
  • Learning and teaching: If you are learning or teaching about Docker, you can use a Docker in Docker container as a playground to practice and demonstrate various concepts and features of Docker. You can also use it to run multiple containers on a single machine without consuming too much resources.

Try the Docker Run Lab for free:

Docker Run Lab
Docker Run Lab

Let us now look at the three methods of running Docker inside a Docker container.

1: Mounting the Host’s Docker Socket

This method of running Docker in a Docker container involves mounting the host’s Docker socket (/var/run/docker.sock) into the container. This way, the Docker CLI inside the container can communicate with the host’s Docker daemon and execute commands on it.

To use this method, you need to run a container with the -v /var/run/docker.sock:/var/run/docker.sock option. See the command below:

docker run -v /var/run/docker.sock:/var/run/docker.sock -ti docker:18.06

This command will run a container using the official docker image from Docker Hub, which has the Docker CLI installed. You can also use any other image that has the docker binary or install it yourself. You can now log into the container using this command:

docker exec -it <CONTAINER_ID> /bin/sh

Once inside the container, you can run any docker command. Let’s start an Nginx container using the command below:

docker container run -d --name=sock-nginx nginx

Then run this command to verify the container has been created:

docker ps

Running the command above gives an output similar to this:

Check the version of the docker binary installed in your container:

Docker --version

You should see something like this:

The advantage of this method is that it is simple and does not require any special privileges or configuration. The disadvantage is that it gives the container full access to the host’s Docker daemon, which can be a security risk. Also, any containers created by the inner Docker will reside on the host system alongside the outer container, which can cause confusion or conflicts.

2: Using the docker:dind Image

The second method to run Docker in Docker is to use the docker:dind image, which stands for “Docker in Docker”. This image provides a self-contained Docker daemon installation inside the container. It operates independently of the host’s daemon, so docker ps inside the container will give different results than docker ps on the host.

To use this method, you need to run a container with the --privileged option and some additional flags. For example:

docker run --privileged --name docker -e DOCKER_TLS_CERTDIR=/certs -v docker-certs-ca:/certs/ca -v docker-certs-client:/certs/client docker:dind

This command will run a container using the docker:dind image and set up some environment variables and volumes for TLS authentication. You can also use other options, such as -p to expose ports or -d to run in detached mode.

Log into the container using this command:

docker exec -it docker /bin/sh

Once inside the container, you can run any docker command as usual:

docker container run -d --name=mynginx nginx

Then run this command to verify the container is up and running:

docker ps

You will see something like this:

To check the version of the docker binary that is installed, run the following command in the container:

Docker --version

You will see something like this:

The advantage of this method is that it creates a separate namespace for the inner Docker daemon and its containers, which avoids interference with the host’s daemon or other containers.

However, it requires privileged mode, which gives the container complete access to the host system. This can be an unacceptable security risk in some environments. Also, there are some issues with Linux Security Modules (LSM), such as AppArmor and SELinux, and with storage drivers that can cause problems with this method.

3: Using Nestybox Sysbox Runtime

The third method to run Docker in a Docker container is to use the Nestybox Sysbox runtime, which is a container runtime that enables containers to act as lightweight VMs. This means that containers can run system-level software such as Docker, Kubernetes, systemd, etc., without requiring privileged mode or special configuration.

To use this method, you need to install the Nestybox Sysbox runtime on your host system and then run a container with the --runtime=sysbox-runc option. For example:

docker run --runtime=sysbox-runc --name sysbox-docker -d docker:dind

The command above starts a docker:dind container with a sysbox runtime. After the container is started, log into the container using this command:

docker exec -it sysbox-docker /bin/sh

Once inside the container, you can run Docker commands on its shell. You can test if the container is working as expected by running the following command.

docker container run -d --name=sysbox-nginx nginx

Then run the following command:

docker ps

You should see an output similar to this:

This method provides a secure and robust way to run Docker in Docker without requiring privileged mode or special configuration.

The disadvantage is that it requires installing and configuring a new runtime on your host system.

PRACTICE the concepts discussed here in a real-world live environment for FREE with KodeKloud Engineer. Join thousands of students gaining real, hands-on experience by working on actual project tasks on a live system.

Best Practices for Docker in Docker

Here are some best practices for using Docker in Docker effectively:

  • Choose the right method for your use case. Depending on your needs and priorities, you may prefer mounting the host’s Docker socket, using the docker:dind image, using Nestybox Sysbox runtime, or using Podman. Each method has its own advantages and disadvantages, so weigh them carefully before deciding.
  • Keep your images small and secure. Use multistage builds, minimal base images, trusted sources, and image scanning tools to reduce the size and vulnerability of your images. Avoid using privileged mode or exposing the Docker daemon socket unless absolutely necessary. Use rootless containers or non-root users whenever possible.
  • Tag your images with useful information. Use descriptive and consistent tags for your images that codify version information, intended destination, stability, or other relevant metadata. Do not rely on the automatically-created latest tag, as it may not reflect the actual state of your image. Use semantic versioning or other conventions to manage your image versions.
  • Follow the general guidelines and recommendations for writing Dockerfiles. Use .dockerignore files to exclude unnecessary files from your build context. Use ENV to define environment variables. Use COPY instead of ADD unless you need to extract a tar file or fetch a remote URL. Use WORKDIR instead of RUN cd. Use ENTRYPOINT and CMD to specify what command to run within the container.

To learn Docker concepts, such as networking and container orchestration, with hands-on labs, check out our course on Docker for Absolute Beginners.

Docker Training Course for the Absolute Beginner | KodeKloud
Learn Docker with simple and easy hands-on Labs

Conclusion

In this article, I have shown you three different methods to run Docker in a Docker container and explained the pros and cons of each one. I have also given you some use cases and tips for using Docker in Docker effectively. You should choose the method that suits your needs and security requirements. Whether you mount the host’s Docker socket, use the docker:dind image, or use Nestybox Sysbox runtime, you can enjoy the benefits of Docker in Docker with some caution and creativity.

Looking to start your Kubernetes mastery journey? Check out the following course from KodeKloud: Kubernetes for the Absolute Beginner.

Find all our Docker courses and certification exam preparation courses in our Docker Learning Path.