前回 Docker のイメージから ACI を作り、 Rocket で動かすということをやってみた。
今回は仕様を見ながらイメージを作ってみる。
appc の仕様はここにまとまっている。(リンクはこれを書いてる時点で見てたバージョン。v0.4.1)
https://github.com/appc/spec/blob/bf255efb12f2455c0f6eb81932458abc0ad80413/SPEC.md
App Container Image の部分を中心に見る。
ACI のファイルフォーマットのことをイメージアーカイブと呼んでいるらしい。 その構造について決まっていることはいくつかあって、
- 拡張子は .aci じゃないといけない
- 中身に重複がない tar ファイルフォーマットのファイルじゃないといけない
- トップレベルに manifest というファイルと rootfs というディレクトリを持っていないといけない
- イメージに入れるファイルは元々の属性を全部維持していないといけない
- gzip, bzip2, xz のどれかで圧縮してもOK
- AES対称暗号(?)で暗号化してもいい
- PGPで署名されるべき
- 署名の拡張子は .aci.asc
という感じ
ここによれば、最も単純な ACI は、単なる tar ファイルで、最低限 manifest と rootfs があればいいことがわかる。
今回はその最も単純な方法で、 nc を使った簡易ウェブサーバが動くか試してみる。
こういうシェルスクリプトを動かしたい。
#!/bin/sh while true; do ( echo "HTTP/1.0 200 Ok"; echo; echo "Hello World" ) | nc -l 8080; [ $? != 0 ] && break; done
manifest ファイルはちょっとめんどいので、まずは入れ物のディレクトリを作る
mkdir rootfs
コンテナには必要なものを全部入れる必要がある。
ここでいうとこのスクリプトを動かす sh と、中で使っている nc が少なくとも必要になってくる。
というわけでまず rootfs に bin のディレクトリを作る。
で、そこに sh と nc を入れる
mkdir rootfs/bin cp -a /bin/sh rootfs/bin/sh cp -a /bin/dash rootfs/bin/dash cp -a /bin/sh rootfs/bin/sh cp -a /bin/nc.openbsd rootfs/bin/nc
最初ここでシンボリックリンクの /bin/sh と /bin/nc しかコピーしてなくて、リンク先がなくて動かないという凡ミスを犯したw
nc は今回試した環境では↓こうなってたので、リンク先を名前変えて突っ込む
vagrant@vagrant-ubuntu-trusty-64:~$ ls -la /bin/nc lrwxrwxrwx 1 root root 20 Jan 30 18:42 /bin/nc -> /etc/alternatives/nc vagrant@vagrant-ubuntu-trusty-64:~$ ls -la /etc/alternatives/nc lrwxrwxrwx 1 root root 15 Jan 30 18:42 /etc/alternatives/nc -> /bin/nc.openbsd
次に、実行するファイルが使うライブラリもないといけない。
vagrant@vagrant-ubuntu-trusty-64:~/test-container$ ldd rootfs/bin/sh linux-vdso.so.1 => (0x00007fff059e6000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb2255f9000) /lib64/ld-linux-x86-64.so.2 (0x00007fb225be8000) vagrant@vagrant-ubuntu-trusty-64:~/test-container$ ldd rootfs/bin/nc linux-vdso.so.1 => (0x00007fffd20f4000) libbsd.so.0 => /lib/x86_64-linux-gnu/libbsd.so.0 (0x00007fec3a421000) libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007fec3a206000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fec39e3f000) /lib64/ld-linux-x86-64.so.2 (0x00007fec3a639000)
これらが全部必要なので、rootfs 以下の対応する場所にこれらをコピーしておく。
で、最後に動かしたいシェルファイルを適当な場所に置く。
今回は /usr/bin に置く。
やってみて、ディレクトリは以下のようになった
vagrant@vagrant-ubuntu-trusty-64:~/test-container$ tree . . ├── manifest └── rootfs ├── bin │ ├── dash │ ├── nc │ └── sh -> dash ├── lib │ └── x86_64-linux-gnu │ ├── ld-2.19.so │ ├── libbsd.so.0 -> libbsd.so.0.6.0 │ ├── libbsd.so.0.6.0 │ ├── libc-2.19.so │ ├── libc.so.6 -> libc-2.19.so │ ├── libresolv-2.19.so │ └── libresolv.so.2 -> libresolv-2.19.so ├── lib64 │ └── ld-linux-x86-64.so.2 -> /lib/x86_64-linux-gnu/ld-2.19.so └── usr └── bin └── tinyweb 7 directories, 13 files
次に manifest を作っていく
manifest のスキーマは以下にまとまっている。 https://github.com/appc/spec/blob/bf255efb12f2455c0f6eb81932458abc0ad80413/SPEC.md#manifest-schemas
具体的には Go のコード読んだほうがいいかも https://github.com/appc/spec/blob/bf255efb12f2455c0f6eb81932458abc0ad80413/schema/image.go
SPEC.md にある例をコピーして、必要ないところは消しつつ作ってみる
type ImageManifest struct { ACKind types.ACKind `json:"acKind"` ACVersion types.SemVer `json:"acVersion"` Name types.ACName `json:"name"` Labels types.Labels `json:"labels,omitempty"` App *types.App `json:"app,omitempty"` Annotations types.Annotations `json:"annotations,omitempty"` Dependencies types.Dependencies `json:"dependencies,omitempty"` PathWhitelist []string `json:"pathWhitelist,omitempty"` }
ここで omitempty になるものはなくてもいいはず。
なので acKing, acVersion, name は書く。
labels はそのまま残しておこう。
app はなくてもいいが、ないと思ったとおりに実行できないので書く。
exec にさきほど用意した /usr/bin/tinyweb を指定する。
その他は特に今回は不要なので空にしておく
docker と違ってデフォルトではホストのネットワークを使うので、特にポートをバインドとかは必要ない。
で、結果として以下のような感じになった
vagrant@vagrant-ubuntu-trusty-64:~/test-container$ cat manifest { "acKind": "ImageManifest", "acVersion": "0.4.1", "name": "test-container", "labels": [ { "name": "version", "value": "1.0.0" }, { "name": "arch", "value": "amd64" }, { "name": "os", "value": "linux" } ], "app": { "exec": [ "/usr/bin/tinyweb" ], "user": "0", "group": "0", "eventHandlers": [], "workingDirectory": "", "environment": [ ], "isolators": [ ], "mountPoints": [ ], "ports": [ ] }, "dependencies": [ ], "annotations": [ { "name": "authors", "value": "totem3 <totem3@github>" }, { "name": "documentation", "value": "https://github.com/totem3/containers" }, { "name": "homepage", "value": "https://github.com/totem3/containers" } ] }
これで作ってみよう。
vagrant@vagrant-ubuntu-trusty-64:~/test-container$ tar cvf test-container.aci manifest rootfs manifest rootfs/ rootfs/lib/ rootfs/lib/x86_64-linux-gnu/ rootfs/lib/x86_64-linux-gnu/libresolv-2.19.so rootfs/lib/x86_64-linux-gnu/libresolv.so.2 rootfs/lib/x86_64-linux-gnu/libc.so.6 rootfs/lib/x86_64-linux-gnu/libbsd.so.0.6.0 rootfs/lib/x86_64-linux-gnu/libc-2.19.so rootfs/lib/x86_64-linux-gnu/libbsd.so.0 rootfs/lib/x86_64-linux-gnu/ld-2.19.so rootfs/lib64/ rootfs/lib64/ld-linux-x86-64.so.2 rootfs/usr/ rootfs/usr/bin/ rootfs/usr/bin/tinyweb rootfs/bin/ rootfs/bin/sh rootfs/bin/nc rootfs/bin/dash
done
動かしてみよう。
rkt で動かす
vagrant@vagrant-ubuntu-trusty-64:~/test-container$ sudo rkt run test-container.aci /etc/localtime is not a symlink, not updating container timezone.
動いた。 /etc/localtime がないと言われているが、これはとりあえず置いておこう
別のターミナルから8080番ポートを叩いてみる
vagrant@vagrant-ubuntu-trusty-64:~$ curl localhost:8080 Hello World
返ってきた。コンテナ側にもリクエストを受け付けた形跡がある
vagrant@vagrant-ubuntu-trusty-64:~/test-container$ sudo rkt run test-container.aci /etc/localtime is not a symlink, not updating container timezone. GET / HTTP/1.1 User-Agent: curl/7.35.0 Host: localhost:8080 Accept: */*
うん、動いていそう。
プロセスツリーはこうなってる。(このうえはsshとかshell)
root 9906 0.0 0.4 65736 2128 pts/0 S+ 21:13 0:00 |\_ sudo rkt run test-container.aci root 9907 28.0 0.2 27808 1216 pts/0 S+ 21:13 0:01 | \_ stage1/rootfs/usr/lib/ld-linux-x86-64.so.2 stage1/rootfs/usr/bin/systemd-nspawn --boot --register false --quiet --uuid=9a78fc07-b3cd-4fd3-8f84-749167e27f8e --directory=stage1/rootfs -- -- root 9912 0.0 0.4 22568 2224 ? Ss 21:13 0:00 | \_ /usr/lib/systemd/systemd --default-standard-output=tty --log-target=null --show-status=0 root 9913 0.0 0.0 4108 384 ? Ss 21:13 0:00 | \_ /usr/bin/sleep 9999999999d root 9915 0.0 0.1 4444 660 ? Ss 21:13 0:00 | \_ /bin/sh /usr/bin/tinyweb root 9917 0.0 0.0 9128 432 ? S 21:13 0:00 | \_ nc -l 8080
ランタイムの話はまた今度やろう
ちなみにコンテナの終了は ^] (ctrl+]) を3回