docker-containerd、docker-containerd-shim、 docker-containerd-ctr、docker-runc

stack overflowのdockerd vs docker-containerd vs docker-runc vs docker-containerd-ctr vs docker-containerd-shimの補足的な記事です。

各コマンドの説明と、これらを説明する上で必要なcontainerdやCRIの話もちょっと書きます。

一応自分の環境の情報

ubuntu@v-Ubuntu:~$  docker info
Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 6
Server Version: 17.03.2-ce
Storage Driver: overlay2
 Backing Filesystem: extfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins: 
 Volume: local
 Network: bridge host macvlan null overlay
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 4ab9917febca54791c5f071a9d1f404867857fcc
runc version: 54296cf40ad8143b62dbcaa1d90e520a2136ddfe
init version: 949e6fa
Security Options:
 apparmor
 seccomp
  Profile: default
Kernel Version: 4.4.0-130-generic
Operating System: Ubuntu 16.04.2 LTS
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 23.54 GiB
Name: v-Ubuntu
ID: QWK4:E7QH:2SSD:QIOB:PQ2V:D4GL:M43V:5WVY:GQBT:XJCG:OSHA:5WBT
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Experimental: false
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false

WARNING: No swap limit support

事前知識1: Dockerとcontainerd

f:id:etogen:20180730010524j:plain

https://hackernoon.com/docker-containerd-standalone-runtimes-heres-what-you-should-know-b834ef155426

Docker 1.1からDocker Engineにcontainerdが統合されました。containerdはコンテナランタイムの一種でコンテナの管理やコンテナイメージの管理を行ってくれます。

docker runなどでコンテナを作成する時はcontainerdの方に命令が渡されるんですが、そこからさらにruncに命令が行きます。runcは実際にコンテナを実行・作成するコンテナランタイムで、こちらはコンテナイメージの管理などは行いません。

両方ともコンテナランタイムでちょっと紛らわしい。どこで聞いたかは覚えてないんですが、containerdはHigh Level Container Runtime、runcはLow Level Container Runtimeって呼ばれているのを耳にしたことがあります。

詳しくはここがすごいわかりやすいのでを読んでくださいね(投げやり)

事前知識2: CRI

CRI(Container Runtime Interface)は簡単に言うと「kubeletとお話するために、これこれこういうserviceを実装してくださいね」というgRPCの仕様です。その仕様はapi.protoを見ればわかると思います。

containerdはCRIに対応していて、実際Kubernetesのコンテナランタイムとして動かすことができます。

CRIにはバージョンが複数存在するので注意してください。containerd/criのリポジトリのREADMEKubernetesとCRIのバージョンの対応表は見ておくと良いでしょう。

また、containerdはバージョンによってはkubeletとの通信でcri-contianerdを仲介させなければならない場合があります。Kubernetes対応コンテナランタイム「containerd 1.1」正式リリース。CRIにネイティブ対応し、Dockerより軽量で高速な動作を実現Containerd Brings More Container Runtime Options for Kubernetesをご参考に。

各コマンドの説明

docker-containerd

Dockerに統合されているcontainerdちゃんです。こいつはdockerdを起動すると、子プロセスとして一緒に起動されます。

dockerdを実行した後にpsコマンドを実行するとこいつが動いているのが確認できます。

ubuntu@v-Ubuntu:~$ sudo systemctl start docker
ubuntu@v-Ubuntu:~$ ps -alfx | grep docker
0  1001 14525 11858  20   0  13956   988 pipe_w S+   pts/0      0:00  |           \_ grep --color=auto docker
4     0 14327     1  20   0 637884 38944 -      Ssl  ?          0:00 /usr/bin/dockerd -H fd:// -s overlay2 -H tcp://127.0.0.1:2375
4     0 14334 14327  20   0 349300  9832 -      Ssl  ?          0:00  \_ docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --shim docker-containerd-shim --runtime docker-runc
ubuntu@v-Ubuntu:~$ 

コマンドのオプションを見ればわかると思うんですが、unixドメインソケットをエンドポイントとしていてここを叩くと色々操作ができるようになっています。ちなみにこのソケットではgRPCの通信が行われるのでcurlAPIを叩くことはできません。docker-containerd-ctrを使えばこのAPIを叩くことができます。

docker-containerd-ctr

上でも書きましたがcontainerdを操作するCLIツールです。実際に使ってみましょう。

ubuntu@v-Ubuntu:~$ sudo docker-containerd-ctr
NAME:
   ctr - High performance container daemon cli

USAGE:
   docker-containerd-ctr [global options] command [command options] [arguments...]
   
VERSION:
   0.2.3 commit: 4ab9917febca54791c5f071a9d1f404867857fcc
   
COMMANDS:
   checkpoints  list all checkpoints
   containers   interact with running containers
   events   receive events from the containerd daemon
   state    get a raw dump of the containerd state
   version  return the daemon version
   help, h  Shows a list of commands or help for one command
   
GLOBAL OPTIONS:
   --debug                      enable debug output in the logs
   --address "unix:///run/containerd/containerd.sock"   proto://address of GRPC API
   --conn-timeout "1s"                  GRPC connection timeout
   --help, -h                       show help
   --version, -v                    print the version
   
ubuntu@v-Ubuntu:~$ sudo docker-containerd-ctr version
[ctr] rpc error: code = 14 desc = grpc: the connection is unavailable
ubuntu@v-Ubuntu:~$ 

containerdのunixドメインソケットのパスをオプションで渡してやる必要があるようですね。

ubuntu@v-Ubuntu:~$ sudo docker-containerd-ctr version
[ctr] rpc error: code = 14 desc = grpc: the connection is unavailable
ubuntu@v-Ubuntu:~$ sudo docker-containerd-ctr --address "unix:///var/run/docker/libcontainerd/docker-containerd.sock" version
daemon version 0.2.3 commit: 4ab9917febca54791c5f071a9d1f404867857fcc
ubuntu@v-Ubuntu:~$ sudo docker-containerd-ctr --address "unix:///var/run/docker/libcontainerd/docker-containerd.sock" state
{"machine":{"cpus":4,"memory":24102}}ubuntu@v-Ubuntu:~$ 

OK〜!ちなみにここのgRPCの通信はCRIではなくcontainerd独自のgRPCのインタフェースに乗っ取った通信なので注意してください。crictl(CRIを叩くことができるCLIツール)でこのAPIを叩くなんてことは当前できません。

docker-containerd-shim

コンテナを作成する際はruncを実行するんですけど、これを使うことでruncを終了させてコンテナをデーモンレスで実行させることができます。このコマンド、実はdocker runでコンテナを作成するたびに裏で実行しています。実際に確認してみましょう。

現在dockerddocker-containerdのプロセスが存在します。

ubuntu@v-Ubuntu:~$ ps aux | grep docker
root     13339  0.0  0.1 643428 42508 ?        Ssl  02:01   0:02 /usr/bin/dockerd -H fd:// -s overlay2 -H tcp://127.0.0.1:2375
root     13347  0.0  0.0 226552 11248 ?        Ssl  02:01   0:01 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --shim docker-containerd-shim --runtime docker-runc
ubuntu   13934  0.0  0.0  13956   932 pts/0    S+   02:41   0:00 grep --color=auto docker
ubuntu@v-Ubuntu:~$ 

ここでnginxのコンテナを作成するとdocker-containerd-shimのプロセスが開始されます。

ubuntu@v-Ubuntu:~$ docker run -d  nginx
94d5e8ba1dc72f68ae4c0d636e841701f8f1c812da240e562b4e47d9978c1b3f
ubuntu@v-Ubuntu:~$ ps aux | grep docker
root     13339  0.0  0.1 643428 42700 ?        Ssl  02:01   0:02 /usr/bin/dockerd -H fd:// -s overlay2 -H tcp://127.0.0.1:2375
root     13347  0.0  0.0 226552 11268 ?        Ssl  02:01   0:01 docker-containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --shim docker-containerd-shim --runtime docker-runc
root     13999  0.0  0.0 413060  3224 ?        Sl   02:42   0:00 docker-containerd-shim 94d5e8ba1dc72f68ae4c0d636e841701f8f1c812da240e562b4e47d9978c1b3f /var/rundocker/libcontainerd/94d5e8ba1dc72f68ae4c0d636e841701f8f1c812da240e562b4e47d9978c1b3f docker-runc
ubuntu@v-Ubuntu:~$ 

このプロセスは1コンテナにつき1つ実行されます。

docker-runc

OCI準拠の設定を読み込んでコンテナを作成するruncちゃんです。Linuxのcgroupsとかnamespacesとかを使って本当に低いレイヤの処理を行ってくれてるようです(ここら辺ちゃんと勉強してないのであんまりよくわかってない)