Millet Porridge

English version of https://corvo.myseu.cn

0%

Docker Series 9: Trick, Using Docker inside a Container

Problem Background

Many people wonder why run Docker inside a container. I think there are mainly the following scenarios that may require running Docker in a container:

  1. Jenkins or other CI tools — these tools may themselves run in Docker containers, but when executing test jobs they still need to start containers. Theoretically speaking, this situation is fairly common.
  2. Some container orchestration tools are themselves Dockerized. For example: you write a software that builds Docker images by manipulating Docker’s API, and you run this software with Docker — at this point, the build operation is definitely triggered by the program inside the container calling the Docker API.

Two Ways to Run

dnd

This is a method of starting another docker process inside a container:

Using Docker-in-Docker for your CI or testing environment? Think twice.

github.com/jpetazzo/dind

The README also explains how it works:

1
2
3
4
5
6
7
8
9
The main trick is to have the --privileged flag. Then, there are a few things to care about:

1. cgroups pseudo-filesystems have to be mounted, and they have to be mounted with the same hierarchies than the parent environment; this is done by a wrapper script, which is setup to run by default;
2. /var/lib/docker cannot be on AUFS, so we make it a volume.

The main trick is --privileged, but there are other things to care about:
1. The cgroups pseudo filesystem must be mounted, and they must be at the same hierarchy as the parent environment (I haven't used cgroups deeply and can't explain further); this is done by the script at initialization.
2. /var/lib/docker cannot run on the AUFS filesystem, so it must be mounted. Docker image building and running both use AUFS (newer environments mostly overlay2). Personal advice: if you must use dnd, don't mount the host's `/var/lib/docker` —
find a separate empty folder to mount as `/var/lib/docker`.

Mounting docker.sock

This is the approach I use at work. The benefit of a unix socket is that as long as you mount it, you can interact with the program.

For example, using it directly on a machine with Docker (find all containers):

1
2
3
4
5
6
7
8
9

~$ docker run -ti -v /var/run/docker.sock:/var/run/docker.sock alpine /bin/sh
> apk add curl

> curl --unix-socket /var/run/docker.sock http:/containers/json

# if that doesn't work, use the statement below

> curl --unix-socket /var/run/docker.sock http:/1.40/containers/json # docker version — just look at the API version

The biggest benefit of this mounting approach is sharing one docker environment; the biggest downside is also sharing one environment. Let me explain why:

  1. Calling the API manipulates the host’s containers — very suitable for Dockerizing certain orchestration tools
  2. The permissions are really too great; with the --privileged parameter in a container, we could even start a container used to shut down the host

Summary

In specific situations we inevitably need to call the Docker API from inside a container to operate. The hope here is to tell everyone there are these two approaches, but concrete usage must be judged together with the usage scenario.