これは、なにをしたくて書いたもの?
そういえば、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
ドキュメントにも書かれていますが、この環境変数で指定したディレクトリに、コンテナが作成する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