これは、なにをしたくて書いたもの?
そういえば、Docker in Dockerについて自分でちゃんと見たことないなと思いまして。
ちょっと調べておこうかな、と。あと、Docker outside of Dockerも少し扱います。
Docker in Docker(とDocker outside of Docker)
Docker in Dockerについての情報はいろいろありますが、どこを見るのが公式(?)なんでしょうね?
Dockerのドキュメントサイトかなとも思ったのですが
Docker Documentation | Docker Documentation
どうやら、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
ドキュメントにも書かれていますが、この環境変数で指定したディレクトリに、コンテナが作成するSSL/TLS証明書が
格納されます。デフォルト値は/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