Docker inside Docker container

Docker inside Docker container

Introduction

Hello everyone! I am an Outreachy Intern working on "Rewriting breeze from bash to python" project. Working on this project gives me opportunity to tinker with bash shell scripting, Python and Docker. I had an interesting case in my current work in Apache Airflow. I thought I could share about it here so that it will be useful for others.

My Use Case

I had to check the version of the Docker client using python code. For this, I used subprocess which runs the docker command as a separate process in python. In Apache Airflow development environment, when executing the code to find the docker version, first I have to check whether the current user have permission to run the docker( in other words, I have to check if the user is added in docker to execute it). So I tried writing the following snippet of code :

def check_docker_permission() -> bool:
    permission_denied = False
    # This command displays information regarding Docker installation
    docker_permission_command = ["docker", "info"]
    try:
        # This subprocess modules helps to run the commands via Python instead of command line
        _ = subprocess.run(
            docker_permission_command,
            check=True,
            capture_output=True,
            text=True,
        )
    except subprocess.CalledProcessError as ex:
        permission_denied = True
        # If the current user doesn't have permission to run command, this would in error response from the command
        if ex.stdout and 'Got permission denied while trying to connect' in ex.stdout:
            console.print('ERROR: You have `permission denied` error when trying to communicate with docker.')
            console.print(
                'Most likely you need to add your user to `docker` group: \
                https://docs.docker.com/ engine/install/linux-postinstall/ .'
            )
    return permission_denied

To test the above code, I want to execute the code as a user with and without permission to verify the working of the code. I was working on my personal laptop with a single user and I haven't created a new user yet. At first, I tried to create a new user to verify the above code snippet involved. But that felt like going overboard due to the number of steps involved to create a user. Check this to see about creating a new user. After testing I have to bring back the machine to its original state. So this will involve more steps to do. I thought I could try running docker inside the docker(Linux) container and I could create new users in Linux and test this part of the code. I just did a random google search to see if we could run docker on docker and it listed a few possibilities.

Docker on Docker

So I started exploring the option to run the linux image and tried installing the Docker. I followed this StackOverflow response afterwards to run the Docker inside ubuntu container.

  1. Create a dockerfile with docker CLI installed. I am using the official compose image, so you also have docker-compose
FROM docker/compose:1.25.5
WORKDIR /app
ENTRYPOINT ["/bin/sh"]
  1. When running it, mount the docker sock
$ docker build -t dind .
$ docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock dind

So I got intrigued by mounting the docker socket as volume and explored why I have to mount to run docker on docker.

Docker sock is a Unix socket that docker Daemon listens to. It's an entry point for Docker API from client to daemon. When you mount the docker socket as volume, under the hood, both the host and the docker ubuntu container are pointing to the same docker daemon. When you run docker inside docker, it's just docker client that runs in the container and it accesses the daemon running in the host machine. While this is suitable for testing cases like this during the development process, it's not advisable to run this in a production environment. You could actually access all the docker API running on your host machine and it is a security threat and doesn't create a sandboxed environment.

With this I got the docker command working inside my docker container(Alpine Linux). I just tried the docker ps command and it executes all the containers running on the host machine. Then I created a new user by using adduser command and ran the above code snippet to test the code with different user permission. Viola :) I could test the code without making any modifications to my host machine.

Final thoughts

I hope you found this information useful. Meanwhile, I stumbled upon Portainer, a web UI for docker where they list all information about docker and lets you manage your docker environment. Here in this installation guide, you can see the mounting of docker sock as volume. They use this to gather all the docker information in the underlying host machine via API.

Share your views and feedback about this post :)

Cover photo credits: Photo by Ian Taylor on Unsplash