Dockerで何が変わるのか

DockerCon 2014 に行ってきた。

この会期中には各社からいくつもの製品が紹介/発表された。そして、それによってクラウドという技術は次のステージに移行したと言っても過言ではないだろう。

より自由にユーザーがクラウドベンダーを選べる時代へ。どうやってクラウドにうまくデプロイするかではなく、アプリケーションそのものに注力できる時代へ。

Dockerとは

Docker とはいわゆるコンテナ技術の1つで、Linuxホスト環境の中に隔離された別のLinux環境を作ってくれる技術だ。

軽量仮想マシンと呼ばれたりもする。 Solaris Container とも似ている。

新しくないDocker

1つ述べておくとDockerは技術的には新しくない。Dockerの価値は技術以外にある(とDockerのCEOもDockerConで言ってた)。

技術的にはSolarisにはSolaris 10の頃からあるし(ruby-lang.orgも使ってた)、LinuxにだってLXCがKernel 2.6の頃からある。そもそもの話Dockerの初期のバージョンはLXCのラッパーみたいなもんだった。

仮想マシンに似ているという観点から述べるなら、コンテナ技術というのはマシンやOSそのものを仮想的に実現してその上でアプリケーションを動かす代わりにマシンとカーネルはホストのものをそのまま使って、ユーザーランド+αだけを仮想化する、みたいなもんだ。

別の視点から述べると、これって要するにchroot+αだ。「ちょっとすごいJail」と言ってもいいだろう。Chrootだとファイルシステムだけが隔離されるけど、その他にDockerではプロセスIDのネームスペースや、ユーザーIDやネットワークポートの空間も隔離される。Dockerの中のrootはホスト環境のrootとは違うユーザーだし、プロセス番号は同じでも違うプロセスだし、TCP portも同様。要は、これぐらい一通りホスト環境から隔離してやればユーザーランドから見ると仮想マシンに隔離されてるも同然だよね、という話。実際にはカーネルはホスト環境のやつを使ってるけど、ユーザーランドからそれを知るすべはほとんどない筈。

新しいDocker

Dockerが新しいのは、コンテナ環境で走らせるアプリケーションを簡単にパッケージする標準的な方法を確立したことにある。

Dockerは、ユーザーランドで使われるGNU/Linuxディストリビューションファイルシステムひと揃いをメタデータと一緒に固めた形式を定義している。要するに仮想ディスクイメージなんだけど。

また、イメージはしばしば他のイメージから派生する。その場合は元のイメージからの差分だけが保存されるので軽量である。

更に、イメージはgitのコミットと同じ要領で内容のハッシュで識別されることになっている。

これらが合わさると、こういうことになる。アプリケーションを含まないOSだけのbaseイメージ(例えばUbuntu preciseイメージ)はみんなが大抵手元に持っているし、必要であれば公式のリポジトリから簡単にダウンロードできる。

そのベースイメージから派生した自分のアプリケーションインスール済み環境を配布したいとする。

受け取る相手は、今自分が受け取ろうとしているイメージの派生元を辿って行く。既に持っている分は改めて取得する必要はなくて、そこからの差分だけを転送すればよい。つまり、ディスクイメージの転送が軽量にできる。

同じ内容のイメージは必ず同じハッシュを持つので、既に持っているかどうかは簡単に判別できる。この辺もgitと同じだ。

更に、こうして作成された差分ディスクイメージを走らせるときもホスト環境のディスクを無駄に使わず、起動時にマージなんてアホなことをすることもなく、効率的にインスタンス化できるようになっている。

こういう便利なパッケージの仕組みをオープンソースで作った。そしてこの仕組みをみんなが使い始めた。みんなというのはGoogle, Amazon, IBM, Microsoft, Rackspace, ...を含む。

新しいクラウドの話

Dockerはそれ単体で使っても便利なものだ。プロセスを隔離したいときのchrootの不便を解消できる。

Chrootだと、chroot環境のファイルシステムを作るのが結構面倒でみんな自作のスクリプトで頑張ったりしたものだった。Dockerなら簡単にUbuntuでもCentOSでも好きな環境のイメージを作れる。 *1

しかし、Dockerが本当に便利なのはクラウド環境との組み合わせで、イメージを他のマシンに転送するときだ。手元のマシンでDockerイメージを作り込んでプロダクション環境に転送、実行してやる。すると、手元で設定したアプケーションがそのままプロダクションで動く。ファイルを配備して、ユーザーを作成して、設定ファイルを弄って、みたいな成果物をそのままの状態で転送できる。もう苦労してプロダクション環境を適切にセットアップしてやる必要はない。つまり、ProvisioningやDeploymentの手順が劇的に簡略化される。

Dockerさえ設定しておけば、あとはイメージをポイッと配布するとそれがそのまま動くのだ。

最初にDockerを軽量仮想マシンぽいものだと言ったけれど、ここに至っては仮想化であるということは手段の1つでしかなくてあまり重要なことではない。重要なのは設定済みのアプケーション動作環境をユーザーランドまるごとパッケージして軽量に移動できるということのほうだ。

そして、これがクラウドの主要ベンダーたちによってサポートされた。

  • GoogleはManaged VMを発表した。ユーザーがアップロードしたDockerイメージがAppEngine相当のmanaged環境で実行される。AppEngine同様の「Googleが運用の面倒を見てくれる」手軽さがありながら、Dockerイメージには任意の言語で任意のアプケーションを入れられる。
  • AmazonはElastic BeanstalkでDockerをサポートした。話としてはManaged VMと同じだ。
  • ...

こうして各社がDockerをサポートした。つまり、クラウド環境で動かすためにアプケーションをパッケージングし転送する標準的な方法が生まれた。もうベンダーロックインを心配しなくていい。他社のサービスへ移りたくなったらそのDockerイメージを移動先に改めてアップロードすれば良い。

libswarm

今回のDockerConでは、もう1つベンダーロックインをなくすための製品が発表された。

なるほど、一個のサービスはDockerで簡単に配備できるし移動もできるかもしれない。しかし、今どきのクラウド上のアプケーションというのは1つのサービスだけで動く訳ではない。データベースに、キャッシュに、バックエンドサーバー、フロントエンドwebアプケーションサーバーなどなど沢山のroleを為すそれぞれの種類のサーバーインスタンスがあって、それぞれを適切に繋げてやらねばならない。しかもクラウド上の話だからしばしばサーバーのIPはクラウドベンダーに割り振られる。IP決めうちであらかじめ設定してからイメージを作るという訳にもいかない。つまり、依存する各サーバーが他のサービスを発見して繋ぎにいくというサービスディスカバリとオーケストレーションの問題が発生する。

この問題に対しては既にいくつものソリューションがある。fleet+etcdだとか、gearだとか。うまく使えばDNSも解になり得るだろう。クラウドベンダーも思い思いに解決法を提供している。

真の問題は、解決法が多すぎることだ。未だに標準的な方法はないし、どこかのベンダーの機能を使えば、サービスのオーケストレーションという要の部分を握られてロックインされる。

そこでDockerはこの度libswarmを発表した。libswarmはこの様々な実装を抽象化したAPIを提供するライブラリだ。

個人的にはlibvirtオーケストレーション版、という理解をしている。

libswarmによっていよいよクラウドベンダー間の移動は楽になる。もっと安いところ、もっとスケールするところ、などなど必要に応じて他のベンダーに自由に移動できる時代がやってくる。

Kubernetes

そしてKubernetesは更にその一歩先の話、だと思うけどその話は後で書く

Disclaimer このブログはYuguiの個人的なものです。ここで述べられていることはDockerConで聞いた話の個人的理解、および個人的な意見に基づくものであり、私の雇用者には一切の関係はありません。

上で間違ってdocker imageのidがcontent hashかのように書いたが、それは次期イメージフォーマットの話で現在はイメージ作成時にランダムに決まる256bitだった。イメージ生成時にはキャッシュが効くので続けざまに二回同じイメージをビルドすると同じIDが帰ってくるが、別のホストで独立に同じイメージをビルドしても別のIDになる。

*1:隔離されていて予測可能な状態にある環境というのはビルドやなんかにはとても便利だ。だからDockerのビルドスクリプトはDocker環境の中でDockerをビルドする