LXD を試してみた
- 公式ページに簡単なクライアントプログラムの使い方が載りました (2015-02-27 更新)
LXD 0.1 がリリースされましたので LXD を試してみました。
こちらも参考に。ただし、現時点では以下とは少しコマンドが違うようです。
Plamo 5.3 で試しています (kernel は独自ビルドの 3.19)。go コマンドはインストール済み。
構築
lxd/README.md at master · lxc/lxd · GitHub の通りです。
$ mkdir -p ~/go $ export GOPATH=~/go $ go get github.com/lxc/lxd $ cd $GOPATH/src/github.com/lxc/lxd $ go get -v -d ./... $ make
これで ~/go/bin 以下にコマンドができました。
$ ls ~/go/bin fuidshift* lxc* lxd*
デーモン起動
これも書いてある通り。
$ sudo mkdir -p /var/lib/lxd $ sudo chown karma:users /var/lib/lxd
subuid, subgid は設定済みです
$ cat /etc/subuid karma:100000:65536 $ cat /etc/subgid karma:100000:65536
とりあえず verbose モードで起動してみました。
$ ~/go/bin/lxd --help Usage: lxd [options] Options: --debug (= false) Enables debug mode. --group (= "") Group which owns the shared socket --help (= false) Print this help message. --tcp (= "") TCP address <addr:port> to listen on in addition to the unix socket (e.g., 127.0.0.1:8443) -v (= false) Enables verbose mode. --version (= false) Print LXD's version number and exit.
非特権コンテナのようですから、Plamo の場合、lxd コマンドを動かすシェルを読み書きできる cgroup に登録しないといけません(Ubuntuだとsystemd-logind辺りが作ったグループがあるのでそれを使いますのでこれは不要)。その後おもむろに lxd 起動
$ for d in /sys/fs/cgroup/* > do > echo $$ > $d/karma/tasks > done $ ~/go/bin/lxd -v
コマンド
$ cd ~/go/bin $ ./lxc help Usage: lxc [subcommand] [options] Available commands: config - Manage configuration. delete - lxc delete <resource> exec - exec specified command in a container. file - Manage files on a container. finger - Fingers the lxd instance to check if it is up and working. help - Presents details on how to use lxd. list - Lists the available resources. remote - Manage remote lxc servers. restart - Changes a containers state to restart. snapshot - Create a read-only snapshot of a container. start - Changes a containers state to start. stop - Changes a containers state to stop. version - Prints the version number of lxd.
コンテナ作成
イメージを勝手に落としてきてコンテナ作ります。help に init がないよw
$ ./lxc init ubuntu test01 $ ./lxc list test01
コンテナ起動
特にひねりはありません。素直に start。
$ ./lxc start test01 $
コンテナの状態確認
特に何もなく起動しているようですが、起動している様子を表示することができません ^^;
$ ./lxc info test01 error: unknown command: info :(snip)
プロセスを見てみると
$ pstree -p :(snip) | |-bash(24780)---lxd(17197)-+-{lxd}(17198) | | |-{lxd}(17199) | | |-{lxd}(17202) | | `-{lxd}(17203) :(snip) |-lxd(17207)---init(17218)-+-cron(18639) | |-getty(18626) | |-getty(18628) | |-getty(18629) | |-getty(18670) | |-getty(18673) | |-rsyslogd(17673)-+-{rsyslogd}(17684) | | `-{rsyslogd}(17685) | |-systemd-udevd(17564) | |-upstart-file-br(17670) | |-upstart-socket-(17669) | `-upstart-udev-br(17540)
確かに Plamo の上で Ubuntu が起動しているようです。
試してみると lxc のコマンドが使えそうです。
$ lxc-ls -P /var/lib/lxd/lxc -f NAME STATE IPV4 IPV6 GROUPS AUTOSTART ---------------------------------------------- test01 RUNNING - - - NO $ lxc-info -P /var/lib/lxd/lxc -n test01 Name: test01 State: RUNNING PID: 17218 CPU use: 1.17 seconds BlkIO use: 248.00 KiB Memory use: 3.94 MiB KMem use: 0 bytes
コマンド実行
$ ./lxc exec test01 -- /bin/uname -a Linux test01 3.19.0-plamo64-karma #2 SMP PREEMPT Mon Feb 9 16:13:40 JST 2015 x86_64 x86_64 x86_64 GNU/Linux
lxc-attach コマンドも使えます。
$ lxc-attach -P /var/lib/lxd/lxc -n test01 -- uname -a Linux test01 3.19.0-plamo64-karma #2 SMP PREEMPT Mon Feb 9 16:13:40 JST 2015 x86_64 x86_64 x86_64 GNU/Linux
コンテナの停止
普通にできます。
$ ./lxc stop test01 $ lxc-ls -P /var/lib/lxd/lxc -fNAME STATE IPV4 IPV6 GROUPS AUTOSTART ---------------------------------------------- test01 STOPPED - - - NO
(続く)
2014年振り返りコンテナ編
今年は2014年を振り返るみたいなブログやらFacebookの書き込みをよく見かける気がするので私も。もう今年も残り少ないので手短に。
Docker が春くらいからそれまで以上に盛り上がりはじめて、そこら中のベンダーがサポートを表明してましたね。その盛り上がりのおかげというわけでもないのですが、gihyo.jp で コンテナとLXCに関する連載 をさせていただきました。つたない文章ですが、それなりにご覧いただいていたようでありがとうございました。
それと第2回 以降、急激に参加人数の増えた コンテナ型仮想化の情報交換会 は、かなり私の趣味に走った勉強会にも関わらず今年も毎回色々な方にお話いただき、多数の方に参加いただき、色々な方と知り合うことができ、色々な勉強ができました。ありがとうございました。
この勉強会をきっかけに他の勉強会に呼んでいただいて登壇できたのも良い経験でした。
どちらかというと人見知りで初めての方とお話するのが苦手な私でも、勉強会主催とか登壇者となるとたくさんの方が話しかけて下さるので、世界も広がったような気がします。
私はコンテナやcgroupなどに関して広く知られて盛り上がる前から調べていたので、今色々偉そうに話したり書いたりできていますが、実際持っている知識はたいしたことがありません。コンテナが盛り上がっている今では、私より頭の良い色々知識が豊富な方が私の興味のある分野について色々なところでお書きになったりお話になったりするようになっていますし、今後はますますそうなっていくでしょうから、今後はそれを勉強させてもらう方が多くなるような気がしています。それはそれで楽しみだなあ、と思ってます。
今年一年どうもありがとうございました。来年もよろしくおねがいたします!!良い年をお迎えください!!
コンテナの歴史と Linux カーネルのコンテナ関連機能についての割とどうでも良い愚痴
この記事は Linux Advent Calendar 2014 の 18 日目のエントリとして書いています。
Docker が盛り上がって、Docker が使ってる「コンテナ」という技術が盛り上がって、Doker の解説がそこら中にあふれるようになったので「Docker? そんなの FreeBSD が jail でずっと前からできてたぞ」というちょっと的外れな発言を見かけることは少なくなりました。一方でコンテナの歴史を追って見る的な企画をみかけるようになりました。
みかけた歴史の解説でいくつか「ちょっと違うやろー」というものを見かけたのでここで愚痴ります。
コンテナの歴史として大体書かれているのが
1979 年 | chroot(2) システムコールの Version 7 Unix への導入 |
1983 年 | chroot(2) システムコールの 4.2BSD への導入 |
2000 年 | FreeBSD jail が FreeBSD 4.0 に導入 |
2005 年 | Solaris Containers 登場 |
2008 年 | Cgroup が Linux カーネル 2.6.24 にマージ |
2014 年 | Docker 1.0 リリース |
というものです。
もちろん「chroot → FreeBSD jail → Linux のコンテナ」という大きな流れを否定するつもりはありません。しかし、前述の年表のようなものにはかなり違和感を覚えます。
しかも私が見たいくつかの記事では「FreeBSD jail (相当|と同様) の機能として cgroup が実装」「ここで初めてLinuxにコンテナの機能が実装された」というような説明がなされています。つまり「FreeBSD jail≒Linux Cgroup≒Linuxカーネルに実装されたコンテナ」というわけですな。これはおかしい!!
どこが!? そう、LXCで学ぶコンテナ入門 -軽量仮想化環境を実現する技術:連載|gihyo.jp … 技術評論社 を読んでいただいている方はおわかりいただけるのではないでしょうか!? (宣伝)
Linux カーネルに実装されているコンテナ関連の機能
Linux カーネルに実装されているコンテナ関連の機能の主要なものは大きく 2 つあると言えるでしょう。もちろん Cgroup はその一つです。しかし Cgroup だけではコンテナは実現できません。
ここでその 2 つの機能のおさらいです。
- Cgroup
- コンピュータに備わる物理的なリソース(cpu, memory, etc)を隔離/制限するための機能
- Namespace(名前空間)
- カーネル/OSが扱うリソース(ホスト名、ネットワークスタック、PID、etc)を隔離するための機能
そう、この 2 つです。なんで Cgroup だけが取り上げられるん? (もちろんこの2つの他にも使っている技術は様々あります)
そもそも前述の流れだと FreeBSD jail からの流れになっており、FreeBSD jail 相当の機能として Cgroup となっています。FreeBSD jail ってディレクトリツリーとかプロセスとかネットワークスタックとか (これは Vimage か) の隔離ですよね?
この流れからいくと取り上げるべきは Cgroup ではなく Namespace じゃないですか? 今の所 6 つある Namespace のうち、最初にカーネルにマージされたのは Mount Namespace で、なんと 2.4.19 でのマージです (2002 年)。*1
jail 相当とも言える PID Namespace が導入されたのは 2.6.24 で 2008 年なので、前述の年表で「Linuxのコンテナ機能がとりあえず実装されたとき」として 2008 年を取り上げるのは問題ないと思いますが、jail に対応する機能としては Namespace を取り上げるべきなのです。
歴史を語るのは重要なんですが、ちゃんと機能を理解して書いてほしいなあというわりとどうでもよい愚痴でした。
ああ、Linux Advent Calendar 2014 の他のに比べて著しくレベル低いですね… (^^;)
docker の CPU 隔離性
某所で話題になってたので。3.17.1 kernel で試してます (Plamo Linux 5.2)
docker でも何でもなくて単に Linux kernel の cgroup がちゃんと動いてるかって話なんですが。:-)
(2014-10-29 追記) なんか docker ってキーワード入ってるからかわかりませんが、多数アクセスいただいていますね。CFS Throttle の機能自体はもう 3 年近く前に試してちゃんと動いていたテストそのままです。dockerを使って試してるか、直接 cgroup と普通のプロセスで試してるかの違い。gihyo.jp での連載でもそのまま載ってます :-)
- Linux 3.2 の CFS bandwidth control (2) - TenForwardの日記
- 第4回 Linuxカーネルのコンテナ機能[3] ─cgroupとは?(その2):LXCで学ぶコンテナ入門 -軽量仮想化環境を実現する技術|gihyo.jp … 技術評論社
cpu.shares
Linux cgroup の cpu サブシステムで cgroup 内のタスクが使用できる CPU 時間の相対比率が指定できます。これをそのまま使う形で "docker run" コマンドに "-c/--cpu-shares" というオプションがあります。cpu.shares にはデフォルトでは 1024 が入っています。
実験したのですが、なぜか CPU 使いまくるコンテナを 2 つ起動すると cpuset を使ってコア指定していても別のコアに逃げてしまうので (Why?? 後述のようにコンテナ起動しても、別のコアを使ってCPU 100%いきます)、とりあえずコア 1 個だけにして実験しました。(何か見落としてる?? 誰か教えて)
# echo 0 > /sys/devices/system/cpu/cpu0/online # echo 0 > /sys/devices/system/cpu/cpu1/online # echo 0 > /sys/devices/system/cpu/cpu3/online
コンテナを 2 つ起動します。1024:100 としています。(2 以外の CPU は無効にしてるので --cpuset=2 の指定は意味ないですが)
$ docker run -d --cpu-shares=1024 --cpuset=2 -d ubuntu sh -c "while :; do true; done" 896d40f8c9996ccf44f80431ef1f23cfde8479c5852437126338ef75abfd104f $ docker run -d --cpu-shares=100 --cpuset=2 -d ubuntu sh -c "while :; do true; done" e6f843b52a607eb66dbe3c65236327ce98c7149cfd3e73284394d98141b06193
top コマンドで見ると、まあ大体そんな感じの比率になってますね。
top - 17:01:51 up 23 min, 5 users, load average: 1.80, 1.40, 1.08 Tasks: 252 total, 9 running, 243 sleeping, 0 stopped, 0 zombie %Cpu2 : 99.7 us, 0.3 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem: 7975984 total, 1601860 used, 6374124 free, 91860 buffers KiB Swap: 7823648 total, 0 used, 7823648 free, 626368 cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 5953 root 20 0 4452 692 608 R 89.80 0.009 0:46.53 sh 5980 root 20 0 4452 840 756 R 8.980 0.011 0:03.98 sh
CFS throttling
3.2 カーネルからサポートされている、単位時間あたりの CPU 割り当て時間を指定できます。これは docker run コマンドからは直接は指定できないので、cgroupfs のファイルに直接書き込む必要があります。
- まずは 2 つコンテナを起動します。CPU を無駄に消費するようにします。
$ docker run -d ubuntu sh -c "while :; do true; done"
6c6e705f632b7030e9ab2b3414cc3ec7e9654a74d4deaadc42e3777ae22413b1
$ docker run -d ubuntu sh -c "while :; do true; done"
0add197884a6aee7132ce6647982bfa019b4cf6b85017a10173180a50547293a- top コマンドで確認します。それぞれ 100% 使っています。
top - 15:16:59 up 1:19, 7 users, load average: 1.17, 0.84, 0.67
Tasks: 254 total, 3 running, 251 sleeping, 0 stopped, 0 zombie
%Cpu(s): 52.4 us, 0.2 sy, 0.0 ni, 47.1 id, 0.2 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem: 7975980 total, 3295148 used, 4680832 free, 370868 buffers
KiB Swap: 7823648 total, 0 used, 7823648 free, 1047416 cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
10064 root 20 0 4452 688 604 R 99.99 0.009 0:34.85 sh
10089 root 20 0 4452 768 688 R 99.99 0.010 0:33.61 sh
- top コマンドで確認します。それぞれ 100% 使っています。
- CFS throttling の単位時間は 100ms です。それぞれのコンテナに 10ms、5ms を割り当てます。
$ cat /sys/fs/cgroup/cpu/docker/cpu.cfs_period_us (単位時間を確認)
100000
$ echo 10000 | sudo tee /sys/fs/cgroup/cpu/docker/0add197884a6aee7132ce6647982bfa019b4cf6b85017a10173180a50547293a/cpu.cfs_quota_us (10msを設定)
10000
$ echo 5000 | sudo tee /sys/fs/cgroup/cpu/docker/6c6e705f632b7030e9ab2b3414cc3ec7e9654a74d4deaadc42e3777ae22413b1/cpu.cfs_quota_us (5msを設定)
5000- top コマンドで確認します。それぞれ大体 10% と 5% になってます。
top - 15:23:03 up 1:25, 7 users, load average: 1.51, 1.63, 1.12
Tasks: 252 total, 3 running, 249 sleeping, 0 stopped, 0 zombie
%Cpu(s): 8.1 us, 1.1 sy, 0.0 ni, 90.7 id, 0.0 wa, 0.0 hi, 0.1 si, 0.0 st
KiB Mem: 7975980 total, 3344872 used, 4631108 free, 372016 buffers
KiB Swap: 7823648 total, 0 used, 7823648 free, 1054536 cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
4705 karma 20 0 1852500 733552 111680 S 16.62 9.197 14:06.92 firefox
10089 root 20 0 4452 768 688 R 9.974 0.010 5:11.81 sh
10064 root 20 0 4452 688 604 R 4.987 0.009 6:10.79 sh
- top コマンドで確認します。それぞれ大体 10% と 5% になってます。
lxc-checkpoint で CRIU を使って LXC コンテナの checkpoint/restore 処理
CRIUを最後に試したのは昨年11月でした。
いつの間にやらバージョンも 1.3 とかで進化しています。でも LXC できちんと動かないよという話だったので動向だけ見守っていました。まあ、前回でもそれなりには動いていましたが。最近、Add support for checkpoint and restore via CRIU · lxc/lxc@735f2c6 · GitHub で LXC が CRIU 対応し lxc-checkpoint というコマンドが新しく実装されました。
早速触ってみました。試したのは以下の環境です。プレーンな環境なのでコンテナに限らず新しいモノを触るのに最適ですよ! > Plamo Linux
カーネルで必要な config があるので、そのあたり不足していればカーネル作りなおしてください。
# criu check --ms Warn (tun.c:55): Skipping tun support check Warn (timerfd.c:44): timerfd: Skipping timerfd support check Warn (cr-check.c:260): Skipping mnt_id support check Looks good.
コンテナの作成と設定ファイル
- ホストで fuse モジュールが読み込まれているとダメなのでロードされないようにしました。
- まずは通常通りコンテナを作成します。Ubuntu Trusty (amd64) のコンテナにしました。私の環境は /var/lib/lxc は btrfs なので一応 btrfs を指定しています。
# lxc-create -n ct01 -t download -B btrfs -- -d ubuntu -r trusty -a amd64
- まずはコンテナを起動させて、動作確認のためにコンテナに nginx をインストールしておきました。
- 設定ファイルを書き換えます。デフォルトだと ubuntu.common.conf と common.conf を include しているので include をやめて全部直に書きます。
# cd /var/lib/lxc/ct01
ここでのキモは
# mv config config.tmp
# cp /usr/share/lxc/config/common.conf > config
# cat /usr/share/lxc/config/ubuntu.common.conf >> config
# cat config.tmp >> configlxc.tty = 0
です。この 3 つは LXC - CRIU で指定されている設定で、lxc-checkpoint でも criu コマンドを実行する前にチェックされます。必要な設定がないと LXC のチェックでひっかかります。
lxc.console = none
lxc.cgroup.devices.deny = c 5:1 rwm# lxc-checkpoint -v -n ct01 -s -D /root/criu
lxc_container: couldn't find devices.deny = c 5:1 rwm
Checkpointing ct01 failed. - /sys 以下の bind mount があるとダメだったのでコメントアウトしました。
最終的にこんな設定ファイルになってます。
lxc.tty = 0 lxc.console = none lxc.cgroup.devices.deny = c 5:1 rwm lxc.pts = 1024 lxc.cap.drop = mac_admin mac_override sys_time sys_module lxc.pivotdir = lxc_putold lxc.hook.clone = /usr/share/lxc/hooks/clonehostname lxc.cgroup.devices.deny = a lxc.cgroup.devices.allow = c *:* m lxc.cgroup.devices.allow = b *:* m lxc.cgroup.devices.allow = c 1:3 rwm lxc.cgroup.devices.allow = c 1:5 rwm lxc.cgroup.devices.allow = c 1:7 rwm lxc.cgroup.devices.allow = c 5:0 rwm lxc.cgroup.devices.allow = c 5:2 rwm lxc.cgroup.devices.allow = c 1:8 rwm lxc.cgroup.devices.allow = c 1:9 rwm lxc.cgroup.devices.allow = c 136:* rwm lxc.seccomp = /usr/share/lxc/config/common.seccomp lxc.mount.entry = proc proc proc nodev,noexec,nosuid 0 0 lxc.mount.entry = sysfs sys sysfs defaults 0 0 lxc.mount.entry = /sys/fs/fuse/connections sys/fs/fuse/connections none bind,optional 0 0 #lxc.mount.entry = /sys/kernel/debug sys/kernel/debug none bind,optional 0 0 #lxc.mount.entry = /sys/kernel/security sys/kernel/security none bind,optional 0 0 lxc.mount.entry = /sys/fs/pstore sys/fs/pstore none bind,optional 0 0 lxc.cgroup.devices.allow = c 254:0 rm lxc.cgroup.devices.allow = c 10:229 rwm lxc.cgroup.devices.allow = c 10:200 rwm lxc.cgroup.devices.allow = c 10:228 rwm lxc.cgroup.devices.allow = c 10:232 rwm lxc.arch = x86_64 lxc.rootfs = /var/lib/lxc/ct01/rootfs lxc.utsname = ct01 lxc.network.type=veth lxc.network.link=lxcbr0 lxc.network.flags=up
コンテナイメージ内
コンテナの rootfs 以下のファイルも少し調整します。
- udev は起動させないように、と CRIU ページにあったので /etc/init/udev.conf を削除
# rm /var/lib/lxc/ct01/rootfs/etc/init/udev.conf
- console, tty は無効にしてますので、その関係も一応 /etc/init 以下から削除しました。まあこれは削除しなくてもエラーで起動しないだけかも。
checkpoint 処理
ではコンテナを起動させます。きちんと動作しています。
# lxc-start -n ct01 # lxc-ls --fancy NAME STATE IPV4 IPV6 GROUPS AUTOSTART ---------------------------------------------------- ct01 RUNNING 10.0.100.119 - - NO
nginx を入れたのでその動作確認。
# curl -I http://10.0.100.119/ HTTP/1.1 200 OK Server: nginx/1.4.6 (Ubuntu) Date: Fri, 29 Aug 2014 09:00:59 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Tue, 04 Mar 2014 11:46:45 GMT Connection: keep-alive ETag: "5315bd25-264" Accept-Ranges: bytes
lxc-checkpoint を実行します。lxc-checkpoint は必要なチェックや準備をしてからインストールされている criu コマンドを実行します。criu をデーモンで動かしておく必要はありません。
- 指定オプション
- -v : criu のログの verbose モード指定
- -s : checkpoint が終わったらコンテナを停止させる
- -D : dump ファイルの置き場所
# lxc-checkpoint -v -n ct01 -s -D /root/criu # lxc-ls --fancy NAME STATE IPV4 IPV6 GROUPS AUTOSTART -------------------------------------------- ct01 STOPPED - - - NO
エラーなく終わると黙って lxc-checkpoint は終了します。-s を指定したのでコンテナも停止しています。
# curl -I http://10.0.100.119/ ^C
コンテナが止まってるから当然 nginx とか反応しません。
ダンプファイル指定した場所にたくさんの dump ファイルができています。
# ls /root/criu/ bridge0 fs-151.img pagemap-257.img cgroup.img fs-248.img pagemap-289.img core-1.img fs-254.img pagemap-373.img core-141.img fs-257.img pagemap-374.img core-151.img fs-289.img pagemap-389.img core-248.img fs-373.img pagemap-390.img core-249.img fs-374.img pagemap-391.img core-250.img fs-389.img pagemap-393.img core-252.img fs-390.img pagemap-394.img core-254.img fs-391.img pagemap-566.img core-257.img fs-393.img pagemap-568.img core-289.img fs-394.img pagemap-570.img core-373.img fs-566.img pagemap-572.img core-374.img fs-568.img pagemap-574.img core-389.img fs-570.img pagemap-shmem-60541.img : (snip)
たくさんすぎるので省略。
restore 処理
では dump ファイルから restore 処理を行って、コンテナを起動させましょう。
- 指定したオプション
- -r : restore 処理を行う
- -d : restore 後、コンテナをデーモンモードで起動
# lxc-checkpoint -v -n ct01 -r -d -D /root/criu # lxc-ls --fancy NAME STATE IPV4 IPV6 GROUPS AUTOSTART ---------------------------------------------------- ct01 RUNNING 10.0.100.119 - - NO
起動しました。nginx の起動を確認してみましょう。
# curl -I http://10.0.100.119/ HTTP/1.1 200 OK Server: nginx/1.4.6 (Ubuntu) Date: Fri, 29 Aug 2014 09:02:21 GMT Content-Type: text/html Content-Length: 612 Last-Modified: Tue, 04 Mar 2014 11:46:45 GMT Connection: keep-alive ETag: "5315bd25-264" Accept-Ranges: bytes
問題なく起動しており、コンテナ内のプロセスも無事復帰しているのがわかります。
チェックポイント機能として働いているかまではチェックしてないけど、とりあえずこんなところで。
(続くかも)