Docker マトリョーシカと私

この記事は Docker Advent Calendar 2015 の 21 日目です.

昨日は rotoni さんの Docker Registry Proxy Cache を使ってみる でした… と思ったら現時点ではまだ書きかけだったようです. Docker Hub のネットワークレイテンシーが気になることは度々あるので続きが非常に楽しみです.

その昔 LT でこんなことを


自分自身の LT なんですが、簡単にまとめると Docker の --privileged オプションdind を使って、Docker コンテナの中で docker コマンド使っちゃおうって話です.

コンテナの中でコンテナを起こし、さらにその中で… みたいなことができるようになります.

オンプレの CI システム(Jenkins とか)でこの privileged オプションを使って

  • CI システム自体を Docker コンテナで動かして
  • その中で各プログラミング言語/依存ミドルウェアごとの Docker コンテナが動いてて
  • さらにその中でテスト回してそのままプロダクション用とかの Docker イメージ作っちゃおう

という感じで進めれば CI 環境が各プロジェクトの依存関係で汚れなくていいですよねという話をしたんですが、結局僕自身もこの privileged を用いる方法は使っていません.

ということで今回の記事の内容は「例のスライドで紹介した privileged オプションでの Docker-in-Docker はイケてないから他の方法でやりましょ」というものです.

Using Docker-in-Docker for your CI or testing environment? Think twice.

というタイトルのブログ記事が今年の9月に界隈で話題に上がりました.

priviledged オプションの初期の実装を Docker リポジトリにコントリビュートした Jérôme Petazzoni さんという方の書かれた記事です. (彼は dind の作者でもあり、一時期はいろんなとこにこのリポジトリのフォークが生まれていました)

詳細は是非彼の記事を読んでいただきたいんですが、簡単にまとめると

  • privileged オプションはそもそも Docker 自体の開発ワークフロー改善のために作った
  • privileged x dind を CI で使ってる人多いっぽいですね
  • SELinux とか AppArmor みたいな Linux Security Modules 絡みで、環境によってクラッシュすることが分かってる
  • docker の設計は /var/lib/docker が docker デーモンの聖域であることを前提としているから、他のプロセスが触るとデータ壊れちゃうかも

僕自身が Docker-in-Docker を CI で使おうとして動作検証を行った 1 週間では上記のような問題は発生しませんでしたが、将来面倒なことが起きたときに対応に時間を割きたくなかったので、privileged オプションを使った Docker-in-Docker は見送りました.

結局どんな感じで Docker をマトリョーシカしたのか

上に紹介した記事の最後の方にも書かれていますが、以下の方法が現時点ではシンプルかつベストだと思います.

docker run -v /var/run/docker.sock:/var/run/docker.sock \
           -v $(which docker):/bin/docker \
           -ti ubuntu

privileged オプションを使った Docker-in-Docker で docker run をすると新コンテナはそので走るイメージになりますが、上記のコマンドで立ち上がったコンテナの中で docker run コマンドを実行すると、新しいコンテナはコマンドを実行したコンテナので走るというイメージになります.

この方法なら Docker が想定していない /var/lib/docker への怪しげなアクセスも発生しませんので、コンテナが外の世界に迷惑をかけるリスクを低減できます.

(初期の drone のように privileged オプションは使えるけどワーカーコンテナに対して任意のマウントオプションをつけられないみたいな CI システムを使っている場合は privileged を使うしかないかも)

以上、新・Docker マトリョーシカでした.

楽しいコンテナライフのお供にどうぞ.


追記:

Docker のバージョンや走らせる Docker イメージによっては、上記の方法で立ち上げたコンテナの中で docker コマンドを実行した時に以下のような依存ライブラリ不足のエラーが出て動かないことがあります.

docker: error while loading shared libraries: libapparmor.so.1: cannot open shared object file: No such file or directory

(このエラーメッセージはホストマシンの OS やインストールされている Docker のバージョンによって多少違いがあります)

これについては

  • apt-get install lxc とかで依存ライブラリをインストール

もしくは

  • ホスト側の libapparmor.so ファイルも -v マウントしちゃう

という感じのワークアラウンドがこことかここにも出ていますが、新しめのベースイメージを使うようにしていればほぼほぼお目にかかることはないと思います.