CLOVER🍀

That was when it all began.

Docker in Docker、Docker outside of Docker(ソケットファイルの共有)を試す

これは、なにをしたくて書いたもの?

そういえば、Docker in Dockerについて自分でちゃんと見たことないなと思いまして。

ちょっと調べておこうかな、と。あと、Docker outside of Dockerも少し扱います。

Docker in Docker(とDocker outside of Docker)

Docker in Dockerについての情報はいろいろありますが、どこを見るのが公式(?)なんでしょうね?

Dockerのドキュメントサイトかなとも思ったのですが

Docker Documentation | Docker Documentation

どうやら、Docker Hubを見るのが正解な気がします。

Docker / Docker Hub

この部分ですね。

What is Docker in Docker?

ちなみに、Dockerのドキュメントだと、Rootless modeのところで少し登場します。

Run the Docker daemon as a non-root user (Rootless mode) | Docker Documentation

Docker Hubにも少し書かれていますけどね。

話を戻して、Docker in Dockerとは文字通りDocker内でDockerを動作させることです。その利用自体は推奨されて
いませんが、CIなどで利用されることがあります。

Although running Docker inside Docker is generally not recommended, there are some legitimate use cases, such as development of Docker itself.

ただ、Docker in Dockerにはセキュリティ、ファイルシステム、キャッシュに関する注意事項があります。

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

Dockerのソケットファイルを共有する、Docker outside of Dockerという選択肢を取る方がよいケースもあるでしょう。
※上記ブログ内の「The socket solution」に書かれているものですね

まあ、今回はまずはDocker in Dockerを動かしてみようということで。最後にDocker outside of Dockerも扱います。

環境

今回の環境は、こちらです。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.2 LTS
Release:    20.04
Codename:   focal


$ uname -srvmpio
Linux 5.4.0-80-generic #90-Ubuntu SMP Fri Jul 9 22:49:44 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

ホストにあるDockerのバージョン。

$ docker version
Client: Docker Engine - Community
 Version:           20.10.7
 API version:       1.41
 Go version:        go1.13.15
 Git commit:        f0df350
 Built:             Wed Jun  2 11:56:38 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.7
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       b0f5bc3
  Built:            Wed Jun  2 11:54:50 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.4.8
  GitCommit:        7eba5930496d9bbe375fdf71603e610ad737d2b2
 runc:
  Version:          1.0.0
  GitCommit:        v1.0.0-0-g84113ee
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

Docker in Docker用のイメージを使ってみる

Dockerのイメージのタグから、dindと書かれているものを選び、とりあえず起動してみます。

$ docker container run -it --rm --name dind docker:20.10.7-dind
Generating RSA private key, 4096 bit long modulus (2 primes)
.................................................................................................................................................................................................................................................................................++++
....................................................................................................................................................................................................++++
e is 65537 (0x010001)
Generating RSA private key, 4096 bit long modulus (2 primes)
.................................++++
...........................................................................................................................................................................................................++++
e is 65537 (0x010001)
Signature ok
subject=CN = docker:dind server
Getting CA Private Key
/certs/server/cert.pem: OK
Generating RSA private key, 4096 bit long modulus (2 primes)
......................................++++
.......................................................................++++
e is 65537 (0x010001)
Signature ok
subject=CN = docker:dind client
Getting CA Private Key
/certs/client/cert.pem: OK
mount: permission denied (are you root?)
Could not mount /sys/kernel/security.
AppArmor detection and --privileged mode might break.
mount: permission denied (are you root?)

パーミッションが不足している、--privilegedがないといろいろ言われていますね。/certsディレクトリになにか生成した
みたいです。

--privilegedを付与して起動してみましょう。

$ docker container run -it --rm --name dind --privileged docker:20.10.7-dind

今度は起動しました。

INFO[2021-07-22T10:38:31.911856678Z] Docker daemon                                 commit=b0f5bc3 graphdriver(s)=overlay2 version=20.10.7
INFO[2021-07-22T10:38:31.912922168Z] Daemon has completed initialization          
INFO[2021-07-22T10:38:32.007965645Z] API listen on /var/run/docker.sock           
INFO[2021-07-22T10:38:32.017627627Z] API listen on [::]:2376 

コンテナ内の環境変数を見ると、DOCKER_TLS_CERTDIRというものがあります。

$ docker container exec -it dind env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=a1829346b4d4
TERM=xterm
DOCKER_VERSION=20.10.7
DOCKER_TLS_CERTDIR=/certs
DIND_COMMIT=42b1175eda071c0e9121e1d64345928384a93df1
HOME=/root

ドキュメントにも書かれていますが、この環境変数で指定したディレクトリに、コンテナが作成するSSLTLS証明書が
格納されます。デフォルト値は/certsのようです。

Starting in 18.09+, the dind variants of this image will automatically generate TLS certificates in the directory specified by the DOCKER_TLS_CERTDIR environment variable.

以下の3つのディレクトリを含みます。

  • ca … 認証局
  • server … dockerd用証明書
  • client … docker(クライアント)用証明書

置かれているファイルは、こんな感じですね。

$ docker container exec -it dind find /certs -type f
/certs/client/csr.pem
/certs/client/key.pem
/certs/client/cert.pem
/certs/client/ca.pem
/certs/client/openssl.cnf
/certs/server/csr.pem
/certs/server/key.pem
/certs/server/cert.pem
/certs/server/ca.pem
/certs/server/openssl.cnf
/certs/ca/key.pem
/certs/ca/cert.pem
/certs/ca/cert.srl

他のコンテナからこのDocker自体に接続する場合は、${DOCKER_TLS_CERTDIR}/client内のファイルを共有する必要が
あります。

ちなみに、このコンテナはAlpine Linuxのようです。

$ docker container exec -it dind cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.13.5
PRETTY_NAME="Alpine Linux v3.13"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://bugs.alpinelinux.org/"

Dockerコンテナ内でDockerコンテナを起動する

もう1度、dindなDockerコンテナを起動しておきます。

$ docker container run -it --rm --name dind --privileged docker:20.10.7-dind

コンテナ内に入ります。

$ docker container exec -it dind sh
/ #

この中で、さらにDockerコンテナを起動することができます。

/ # docker container run -it --rm --name nginx nginx:1.21.1

今回はnginxのDockerイメージを使いましたが、これはDockerコンテナ内のDockerで管理されていて、ホスト側にある
Dockerとは別になります。

$ docker container exec -it dind docker image ls
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
nginx        1.21.1    08b152afcfae   37 minutes ago   133MB


$ docker image ls
REPOSITORY   TAG            IMAGE ID       CREATED        SIZE
docker       20.10.7-dind   ca749f2062c4   17 hours ago   263MB

これで、Dockerコンテナ内でDockerコンテナを動かせましたね。

Docker in Dockerなコンテナに、他のコンテナから接続する

今回は、ネットワークを作成してみます。

$ docker network create my-network

ホスト名をdindとして、Docker in Dockerなコンテナを起動。この時、クライアント証明書はホスト側からも
見えるようにしておきます。

$ docker container run -it --rm \
  --name dind \
  --hostname dind \
  --privileged \
  --network my-network \
  -v `pwd`/client:/certs/client \
  docker:20.10.7-dind

Docker in Dockerなコンテナのクライアント証明書をマウントしつつ、別のDockerコンテナを起動します。

$ docker container run -it --rm --name client --network my-network -v `pwd`/client:/certs/client:ro docker:20.10.7
/ # 

正しくDOCKER_HOSTを指定しない場合は、docker infoの実行に失敗しますが

/ # docker info
Client:
 Context:    default
 Debug Mode: false

Server:
ERROR: error during connect: Get https://docker:2376/v1.24/info: dial tcp: lookup docker: Try again
errors pretty printing info

環境変数DOCKER_HOSTに先ほどのDocker in Dockerコンテナを指定してあげると

/ # DOCKER_HOST=tcp://dind:2376

実行できるようになります。

/ # docker info
Client:
 Context:    default
 Debug Mode: false

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 20.10.7
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: d71fcd7d8303cbf684402823e425e9dd2e99285d
 runc version: b9ee9c6314599f1b4a7f497e1f1f856fe433d3b7
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: default
 Kernel Version: 5.4.0-80-generic
 Operating System: Alpine Linux v3.13 (containerized)
 OSType: linux
 Architecture: x86_64
 CPUs: 2
 Total Memory: 1.941GiB
 Name: dind
 ID: ZFVC:3EXN:CQPT:PBZG:6NBO:RB4R:VVPV:HGZD:WU7V:QGMU:QVYI:GSHO
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false
 Product License: Community Engine

WARNING: No swap limit support

これで、このDockerコンテナからDocker in DockerなコンテナをDocker Daemonとして利用できるようになりました。

最初からDOCKER_HOST環境変数を指定してもよいでhそう。

$ docker container run -it --rm --name client --network my-network -e DOCKER_HOST=tcp://dind:2376 -v `pwd`/client:/certs/client:ro docker:20.10.7
/ # 

Docker outside of Dockerを試す

最後に、Docker outside of Dockerを試してみましょう。

これは、ホスト側にあるDocker Daemonのソケットファイルをマウントするものです。

$ docker container run -it --rm --name dood -v /var/run/docker.sock:/var/run/docker.sock docker:20.10.7

使用するDockerイメージは、dindとはなりません。--privilegedオプションも不要です。

これで、コンテナ内からホスト側のDocker Daemonを使用することができます。

/ # docker info
Client:
 Context:    default
 Debug Mode: false

Server:
 Containers: 1
  Running: 1
  Paused: 0
  Stopped: 0
 Images: 3
 Server Version: 20.10.7
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 7eba5930496d9bbe375fdf71603e610ad737d2b2
 runc version: v1.0.0-0-g84113ee
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: default
 Kernel Version: 5.4.0-80-generic
 Operating System: Ubuntu 20.04.2 LTS
 OSType: linux
 Architecture: x86_64
 CPUs: 2
 Total Memory: 1.941GiB
 Name: ubuntu2004.localdomain
 ID: PN53:TNUG:JMTT:67UT:A6FZ:DKSM:BDML:4GY3:JNOB:LZ6D:G4AA:FBQG
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false

WARNING: No swap limit support
/ # docker version
Client:
 Version:           20.10.7
 API version:       1.41
 Go version:        go1.13.15
 Git commit:        f0df350
 Built:             Wed Jun  2 11:51:04 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.7
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       b0f5bc3
  Built:            Wed Jun  2 11:54:50 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.4.8
  GitCommit:        7eba5930496d9bbe375fdf71603e610ad737d2b2
 runc:
  Version:          1.0.0
  GitCommit:        v1.0.0-0-g84113ee
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
/ # docker info
Client:
 Context:    default
 Debug Mode: false

Server:
 Containers: 1
  Running: 1
  Paused: 0
  Stopped: 0
 Images: 3
 Server Version: 20.10.7
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 7eba5930496d9bbe375fdf71603e610ad737d2b2
 runc version: v1.0.0-0-g84113ee
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: default
 Kernel Version: 5.4.0-80-generic
 Operating System: Ubuntu 20.04.2 LTS
 OSType: linux
 Architecture: x86_64
 CPUs: 2
 Total Memory: 1.941GiB
 Name: ubuntu2004.localdomain
 ID: PN53:TNUG:JMTT:67UT:A6FZ:DKSM:BDML:4GY3:JNOB:LZ6D:G4AA:FBQG
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false

WARNING: No swap limit support