(本エントリはDockerの基礎知識を前提としています。)
Dockerにはイメージやコンテナレベルのアクセス制限機能がありません。つまり、Dockerデーモンに接続できる人は誰でも、全てのイメージやコンテナを操作できます。よって、社内にDockerを使う複数のプロジェクトがあり、各プロジェクトメンバーの権限をプロジェクト内に制限したい場合、Dockerホストを分ける必要があります。今回は、そんなシチュエーションでDocker-in-Docker(Dockerの入れ子)を活用する話です。
なぜアクセス制限機能がないか
コンテナを起動するときDockerホストの/(ルート)をマウントすると、コンテナの中からホストの全てのファイルにアクセスできます。つまりDockerデーモンへのアクセスはホストのroot権限と同等であり、イメージやコンテナレベルのアクセス制限をしても意味がありません。Dockerのポリシーは、「Dockerデーモンにアクセスできる者を制限せよ」です。
共用の開発用サーバ
KRAYでWebアプリケーションを開発する際には、開発中の機能を同僚エンジニアやその他の関係者に見せるためのサーバを用意します。これをインテグレーションサーバと呼んでいます。今まではVirtualBoxでインテグレーションサーバを作り、1台のオンプレミスマシンでホスティングしていました(下図)。KRAYの殆どのプロジェクトがその1台のオンプレミスマシンを使うので、メモリ不足やCPUパワー不足になることがしばしばありました。
Dockerのインテグレーションサーバ
Dockerが登場し安定して使えるようになり、まず一つのパイロットプロジェクトでVirtualBoxをDockerで置き換えました(ダニーがやってくれました)。このDockerコンテナの中ではsshdやunicornが動作し、capistranoでRailsアプリをデプロイする構成でした(下図)。つまりこのコンテナは永続的で、アプリケーションの実行環境と一体でした。
Docker-in-Docker
Dockerの特長の一つは、クリーンでポータブルなアプリケーションの実行環境を瞬時に作れることです。開発中からコンテナを使い、アプリケーションのバージョンが上がる度にクリーンな状態からコンテナを作れば、環境依存の問題を避けられます。私が8月から担当するプロジェクトでは全環境でDockerを使うことにしました。
この方針を実現するには、開発環境、インテグレーション、本番の全ての環境でそれぞれ別の課題がありましたが、今回はインテグレーション環境の話です。
上述の通り、インテグレーションサーバは既にDockerコンテナの中なので、アプリケーションをコンテナとして実行するにはDockerの中でDockerを実行する必要があります。そのためにDocker-in-Dockerのヘルパであるjpetazzo/dindを利用しました。
dindはDockerデーモンのコンテナであり、docker runするとデフォルトではDockerデーモンが起動し、最終的にbashに処理が渡ります。つまりプライベートなDockerデーモンにbashでアクセスできるのですが、これはインテグレーション環境の要件と合わないため、bashの代わりにsshdが起動するようにしました。つまり、この改造dindをインテグレーションサーバとして使うことで、中でアプリケーションコンテナを起動できます(下図)。
改造dindの使い方
今回外側のDockerホストにはUbuntu 14.04 (Linux 3.13.0-24-generic)を使いました。なお、CentOS 6.5 (Linux 2.6.32-431)ではdindの中でcgroupをマウントできず、Dockerデーモンを起動できませんでした。また、Dockerのバージョンは1.1.2です。
公開鍵
改造dindはSSHサーバなので、接続を許可する人の公開鍵をまず用意します。公開鍵は.sshに置くようにauthorized_keysという名前でリポジトリの同名ファイルと置き換えてください。そしてdocker buildします。イメージ名はここではdind-sshdとします。
docker build -t dind-sshd .
ポート
改造dindは以下のポートをEXPOSEしています。
ポート番号 | プロセス |
---|---|
22 | sshd |
8080 | アプリケーションサーバ |
docker buildしたばかりのイメージでは8080番は使って(LISTENして)いませんが、アプリケーション用に確保してあるという意味です。起動するときはこれらのポートをホスト側の決まったポートにマッピングした方が便利でしょう。例えば、ホストの12022を22に、12080を8080に割り当てる場合、docker runのオプションは-p 12022:22 -p 12080:8080となります。
その他のオプション
オリジナルからのdindの制約として、–privilegedオプションが必要です。
また、ログの出力先をLOG環境変数で指定できます……が、好きなファイルを指定できるわけではなく、-e LOG=file(文字通り「file」)と書くと/var/log/docker.logがログファイルになり、それ以外だと標準出力に吐出されます。
あとはデーモン化するために-d、コンテナの名前を指定する–name 好きな名前も付けた方が便利でしょう。
まとめると以下のようになります。
docker run --privileged -d -e LOG=file -p 12022:22 -p 12080:8080 --name 好きな名前 dind-sshd
これでホスト側の12022ポートにsshすることで改造dindの中に入れます。あとは好きなようにアプリケーションを設置してください。
まとめ
- Dockerデーモンへの接続は、ホストのroot権限を取ることと同等
- Docker-in-Dockerを使うことで、1台のホストで複数のDockerデーモンを使える
- dindをSSHサーバにするのもアリ
次回はDockerを使った本番環境の話を書く予定なので、よろしければそちらも読んでいただけると嬉しいです。
KRAYのFacebookページに「いいね!」していただけると、今後のKRAYの活動をタイムラインでお知らせできます!よろしくお願いします!
このエントリーに対するコメント
日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)
- トラックバック
「いいね!」で応援よろしくお願いします!