Motivation
CoreOSがApache 2ライセンスで2014年12月1日に公開したRocketを試してみます。流行のDockerのalternativeになりうるのか。
Conclusion
- ACI (App Container Image)で固められたetcdがRocketで動作することを確認した
- systemd-nspawnによるサンドボックス化がコンテナ動作の核となっている
- Dockerイメージか、Rocket ACIか、どちらのコンテナ形式で多くのアプリがbuild, ship, runされるようになるか。結局、「形式、フォーマット」なので、多くの人がそれに乗っかるかどうか、乗っかるだけのよさがあるかどうかが今後の注目ポイント
TODO
- ACI specを深追いしてDockerイメージとの違いを明らかにする
- そもそもsystemd-nspawnっておいしいの?を明らかにする
- stage0, stage1, systemd-nspawnといったRocketのシーケンス、プロセスモデルを明らかにする
Backgroud
RocketはDockerのalternativeとしてCoreOSの人たちがつくった。曰く…
CoreOS is building a container runtime, Rocket
https://coreos.com/blog/rocket/Unfortunately, a simple re-usable component is not how things are playing out. Docker now is building tools for launching cloud servers, systems for clustering, and a wide range of functions: building images, running images, uploading, downloading, and eventually even overlay networking, all compiled into one monolithic binary running primarily as root on your server. The standard container manifesto was removed. We should stop talking about Docker containers, and start talking about the Docker Platform. It is not becoming the simple composable building block we had envisioned.
残念なことに、単純で再利用可能なコンポーネントというのは現在のDockerが目指している方向ではない。Dockerは今や、クラウドサーバ群、クラスタ向けシステム群を立ち上げるためのツール群と、幅広い機能(イメージの作成・動作・アップロード・ダウンロード、さらにはオーバレイネットワークまでも)を、rootで動作するモノリシックなバイナリで提供している。Standard Container Manifestoは削除された。Dockerコンテナについて話すのではなく、Dockerプラットフォームについて話さなくてはならなくなった。我々が望んでいた、シンプルで組み合わせ可能なビルディングブロックではなくなってしまっている。
確かにDocker自身のロードマップとしても、単なる「コンテナイメージの規定と保持、コンテナのハンドリング」、というところから、オーケストレーション、ネットワークなど周辺系に広がりを見せていたのは確か。その辺はDockerの外でやるべき、すくなくともモノリシックなつくりは回避すべき、というのがCoreOSの人たちの意見に聞こえます。
単純にForkする方向ではなく、独自にRocketを作るに至った理由としては、曰く、
CoreOS is building a container runtime, Rocket
https://coreos.com/blog/rocket/Why not just fork Docker?
From a security and composability perspective, the Docker process model - where everything runs through a central daemon - is fundamentally flawed. To “fix” Docker would essentially mean a rewrite of the project, while inheriting all the baggage of the existing implementation.
セキュリティと組合せ可能性の観点から、Dockerのプロセスモデル、すなわち、中央集権的なデーモン経由ですべてが動作する、というのは、本質的に欠陥がある。Dockerを"修正する"ことは、すなわち過程で既存の実装に関する悩みをすべて引き継ぐことになり、本質的にプロジェクト全体を書き直すことになってしまう。
となかなか痛烈です。ということで、まずはRocketがどんなものかを理解するため動作させてみました。
Environment
CentOS 7.0 x86_64 powered by Vagrant on Windows 7.
Setup
https://github.com/coreos/rocket のREADME.mdにセットアップ手順が書いてあります。ライセンスはApache 2、言語はGoです。
curl -L https://github.com/coreos/rocket/releases/download/v0.1.0/rocket-v0.1.0.tar.gz -o rocket-v0.1.0.tar.gz
tar xvzf rocket-v0.1.0.tar.gz
cd rocket-v0.1.0
./rkt help
セットアップ手順といっても、ELF 64-bit LSB executableなバイナリのtarballをダウンロードしてきて展開するだけです。展開された内容とfile, lddの結果は以下の通り。
[vagrant@localhost rocket-v0.1.0]$ ls -l
total 37560
-rwxr-xr-x 1 vagrant vagrant 8127496 Dec 1 07:00 actool
-rw-rw-r-- 1 vagrant vagrant 5386 Dec 1 07:01 README.md
-rwxr-xr-x 1 vagrant vagrant 30320048 Dec 1 07:00 rkt
[vagrant@localhost rocket-v0.1.0]$ file actool rkt
actool: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
rkt: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
[vagrant@localhost rocket-v0.1.0]$ ldd actool rkt
actool:
linux-vdso.so.1 => (0x00007fff2a8ec000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f37ed06a000)
libc.so.6 => /lib64/libc.so.6 (0x00007f37eccd6000)
/lib64/ld-linux-x86-64.so.2 (0x00007f37ed28d000)
rkt:
linux-vdso.so.1 => (0x00007fff347ff000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f88bdc38000)
libc.so.6 => /lib64/libc.so.6 (0x00007f88bd8a4000)
/lib64/ld-linux-x86-64.so.2 (0x00007f88bde5b000)
actoolは、アプリケーションをパッケージングしたものであるACI (App Container Image)を取り扱うためのもの、rktはRocketで実際にACIから実稼働コンテナを動作させたりするもの、という役割分担に見えます。それぞれのヘルプから可能なコマンドを抜粋。
rkt - rocket, the application container runner
rkt fetch Fetch image(s) and store them in the local cache
rkt status Check the status of a rkt job
rkt run Run image(s) in an application container in rocket
actool - actool, the application container tool
actool build Build a Fileset ACI from the target directory
actool discover Discover the download URLs for one or more app container images
actool validate Validate that one or more images or manifests meet the AppContainer specification
Fetch & Run
手順に従いACIをfetchしてrunしてみます。
[vagrant@localhost rocket-v0.1.0]$ ./rkt fetch https://github.com/coreos/etcd/releases/download/v0.5.0-alpha.4/etcd-v0.5.0-alpha.4-linux-amd64.aci
fetch: error creating image directory: mkdir /var/lib/rkt: permission denied
Rocketの動作バイナリを一般ユーザでダウンロードしただけなので、/var/lib/rktが作れませんでした。Rocket自身のパッケージングと配布がうまくいきはじめたらこのへんの正しいやり方が整備されてくるのだと思うのですが、とりいそぎ今はsudoしてみます。
[vagrant@localhost rocket-v0.1.0]$ sudo ./rkt fetch https://github.com/coreos/etcd/releases/download/v0.5.0-alpha.4/etcd-v0.5.0-alpha.4-linux-amd64.aci
sha256-f9215c18b86f406c7cec4c7b45fd8752b5bfd1a492507d647821c2ce593fbf31
fetchによりダウンロードされたファイルは以下の2つ。cas/blobとcas/remoteのそれぞれの1つずつ。casってのは、Contents Addressable Storageですね。
/var/lib/rkt/cas/blob/sha256/f9/sha256-f9215c18b86f406c7cec4c7b45fd8752b5bfd1a492507d647821c2ce593fbf31
/var/lib/rkt/cas/remote/sha256/8e/sha256-8eac4158f86ae7d7e78f52e48ab18dcefdbc56104010de295b4c637e7ff4f02a
cas/blobの方はtarアーカイブで、以下のディレクトリ構成でetcdのバイナリがパッケージングされています。
[vagrant@localhost rocket-v0.1.0]$ tar xvf /var/lib/rkt/cas/blob/sha256/f9/sha256-f9215c18b86f406c7cec4c7b45fd8752b5bfd1a492507d647821c2ce593fbf31
rootfs/
rootfs/Documentation
rootfs/Documentation/0_4_migration_tool.md
rootfs/Documentation/admin_guide.md
rootfs/Documentation/api.md
rootfs/Documentation/clustering.md
rootfs/Documentation/configuration.md
rootfs/Documentation/glossary.md
rootfs/Documentation/other_apis.md
rootfs/Documentation/proxy.md
rootfs/Documentation/runtime-configuration.md
rootfs/README-etcdctl.md
rootfs/README.md
rootfs/etc
rootfs/etc/hosts
rootfs/etcd
rootfs/etcd-migrate
rootfs/etcdctl
app
いっぽうcas/remoteの方はJSONファイルです。blobのSHA256ハッシュ値と、どこから取ってきたかが含まれています。
[vagrant@localhost rocket-v0.1.0]$ cat /var/lib/rkt/cas/remote/sha256/8e/sha256-8eac4158f86ae7d7e78f52e48ab18dcefdbc56104010de295b4c637e7ff4f02a | python -m json.tool
{
"Blob": "sha256-f9215c18b86f406c7cec4c7b45fd8752b5bfd1a492507d647821c2ce593fbf31",
"ETag": "",
"Mirrors": [
"https://github.com/coreos/etcd/releases/download/v0.5.0-alpha.4/etcd-v0.5.0-alpha.4-linux-amd64.aci"
],
"Name": "https://github.com/coreos/etcd/releases/download/v0.5.0-alpha.4/etcd-v0.5.0-alpha.4-linux-amd64.aci"
}
それでは、fetchしたetcdをrkt runしてみます。/var/lib/rkt/containers配下に書き込みむようなので、安直にsudoで。
[vagrant@localhost rocket-v0.1.0]$ sudo ./rkt run sha256-f9215c18b86f406c7cec4c7b45fd8752b5bfd1a492507d647821c2ce593fbf31
stage1/usr/bin/systemd-nspawn: error while loading shared libraries: libseccomp.so.2: cannot open shared object file: No such file or directory
seccompがいるらしいので、yumで入れてから再チャレンジ。
[vagrant@localhost rocket-v0.1.0]$ sudo yum install libseccomp
(snip)
[vagrant@localhost rocket-v0.1.0]$ sudo ./rkt run sha256-f9215c18b86f406c7cec4c7b45fd8752b5bfd1a492507d647821c2ce593fbf31
Timezone UTC does not exist in container, not updating container timezone.
2014/12/04 00:19:29 no data-dir provided, using default data-dir ./default.etcd
2014/12/04 00:19:29 etcd: listening for peers on http://localhost:2380
2014/12/04 00:19:29 etcd: listening for peers on http://localhost:7001
2014/12/04 00:19:29 etcd: listening for client requests on http://localhost:2379
2014/12/04 00:19:29 etcd: listening for client requests on http://localhost:4001
2014/12/04 00:19:29 etcdserver: name = default
2014/12/04 00:19:29 etcdserver: data dir = default.etcd
2014/12/04 00:19:29 etcdserver: snapshot count = 10000
2014/12/04 00:19:29 etcdserver: advertise client URLs = http://localhost:2379,http://localhost:4001
2014/12/04 00:19:29 etcdserver: initial advertise peer URLs = http://localhost:2380,http://localhost:7001
2014/12/04 00:19:29 etcdserver: initial cluster = default=http://localhost:2380,default=http://localhost:7001
2014/12/04 00:19:29 etcdserver: start member ce2a822cea30bfca in cluster 7e27652122e8b2ae
2014/12/04 00:19:29 etcdserver: added local member ce2a822cea30bfca [http://localhost:2380 http://localhost:7001] to cluster 7e27652122e8b2ae
2014/12/04 00:19:30 raft: elected leader ce2a822cea30bfca at term 1
2014/12/04 00:19:30 etcdserver: published {Name:default ClientURLs:[http://localhost:2379 http://localhost:4001]} to cluster 7e27652122e8b2ae
無事にetcdが動き始めたようです。
sudo ps auxから関係しそうなプロセスを抜粋。
root 10416 0.0 0.5 189372 2700 pts/0 S+ 00:19 0:00 sudo ./rkt run sha256-f9215c18b86f406c7cec4c7b45fd8752b5bfd1a492507d647821c2ce593fbf31
root 10417 0.3 0.1 21660 872 pts/0 S+ 00:19 0:00 stage1/usr/bin/systemd-nspawn --boot --register false --quiet --uuid=0d5bee94-3158-4cc2-a1ef-3
root 10422 0.0 0.4 22564 2140 ? Ss 00:19 0:00 /usr/lib/systemd/systemd --default-standard-output=tty --log-target=null --show-status=0
root 10423 0.0 0.0 4108 388 ? Ss 00:19 0:00 /usr/bin/sleep 9999999999d
root 10424 1.3 1.3 12024 6272 ? Ssl 00:19 0:02 /etcd
根幹となるコンテナの起動はsystemd-nspawnに任せているようです。Rocketの概念として、stage0, stage1という段階を経ているよう模様。
Remarks
まずはチュートリアルどおりコンテナを動かすところまでは無事いきました。この浅さではまだなんともいえないですが、DockerにしろRocketにしろ、アプリケーションのパッケージング方式がミソなので、「Dockerイメージ」と「Rocket ACI」のどちらがスジがいいのか、多くのアプリケーションが配布・流通するようになるのか、というのを見極める必要があります。
最近いわれているDockerコンテナのセキュリティ、横にちょっかいを出せる系の課題にたいして、Dockerやその下回りにきちんとした隔離機能を追加する方向でガンバルのか、Rocketのように再発明する方向でガンバルのか、どちらがよいのかは、サンドボックス化そのものを担うコンポーネントたち(libcontainer (←これは抽象化層だけれど), systemd-nspawn)のスジのよさも含めて見る必要があります。
CoreOSの人たちが痛烈に指摘している、Dockerのプロセスモデルの課題(中央集権的なデーモン経由ですべてが動作する)に対して、Rocketがどのようにアプローチしている、していくのか。そこは、Rocketの内部構造を紐解きながら見ていきたいところです。
そんじゃーね!!!