OSS版Drone.io(以下Drone)が立ち上げたワーカーコンテナ上でコンテナを作成する方法2つと、実際に使ってみたメリット、デメリットを書きました。
今回はDroneでの使用を前提にしていますが、Droneに限らず「コンテナから新しいコンテナをrunしたい」などという用途にも使えると思います。
環境
- Amazon Linux (on EC2)
- Docker 1.9.1
- Drone 0.4
Droneはdocker hubにある公式のコンテナを使用。
一部機能は新しいバージョンで実装された機能を使っているため、古いDockerやDroneでは動作しない可能性あり。
wrapdockerを使う
1つ目の方法は"wrapdocker"を使う方法。こちらを参考に。
build:
image: jpetazzo/dind
privileged: true
commands:
- wrapdocker
- docker build -t my_container .
Droneの設定で "Trusted"をONにする のを忘れずに。
メリット
- 手軽に使用可能
デメリット
- dindコンテナの中のDockerが作業を行う。つまり、 Droneの一連の処理が終わったらすべて消える。
- privilegedで特権を取得するのでセキュリティ的にあまりよろしくない。らしい。
docker.sockを使う
ホストのdockerの/ver/run/docker.sockをマウントしてホストのDockerを操作する。
コンテナの準備
Dockerのモジュールが入ったコンテナを作成する。
FROM debian:jessie
# --build-argで定義した変数を使用するために必要
ARG DOCKER_VERSION
RUN apt-get update && apt-get install -y apt-transport-https ca-certificates
# Dockerをダウンロードするための設定
RUN apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
RUN echo deb https://apt.dockerproject.org/repo debian-jessie main > /etc/apt/sources.list.d/docker.list
# Dockerのインストール
RUN apt-get update && apt-get -y install docker-engine=${DOCKER_VERSION}-0~jessie
Docker公式のセットアップ手順を参照に、コンテナの中にDockerをセットアップしているだけ。
ベースはDebianにしているけど、Ubuntuでもほぼ同様。
Debian
https://docs.docker.com/engine/installation/linux/debian/
Ubuntu
https://docs.docker.com/engine/installation/linux/ubuntulinux/
ビルドする。
docker build --rm --build-arg DOCKER_VERSION=$(docker version --format='{{.Server.Version}}') -t my_docker_in_docker .
--rmオプションで中間を消すのはお好みに応じて。このコンテナでわざわざキャッシュを残しておく意味はないと思う。
Dockerのバージョンを定義しているのは、ホストとクライアント(コンテナ)のDockerでAPIバージョンを合わせておかないとエラーが起きるため。
(常にどちらも最新バージョン同士なら問題ないだろうけど、今回はAmazon Linuxのリポジトリにある最新のDockerとDebianの最新版のバージョンがずれていたためエラーが起きた。)
Drone側の準備
準備と言っても.drone.ymlですけど。
build:
image: my_docker_in_docker
volumes:
- /var/run/docker.sock:/var/run/docker.sock
commands:
- docker build -t my_container .
メリット
- pullしたベースやbuildしたコンテナ(中間含む)はすべてホストのDockerの管理下に置かれるのでキャッシュが利くし、ホストのDockerを操作している感覚(というか、実際にホストに対して操作しているのだけど)でよい。
デメリット
- 一度やったら後は楽だけど、準備がやや面倒。
- この方法も、本当ならセキュリティ的にあまりよろしくない。らしい。
まとめ
dindで何回かテストをしてみたけど、ベースを毎回pullしてくるし、ゼロからコンテナ作り直してるじゃん。ということで他の可能性を調べた末の方法がdocker.sockを使う方法でした。
やっぱりキャッシュが利く方がいいよね。
結局どっちも「セキュリティ的にあまりよろしくない」のね。そのあたりは参考のリンク先をご一読を。
その他
「wrapdockerのデメリットをなくすために、dindコンテナに対象のベースコンテナををpullしてcommitしておけばいいんじゃね?」とも思ったけど、それだと「ベースが更新されるたびに手動で作り直さないといけないよね」ということで考えるのを止めました。
参考
OSS版 drone.io を使って Docker Image をビルド
http://qiita.com/quickguard/items/3b711fc871f42bf0772d
Docker マトリョーシカと私
http://orih.io/2015/12/we-should-think-twice-about-using-docker-in-docker/
Dockerコンテナ内からホストマシンのルートを取る具体的な方法(あるいは/var/run/docker.sockを晒すことへの注意喚起)
http://rimuru.lunanet.gr.jp/notes/post/how-to-root-from-inside-container/