Dockerコンテナ内からDockerを使うことについて

Dockerコンテナ内からDockerを使うことについて

April 30, 2019
Docker
docker

Docker内からDockerを使う目的

CI用途で使う人が多いのではないでしょうか? CIでビルドなりテストなりやるとき、毎回同じ環境で実行したいと思う サーバ上で直接ジョブ動かしちゃうと、ゴミが残る可能性があったり サーバに直接ジョブ実行に必要なjavaなりrubyなりを突っ込む必要が出てくるので、どんどん汚れていく

Dockerでビルドやテストを実行すれば毎回終わったら消せばいいので、クリーンにできるよねーって話 CIサーバを直接yumなりでインストールして、そこからDocker使うのであれば特に問題ないけど 最近はCIサーバ自体をDockerコンテナで立ち上げて、さらに中でDockerを呼ぶというのがよく使われている気がする その時のやり方の話です。

なぜDockerコンテナ内からDocker使えないか

前提としてDockerの仮想化の仕組みは今までのHypervisorとかと少し違って ベースとなるイメージや、ホストのカーネルなど多くの部分を共有して、コンテナごとに少ない書き込み領域を用意することで、高速起動, 軽量などを実現しています. dockerイメージ-1

そしてセキュリティのため、コンテナ内からいくつかの操作は制限されます Dockerの操作は、Dockerデーモンに対して、クライアントを利用して接続しています. Dockerデーモンはホストに対して下の制約に引っかかることをやっているので、コンテナ内からは起動できないです

DinD-1 DinD-2

上記スライドの引用元

DockerコンテナからDockerを使うには?

2種類の方法があります

  • 権限を付与して、コンテナ内からホストのリソースを自由に扱える権利を持たせる(–privilegedオプションをつける) – Docker in Docker(DinD)
  • ホストのDockerデーモンのソケットファイルをvolume接続(マウント)して、そことやりとりするようにする – Docker outside of Docker (DooD)

イメージとしては下のような感じ

DinD 002

参考元


簡単な違い

参考1

わかりやすい違いとしては、DinDではホストと、コンテナで完全にデーモンが分かれるので イメージ・コンテナ管理なども別々になります, これは管理しやすいという利点でもありますが、 ディスク容量を大量に消費する要因にもなります

DooDではデーモンを共有するため、ホストとコンテナ内で共通のイメージ・コンテナ管理を行います。 利点は↑と逆ですね

シェルで確認してみましょう

DinD

$ sudo docker run --privileged --name dind -d docker:dind
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
cba616b2250c        docker:dind         "dockerd-entrypoint.…"   8 seconds ago       Up 7 seconds        2375/tcp            dind
// dockerコンテナに入ってみる
$ docker exec -it dind sh
// dockerコンテナ内でイメージ起動
/ # docker run -d -p 80:80 --name webserver nginx

// nginxのコンテナしか見えない
/ # docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
99e66f209820        nginx               "nginx -g 'daemon of…"   3 seconds ago       Up 2 seconds        0.0.0.0:80->80/tcp   webserver

// ホストに戻って確認
/ # exit

// dindコンテナしか見れない
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
cba616b2250c        docker:dind         "dockerd-entrypoint.…"   4 minutes ago       Up 4 minutes        2375/tcp            dind

// 消しておく
$ docker stop cba616b2250c && docker rm cba616b2250c

DooD

// doodコンテナ起動
$ sudo docker run -v /var/run/docker.sock:/var/run/docker.sock -it --name dood -d docker
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
4cfa187ac191        docker              "docker-entrypoint.s…"   3 seconds ago       Up 1 second                             dood

// コンテナに入る
akasetnoMacBook-puro% docker exec -it dood sh

// コンテナ内からホストで動いているコンテナ観れる
/ # docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
4cfa187ac191        docker              "docker-entrypoint.s…"   18 seconds ago      Up 16 seconds                           dood

// コンテナ起動
/ # docker run -d -p 80:80 --name webserver nginx
/ # docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
be56745b1af4        nginx               "nginx -g 'daemon of…"   7 seconds ago       Up 6 seconds        0.0.0.0:80->80/tcp   webserver
4cfa187ac191        docker              "docker-entrypoint.s…"   52 seconds ago      Up 51 seconds                            dood

// ホストに戻る
/ # exit
// ホストからもコンテナ内で起動したコンテナが見れる
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
be56745b1af4        nginx               "nginx -g 'daemon of…"   14 seconds ago      Up 12 seconds       0.0.0.0:80->80/tcp   webserver
4cfa187ac191        docker              "docker-entrypoint.s…"   59 seconds ago      Up 57 seconds                            dood

どっちを使えばいいの?

参考2

CI用途に関してはDooDを使うのが好ましいと思います. DinDの開発者自身がブログでDinDのCI利用について述べています https://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/

ざっと要点

  • そもそものDinDの用途はDockerの開発プロセス高速化のためだった
  • DinDは次の問題がある
    • SELinuxとかをホストとコンテナで別設定にしていると、クラッシュする可能性がある
    • ホストとコンテナで別々のファイルシステムを使っているとクラッシュする可能性がある
    • /var/lib/dockerはdockerデーモンの専用領域みたいなものだから、別デーモン作って触らせると何が起きても知らないよ
  • CIをやりたないならDooDでいいんじゃない?
    • ホストとDockerデーモンを共有することで、ビルドごとにイメージのキャッシュが消えたりがなくなると思うよ
    • 上の問題点も解決すると思うよ