開発環境を構築したり、ツールを導入したりするのに、パッケージ管理システムはよく使われる。よく目にするものでも、Homebrew・yum・apt-get・npm・pip・gem...などいろいろある。
パッケージ管理システムはエンジニアを面倒な作業から開放してくれる。コマンドひとつで、オンラインからパッケージを探せて、ダウンロードでき(リポジトリの機能)、パッケージを追加したり削除したりもできる(インストーラの機能)。さらに、パッケージに必要な別のパッケージを同時にインストールしてくれる(依存関係解決機能)。たとえば、Ubuntuでhttpieが欲しいと思ったら、次のコマンドを打ってしばらく待てば使えるようになる。
$ apt-get install httpie
パッケージ管理システムとしてのDocker
ところで、話題のツールにDockerがある。Dockerはインフラ構築の文脈で、開発環境や本番サーバのプロビジョニングして配置するような活用方法が紹介されることが多いように思う。Dockerはパッケージ管理ツールではない。だが、Dockerにはオンラインでコンテナを探せてダウンロードできるレジストリがあり、コンテナを追加・削除できるインストーラのような機能がある。それにコンテナはそれが動作するために必要なパッケージをすべて含んでいる。これはまるでパッケージ管理システムのみたいではないだろうか。
表1. パッケージ管理システムとDockerの機能の対応
パッケージ管理システム | Docker |
---|---|
リポジトリの機能 | レジストリ, docker pull , docker push
|
インストーラの機能 |
docker run , docker rm , docker rmi
|
依存関係解決機能 | ビルドされたコンテナ, Dockerfile
|
ツールとしてのコンテナ
ここにシンプルなdockerのコマンドがある。このコマンドを実行すると、UbuntuコンテナがDockerレジストリからダウンロードされ、最後に現在日時が表示される。このdateコマンドはダウンロードしてきたUbuntuの環境の中で動いたものだ。Dockerを使っている人にとっては当たり前のことだろう。
$ docker run ubuntu date
Wed Aug 20 14:35:04 UTC 2014
dateコマンドがない環境はあまりなさそうだが、Node.jsが入っていない環境はあるかもしれない。そんなときにNode.jsを少し試したいと思ったら、次のコマンドを走らせればレジストリからREPLが降ってくる。
$ docker run -it node node
> "foo".indexOf("oo");
1
> [1, 2, 3].join(",");
'1,2,3'
驚くほどのことではないが、着目したいのはDockerが環境を変更しない点だ。パッケージ管理ツールであれば、Node.jsが依存するパッケージを更新して環境を壊してしまうかもしれない。一方、上のコマンドにはそれがない。そのため、新しいツールを試しに走らせてみることも安心してできる。例えば、Redisの導入を検討していて動かしてみたいなら次のコマンドを実行すればいい。
$ docker run -d --net host --name redis-server redis
$ docker run -it --net host redis redis-cli
127.0.0.1:6379> SET foo bar
OK
127.0.0.1:6379> KEYS *
1) "foo"
加えて、Dockerならツールを使い終わった後も環境を汚さない。ここまでに実行したDockerのコマンドはコンテナが残ってしまっている。docker ps -a
を実行したらそれが分かるはずだ。redis-cliを実行するコマンドに--rm
をつければ、使い終わったコンテナは自動的に削除される。-d
で起動したコンテナやイメージも不要とあらば簡単に消すことができる。
$ docker run -it --rm --net host redis redis-cli
不要とあらば
$ docker rm -f redis-server
$ docker rmi redis
ファイルを読み書きしてこそ真価を発揮するツールはどうしたらいいだろうか?例えば、Go言語のコードをビルドしたかったら、-v
でDockerホストのディレクトリをマウントするといいだろう。Dockerのtipsとして、-w
オプションと組み合わせた-v `pwd`:/wd -w /wd
を渡すと、シームレスにファイルを扱うことができる。
package main
func main() {
println("Hello World")
}
このhello-world.goはDockerホスト上にある。それでも下のコマンドでビルドは成功し、バイナリがホスト上に出来上がる。
$ docker run -it --rm -v `pwd`:/wd -w /wd google/golang go build hello-world.go
$ ls
hello-world hello-world.go
$ ./hello-world
Hello World
-v
を応用すれば、rbenvやphpenv、ndenvなしにバージョン間の振る舞いの違いを調べたり、自分好みにカスタマイズしたvimのコンテナを作っておいて、どのサーバに行っても自分のvimが使えるといったことも可能かもしれない。
エイリアスはまるで遅延評価
以上のちょっとしたtipsを踏まえて、httpieをツールとしてDockerでインストール・実行しようとしたら、次のコマンドになる。
$ docker run -it --rm --net host clue/httpie PUT httpbin.org/put hello=world
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 531
Content-Type: application/json
Date: Wed, 20 Aug 2014 16:12:34 GMT
Server: gunicorn/18.0
...省略...
パッケージ管理システムを使わないぶん、httpieを入れるために環境を汚したりすることはないが、コマンドが長くなりこれではapt-get
で入れたほうがましだ。この問題を解決する手っ取り早い方法は、エイリアスを作ることだ。
alias http="docker run -it --rm --net host clue/httpie"
こうしておけば、先ほどのコマンドはこれだけになる。
$ http PUT httpbin.org/put hello=world
aliasを.bashrcなどに書く習慣にならって、上のエイリアスも.bashrcなどに追加しておいてはどうだろう?そして、その.bashrcをチームで共有したり、Dockerホストのベースイメージに加えておくと面白い体験ができる。httpieがまだない環境でも、httpコマンドは叩くことができる。そして、httpコマンドをはじめて実行したときに自動的にそれがインストールされ、そのまま実行される。言い換えると、必要になるまでインストールされない。これはまるでプログラミング言語の遅延評価のようだ。
課題があるとしたら…
Dockerをバージョン管理ツールとして使うのに課題は無いだろうか?1つ目の課題は、ファイルサイズだ。Dockerのコンテナはファイルシステムがまるごと入ってくるため、どうしても必要以上に容量を使ってしまう恐れがある。コンテナのベースをCoreOSなど小さなサイズのOSにするなどの工夫はできるが、通常のパッケージ管理ツールよりも容量を使いがち。これは環境を汚さないなどの利便性とのトレードオフなのかもしれない。
2つ目の課題は、ダウンロードの遅さだ。コンテナによっては、ファイルシステムのレイヤが多かったりと、ダウンロードに結構時間がかかってしまう場合がある。また、公式のDocker Registryはとても便利だが、自前で建てたRegistryよりも遅い気がする。これは今後改善していくことに期待したい。
3つ目の課題は、複雑なオプションだ。この記事で示したdocker run
のオプションの数は少ないほうだと思う。実際にいろいろな場面で試してみると、環境変数を渡すために-e
オプションだらけになったり、-v
を何個もつかってマウントしないといけないケースも出てくる。エイリアスを.bashrcに定義するケースでも、-v `pwd`:/wd -w /wd
のpwd
は遅延評価させないとホームディレクトリ固定になってしまう課題もある。Dockerをパッケージ管理ツールとして使う人が増えてきたら、こうした課題を解消してくれるツールが登場するかもしれない。
パッケージ管理は無くなるか?
たぶんパッケージ管理ツールはなくならない。まず、DockerがLinuxでしか動かないからだ。Macで同じことをやろうとしてもできないので、Homebrewにはしばらくお世話になりそうだ。とは言っても、WindowsやMacもDockerにインスパイヤされた何かを出してくるかもしれない。そうしたら、Linux以外の環境でもパッケージ管理は無くなるかもしれない。
そうなれば、ユーザの手からはパッケージ管理ツールが離れるかもしれない。それでも、コンテナの作り手はパッケージ管理を使い続けるだろう。さすがに、自力で依存関係を管理したりするのは手間だろうから…。
おわりに
今回はパッケージ管理ツールとしてのDockerの可能性について考えてみた。Dockerは可能性に満ちたツールだ。どんな使われ方が考案されてくるか楽しみだ。