motivation
近頃はほとんどのプロジェクトでDockerないしKubernetesといったコンテナで開発します
特にフリーランスだと複数の仕事が同じDockerホスト上のコンテナとしてぶら下がります
あまり大きな問題が出たことはありませんが
- プロジェクト終了時に全てのコンテナを削除したい
- コンテナ、イメージ名がかぶる可能性
- 他のプロジェクトのイメージが
- お客さんの前あるいは配信時に、他の案件のコンテナリストが表示される
等の問題が生じる可能性があります
まず、シェルなどをまとめたものを下記においておきます
https://github.com/YukiMiyatake/util/tree/master/environment/docker_sandbox
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker dind 3c34f16aeaa0 19 hours ago 505MB
<none> <none> 31f248f7f9b6 19 hours ago 658MB
kgb_secret_project latest bc7c96ecde80 3 days ago 814MB
cia_secret_project latest 4b7b8690eb05 6 days ago 2.89GB
docker dind-alpine a4b37e66ffc7 7 days ago 230MB
rothschild_report latest 10 days ago 3.09GB
golang latest 54e71dcafb7c 2 weeks ago 803MB
ubuntu 16.04 5f2bf26e3524 3 weeks ago 123MB
ubuntu 18.04 775349758637 3 weeks ago 64.2MB
buildpack-deps stretch 81af74c34933 5 weeks ago 835MB
golang 1.12.7 be63d15101cb 4 months ago 814MB
docker 1.13.0-dind 7d6978320b24 2 years ago 99MB
こんな情報がバレてしまうと、命が危険だ!!
もちろん、案件ごとにPCを換える、マルチブートにする、ユーザーを切り替える、案件ごとにVMを作りそこでDockerする
等の方法で、回避は可能だが
例えばWindowsでHyper-Vを有効にしている場合にはVMを作れない
そのため、現実的な回避手段として
dindを思いついた
dindとは
DockerはOSの殆どの操作はできますが、一部の操作は出来なくなっています
通常Dockerコンテナ内からDockerを起動できないようになっています
$ docker run -it ubuntu:18.04 bash
root@d3da654e2a5f:/# docker
bash: docker: command not found
コンテナ内からDockerを使う方法は、dindとdoodの2種類の方法があります
通常のDocker
ホストPCのDocker上で全てのイメージを起動します
全てのプロジェクトのコンテナは同じDocker上に存在します(皆兄弟)
不便ですよね?
dind
プロジェクト毎に dind Dockerを立ち上げます( privileged フラグが必須!! )
プロジェクト毎のDockerにログインし、そこで Dockerイメージを作成します
Dockerイメージは親子関係で作成されます
$ docker run -it --privileged -v $('pwd'):/volume -w /volume -d docker:dind
root@e394f7876063:/volume# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@e394f7876063:/volume# docker run -it busybox
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
0f8c40e1270f: Pull complete
Digest: sha256:1303dbf110c57f3edf68d9f5a16c082ec06c4cf7604831669faf2c712260b5a0
Status: Downloaded newer image for busybox:latest
/ # exit
root@e394f7876063:/volume# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@e394f7876063:/volume# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest 020584afccce 3 weeks ago 1.22MB
別プロジェクトのコンテナは見えないし影響を与えない
完全にプロジェクト毎のSandbox環境に成功しました!
dood
dindに近い考え方として Docker Out of Dockerがあります
dindなDockerを立ち上げます。
このとき privilegidフラグはたてず、docker.socファイルを Volumeでマウントします
プロジェクトのDockerコンテナにログインし、dockerコマンドを使うと ホスト上のdockerホストに繋がります
ここで作ったコンテナはホスト上に作成されます=兄弟関係
$ docker run -it -v /var/run/docker.sock:/var/run/docker.sock docker:dind bash
root@b49f798ae8ca:/# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b49f798ae8ca docker:dind "bash" 6 seconds ago Up 5 seconds crazy_goodall
root@b49f798ae8ca:/# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker dind 3c34f16aeaa0 24 hours ago 505MB
<none> <none> 31f248f7f9b6 24 hours ago 658MB
ubuntu 16.04 5f2bf26e3524 3 weeks ago 123MB
ubuntu 18.04 775349758637 3 weeks ago 64.2MB
buildpack-deps stretch 81af74c34933 5 weeks ago 835MB
golang 1.12.7 be63d15101cb 4 months ago 814MB
docker 1.13.0-dind 7d6978320b24 2 years ago 99MB
(ホストのDockerイメージが見えている)
root@b49f798ae8ca:/# docker pull busybox
Using default tag: latest
latest: Pulling from library/busybox
0f8c40e1270f: Pull complete
Digest: sha256:1303dbf110c57f3edf68d9f5a16c082ec06c4cf7604831669faf2c712260b5a0
Status: Downloaded newer image for busybox:latest
docker.io/library/busybox:latest
root@b49f798ae8ca:/# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker dind 3c34f16aeaa0 24 hours ago 505MB
<none> <none> 31f248f7f9b6 24 hours ago 658MB
ubuntu 16.04 5f2bf26e3524 3 weeks ago 123MB
ubuntu 18.04 775349758637 3 weeks ago 64.2MB
busybox latest 020584afccce 3 weeks ago 1.22MB
buildpack-deps stretch 81af74c34933 5 weeks ago 835MB
golang 1.12.7 be63d15101cb 4 months ago 814MB
docker 1.13.0-dind 7d6978320b24 2 years ago 99MB
(ホストのDockerイメージに追加された)
通常のDocker起動と違うのは、Dockerコンテナから兄弟関係のコンテナを作成&利用出来ることです
プロジェクトごとにDockerイメージは別れないので今回の目的には合致しません
CIや、状況に応じてコンテナを生成破壊をするサービスには DooDが向いています(たいていは DinD使わなくてもよい)
dindを使いこなす
まず、Docker in Doockerの開発者によると
dindを使うときは本当にdindが必要なのか再度考えてみろ
大抵のことはdoodでできる
dindはDockerの開発用途だ
ということで、おそらく私の使ってるdindも、開発者いわく、使うなと言うことだろうけど
面白いんで使ってみます
実際の使い方を
上記にスクリプトなどを追加して、より良い環境を構築中です
dindイメージの作成
プロジェクト毎に、dindのDockerイメージを作成します
dindの公式イメージはalpineですが、開発用のホストとして使うのは辛いので
ubuntuなりarchなり好きなイメージを作りましょう
上記の Dockerfileとwrapdockerで、好きなOSのイメージを作れるようにしています
コンテナの作成
コンテナ名を環境変数で指定するために direnvを使ってます
docker run -it --privileged --name $PROJECT_GROUP -v $('pwd'):/volume -w /volume -d docker:dind
docer_run.shに、コンテナの作成例をかいています
ディレクトリをマウントすると大抵の場合便利です
スクリプトでは dindイメージをそのまま使っていますが、プロジェクトで使うツールや言語などをDokerfileで書いておくと便利です
コンテナの実行
docker start $PROJECT_GROUP
docker exec -it $PROJECT_GROUP bash
コンテナの中に入ります
普段どおりにコンテナを作って開発を行います
その他
プロジェクトが終了した際などは、親のコンテナを削除すれば全部キレイになくなります!
ただし dindはvolumeを自動でつくるため、volumeも削除しましょう(volumuとコンテナを全部Cleanにするスクリプト作りたい)
あと、時々 commitしてコンテナをイメージに焼いて置くと安心
###メリット
プロジェクトごとにディレクトリもコンテナも分かれるので、もしもの時の心配がない
他のプロジェクトの修正の影響を万が一にもうけない
フォルダもプロジェクトごとにSandbox化できるので、変なことが起きにくい
スクリーンショット見せたときに、他のサービスのコンテナリストが出ない
マイクロサービス等のコンテナが複数あるサービスで、全てのコンテナを消すのが簡単
###デメリット
Sandbox毎にOSやDBのイメージがPullされるのでストレージ容量を使う
Privilegeフラグが必要