はじめてのRocket
先日、CoreOS がRocketというコンテナ実行エンジンを発表して話題になりますた。
Rocketを少し触ってみたので簡単なまとめを書いておこうと思います。
チュートリアル
簡単にRocketでコンテナ起動までをやってみましょう。
簡単にREADMEに目を通しておくことをすすめます。
今回はfilesetを作るのがめんどいのでDockerコンテナを流用します。
そのためDockerをインストールしておきます。
インストール
早速Rocketをインストールしてみましょう。
ビルドするには以下のものが必要です。
- cpio
- squashfs-(util)
- go-bindana
(他にもあるかな?)
$ git clone https://github.com/coreos/rocket.git
$ cd rocket
$ ./build
少し前までgo-bindataがらみでメモリが足りずにビルドによく失敗していましたが、今は修正されています。
(8Gでもビルドできない)
bin
以下にrkt
などが作成されるはずです。
App Container の作成
せっかくなので今回はnginx
のコンテナを立ち上げてみます。
filesetの作成をイチからやるのはしんどいのでDockerから流用します。
$ sudo docker run --name nginx nginx
nginxのコンテナを一度起動し、停止させます。
これでnginxのコンテナをexportできるようになります。
$ mkdir rootfs
$ sudo docker export nginx | sudo tar -x -C rootfs -f -
manifest.json
は以下です。
{
"acVersion": "1.0.0",
"acKind": "AppManifest",
"name": "nginx",
"os": "linux",
"arch": "amd64",
"version": "1.0.0",
"exec": [
"/usr/sbin/nginx -g 'daemon off;'"
],
"ports": [
{
"name": "nginx",
"port": 80
}
]
}
actool
を使い、ACIを作成します。
$ sudo actool build --app-manifest manifest.json rootfs nginx.aci
起動
ではこのコンテナを起動させてみましょう。
$ sudo rkt --debug run nginx.aci
debug
オプションをつけて起動するとDebug Logを出すことができます。
2014/12/05 18:33:09 Unpacking stage1 rootfs
2014/12/05 18:33:10 Writing stage1 init
2014/12/05 18:33:10 Wrote filesystem to /var/lib/rkt/containers/b879414c-33bd-4afd-bba0-0e3c50e4a767
2014/12/05 18:33:10 Loading image sha256-aed279320c457e4f11bc8c717cc785284883dd525476342c813878ad3e7d224f
2014/12/05 18:33:11 Writing container manifest
2014/12/05 18:33:11 Pivoting to filesystem /var/lib/rkt/containers/b879414c-33bd-4afd-bba0-0e3c50e4a767
2014/12/05 18:33:11 Execing stage1/init
Spawning container stage1 on /var/lib/rkt/containers/b879414c-33bd-4afd-bba0-0e3c50e4a767/stage1.
Press ^] three times within 1s to kill container.
Timezone Asia/Tokyo does not exist in container, not updating container timezone.
systemd 215 running in system mode. (-PAM -AUDIT -SELINUX +IMA -SYSVINIT +LIBCRYPTSETUP -GCRYPT -ACL -XZ +SECCOMP -APPARMOR)
Detected virtualization 'systemd-nspawn'.
Detected architecture 'x86-64'.
Welcome to Linux!
Initializing machine ID from container UUID.
[ OK ] Created slice -.slice.
[ OK ] Created slice system.slice.
Starting Graceful exit watcher...
[ OK ] Started Graceful exit watcher.
Starting nginx...
[ OK ] Started nginx.
[ OK ] Reached target Rocket apps target.
http://localhost にアクセスしてnginx
のindex.htmlが表示されてばOKです。
コンテナの終了はログにも出ている通りエスケープを3回叩けばよいです。
Press ^] three times within 1s to kill container.
Dockerと異なり、ネットワークはホストのものを使用します。
そのため、IPやポートはそのまま使用できます。
Rocket の基礎
Rocketはコンテナ実行エンジンとしてどのような処理を行ってコンテナ化を実現しているのでしょうか?
READMEにも書いてありますが、Rocketの処理は以下の段階に分かれます。
基本的なことはREADMEにも記載してあるので補足情報をつけ、順におってみてみます。
- stage0
- stage1
- stage2
なお、Rocketはまだプロトタイプなので今後変更が入るかもしれません。
stage0
stage0
はコンテナの土台となる最初のステージです。
コンテナの土台になるディレクトリの作成、stage1/stage2のセットアップ
コンテナの実行エンジン部になるstage1のinitのコピーなどを行います。
ディレクトリの作成系が主な処理です。
ユーザーが指定しているApp Container部はstage2の部分にあたります。
このステージでACIをダウンロード、キャッシュ、コンテナ内へのstage2部へのコピーを行います。
Logで見るとこの部分ぐらいがstage0
です。
2014/12/05 11:49:44 Unpacking stage1 rootfs
2014/12/05 11:49:44 Writing stage1 init
2014/12/05 11:49:45 Wrote filesystem to /var/lib/rkt/containers/334f58db-4fbc-47d6-b48d-8228df401152
2014/12/05 11:49:45 Loading image sha256-f9215c18b86f406c7cec4c7b45fd8752b5bfd1a492507d647821c2ce593fbf31
2014/12/05 11:49:45 Writing container manifest
Rocketのコンテナ実行エンジン部(ACE)は以下の構成のディレクトリで動作します。
/container
/stage1
/stage1/init
/stage1/opt
/stage1/opt/stage2/sha256-8a30f14877cd8065939e3912542a17d1a5fd9b4c
- /container ACI内manifest.jsonです
- /stage1 実行エンジン部になるOSのルートディレクトリです。
- /stage1/init 実行エンジン部になるOSのinitです。
- /stage1/opt/stage2/xxxxxx App Containerルートです。
このあとstage1
へ移行します。
現状では起動毎にコンテナを作成します。
stage1
コンテナを起動するステージです。
簡単に説明すると以下にような流れになります。
-
manifest.json
を元にApp Container起動用のsystemd unit
の作成 - ホストとのやりとりができるように
volume
を設定 - stage1上の
systemd-nspawn
を起動する -
systemd
が起動
stage1では具体的な処理を行います。
ディレクトリ上のstage1は実行エンジンOSのルートディレクトリにあたります。
現状実行エンジンのOSはCoreOSをベースしたものになっています。
(production_pxe_cpio.img)
順番は前後しますが、問題どうやってこのstage1
のCoreOSを起動するかです。
Systemd Ready なOSならばそのままsystemd-nspawn
を起動すれば良さそうですがRocketはUbuntuなどでも動作します。
どうやっているのでしょうか?
Rocketはld-linux-x86-64.so.2
経由で直接systemd-nspawn
を起動しています。
コマンドラインだと以下のような感じになります。
stage1/usr/lib/ld-linux-x86-64.so.2 stage1/usr/bin/systemd-nspawn --boot --register false --uuid=32c9578e-0f6d-45b4-9890-c396198dcef3 --directory=stage1 -- --default-standard-output=tty
stage1のディレクトリをルートとし、コンテナを立ち上げOSを起動します。
boot
フラグを指定しているのでOS内のinitを自動で検出し、起動します。
OS部はCoreOSベースなのでinit
部はsystemd
になります。
machinectl
で管理する必要がないのでregister
はfalse
です。
Log だと以下の部分がstage1の部分になります。
2014/12/05 11:49:45 Pivoting to filesystem /var/lib/rkt/containers/334f58db-4fbc-47d6-b48d-8228df401152
2014/12/05 11:49:45 Execing stage1/init
Spawning container stage1 on /var/lib/rkt/containers/334f58db-4fbc-47d6-b48d-8228df401152/stage1.
Press ^] three times within 1s to kill container.
Timezone Asia/Tokyo does not exist in container, not updating container timezone.
systemd 215 running in system mode. (-PAM -AUDIT -SELINUX +IMA -SYSVINIT +LIBCRYPTSETUP -GCRYPT -ACL -XZ +SECCOMP -APPARMOR)
Detected virtualization 'systemd-nspawn'.
Detected architecture 'x86-64'.
Welcome to Linux!
Initializing machine ID from container UUID.
[ OK ] Created slice -.slice.
[ OK ] Created slice system.slice.
Starting Graceful exit watcher...
[ OK ] Started Graceful exit watcher.
stage1/init はgoで実装されているのでソース見ることができます。
実際のstage1/initは rktバイナリ内にgo-bindata
埋め込まれています。
このstage1のOS内systemd
経由でApp Containerを起動します。
前後しましたがApp Container→systemd unitへ変換し、stage1のinitで起動できるようにコピーしておき、起動させます。
App Containerのsystemd unitにはRootDirectory
を設定してあります。
RootDirectory
にはstage2のルート、App Containerのrootfsが指定します。
RootDirectory
を設定するとchrootした状態でserviceが起動します。
これでApp Containerのルートでコンテナが起動できるわけです。
stage2
stage2はApp Containerの起動です。
stage1で説明したとおりsystemd serviceとして起動します。
Logで見ると以下の部分になります。
Starting coreos.com/etcd...
[ OK ] Started coreos.com/etcd.
[ OK ] Reached target Rocket apps target.
と簡単に起動までの流れを書いてみました。
Rocketの利点
Rocketは起動までの流れを見る限り既存の技術を組み合わせてコンテナを実行させています。
(コードの行数は7000行もありません)
つまりRokcetはいろいろなところをプラガブルに変更できる設計になっているということです。
Dockerは全て自前で実現しているため、何か変更を入れるにしても複雑で、影響を考えたりしなければいけません。
コンテナの作成もDockerのものも流用できますし、自前で作成することできます。
まだオーケストレーションなどの機能やセキュリティなどはこれからになりますが今後に期待したいと思います。
参考: Dockerを使わない場合
fedoraのシンプルなコンテナの作成
$ yum -y --releasever=19 --nogpg --installroot=/srv/mycontainer --disablerepo='*' --enablerepo=fedora install systemd passwd yum fedora-release vim-minimal
debianコンテナ
$ debootstrap --arch=amd64 unstable ~/debian-tree/
参考: systemd
http://www.freedesktop.org/software/systemd/man/systemd-nspawn.html
http://www.freedesktop.org/software/systemd/man/systemd.service.html
http://www.freedesktop.org/software/systemd/man/systemd.exec.html