いろいろ書いていく

やってみたなど

docker in docker(dind)を使ってみる

お題

Dockerにはdind = docker-in-dockerというものがあって,dockerホストの中にdockerホストを立てることができる.
https://hub.docker.com/_/docker

今回は上記URLのHow to use this imageをベースに,dindを触ってみる.

なぜ

コンテナを用いたサービスを冗長化したい場合,複数のdockerホストを立てクラスタリングするというのが定石らしい.
これを手元でやってみようとなった時,ホストの数だけ仮想マシンを立てる方法もあるが,
そのようなリソースがない場合,dindを使うと仮想マシン1台でもお手軽に体験できる.
(より正直に言うと,swarmやkubernetesなどのツールをお手軽に使ってみたいという願望がある)

注意

上記のDockerHubページに,使う前にここを読んでねと以下のリンクが置いてある.
jpetazzo.github.io

debian系以外ではダメかも・・という話と,内側のdockerを外側のdockerと同じ感覚で使おうとすると色々問題がおきる模様.
便利だけど色々問題もあるから,検証目的や継続利用の場合は慎重に(というか他の方法を考えた方がいいよ)という感じ.
今回はお試しなのでまあOKということで.

環境

Docker (18.09.3) on Ubuntu 18.04 (Oracle VirtualBox VM on macOS)
ubuntuにdockerをインストールする手順はこちら:
koimedenshi.hatenablog.com

手順

DockerHubを参考にする.
https://hub.docker.com/_/docker

ホスト端末のターミナル上で以下のコマンドを実行し,dindコンテナを起動する.

docker run -it --privileged --name some-docker -d docker:stable-dind

--privilegedオプションで特権を与える.これがないと正しく動作しない.ホストマシンの操作権を与えることになるので注意.
少しややこしいが,イメージ名が"docker"でタグが"stable-dind" .

docker execコマンドで,作成したdindコンテナのshellに接続

docker exec -it some-docker sh

OSの情報を確認すると,Alpine Linuxとなっている

/ # cat /etc/*release
3.9.2
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.9.2
PRETTY_NAME="Alpine Linux v3.9"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://bugs.alpinelinux.org/"

docker versionコマンドを実行すると,dind内のdockerホストのバージョン情報が確認できる.

/ # docker version
Client: Docker Engine - Community
 Version:           18.09.3
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        774a1f4
 Built:             Thu Feb 28 06:32:01 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.3
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       774a1f4
  Built:            Thu Feb 28 06:40:51 2019
  OS/Arch:          linux/amd64
  Experimental:     false

この時のstable-dindのバージョンは18.09.3となっており,実際にインストールされているものと一致している.

dindコンテナ内におけるコンテナ起動

dind内でhello-worldコンテナを起動してみる.
docker execコマンドでsome-dockerコンテナのshellに接続:

docker exec -it some-docker sh

dind内でhello-worldコンテナを起動:

/ # docker container run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete 
Digest: sha256:2557e3c07ed1e38f26e389462d03ed943586f744621577a99efb77324b0fe535
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.
 〜省略〜

dind内であっても,通常のdockerホストでの操作と同じ感覚でコンテナイメージを取得して起動できた.
この時イメージはどこから取得しているのかというと,ホストがローカルに保存しているイメージをダウンロードするのではなく,ふつうに外部のdockerレジストリ(https://index.docker.io/v1/)から取得していると思われる.
dind内のdocker設定を見るとレジストリとしてdocker公式レジストリが設定されている.

/# docker info
 〜省略〜
Registry: https://index.docker.io/v1/
 〜省略〜

storage-driverの設定

--storage-driverはvfsを選択するようになっている.「vfsはスペックとしては微妙だが,唯一安定して動作するため,しかたなくこれにしている.
実用的にはホスト端末での--storage-driverと同じ値を設定するのが良い」的なことが書かれている.
ホスト端末での--storage-driverはdocker infoで確認できる.

~ $ docker info
Containers: 11
 Running: 1
 Paused: 0
 Stopped: 10
Images: 21
Server Version: 18.09.3
Storage Driver: overlay2 #ここ
 〜以下略〜

本環境ではoverlay2となっているので,それに合わせたdindコンテナを立てる場合は以下のコマンドとなる.

docker run --privileged --name some-overlay-docker -d docker:stable-dind --storage-driver=overlay2

別コンテナからdindへの接続

dind自体はホスト端末(ここではubuntu)上のdockerから見ればコンテナのひとつなので,ホストのdockerに立てた別のコンテナから--linkオプションで接続できる.
(例)新たにedge-dindコンテナを立て,先ほど立てた"some-docker"コンテナに接続する場合:

docker run --privileged --link some-docker:docker --name some-docker-edge-dind -d docker:edge-dind

データをどこに保存するか

様々な方法があるが,dindコンテナ内にするか,ホストのディレクトリをマウントして保存先とするかが挙げられている.
ホストディレクトリ"/my/own/var-lib-docker"をマウントする場合のコンテナ起動方法は:

docker run --privileged --name some-docker -v /my/own/var-lib-docker:/var/lib/docker -d docker:dind

この辺りも使い方次第でベストプラクティス的なものは変わるかもしれない.

まとめ

dindによって複数のdockerホストを単一の仮想マシン上に構築することができた.
これを使えばswarmによるクラスタ管理などをお手軽に体験できそう.