haconiwa
という、いわゆるLinuxコンテナに関する様々な技術を組み合わせて、自分のためのコンテナを作ることができるRuby製のツールと、そのDSLを作った。ひとまずこれぐらいはやりたいということができていそうなので、バージョン 0.2.0 としてリリースした。
使い方
ほぼREADMEの日本語版。
前提として、以下のライブラリとコマンドが必要になるので入れておいて欲しい。
- libcap (
libcap.so.2
を FFI 経由で使う) - nsenter (
yum install util-linux
とかそういう感じで入れる)
ひとまず動かしたい場合は、rbenvなどが整った環境で、gemとして入れるのがいいと思う。多分Ruby 2.0 以降で動く気がする。
$ gem install haconiwa $ rbenv rehash
そして、現在のhaconiwaはファイルシステムに関しては何も機能がないので、別のツール、例えば debootstrap
や lxc-create
などで準備しておく。
$ lxc-create -t centos -n sample --dir /tmp/udzura
で、ひとまず以下のようなRubyのDSLファイルを new_haconiwa001.haco
とでもして保存する。
Haconiwa::Base.define do |config| config.name = "new-haconiwa001" # to be hostname config.cgroup["cpu.cfs_period_us"] = 100000 config.cgroup["cpu.cfs_quota_us"] = 30000 config.mount_independent_procfs config.chroot_to "/tmp/udzura" config.namespace.unshare "ipc" config.namespace.unshare "uts" config.namespace.unshare "mount" config.namespace.unshare "pid" config.capabilities.allow :all config.capabilities.drop "CAP_SYS_TIME" end
このコンテナを立ち上げるには以下のようにする。
$ haconiwa run new_haconiwa001.haco -- /bin/bash
[root@foobar hacotest]# haconiwa run example001.haco -- /bin/bash unshare(2) flag: 0xc020000 [root@new-haconiwa001 /]# New container: Name = new-haconiwa001, PID = 17782 [root@new-haconiwa001 /]# [root@new-haconiwa001 /]# ls bin boot dev etc home lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var [root@new-haconiwa001 /]# ps auxf USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.1 115384 2048 ? S 10:34 0:00 /bin/bash root 12 0.0 0.0 151028 1700 ? R+ 10:34 0:00 ps auxf [root@new-haconiwa001 /]# cat /etc/centos-release CentOS Linux release 7.2.1511 (Core) [root@new-haconiwa001 /]# exit exit Successfully exit container.
この環境は、普通にCentOS 7のマシンのように扱えるはず。yumコマンドも打てる。
あるいは、cgroupの制限が効いているので、CPUを使うような処理をしても利用率は30%以下に抑えられるだろうし、また、capabilityも落とされているので、例えばコンテナの中で date -s
を走らせようとしてもうまくいかなかったりする。
[root@new-haconiwa001 /]# date -s 10:00 date: cannot set date: Operation not permitted
コンテナで「initプロセス」として長時間動作するプロセスを立ち上げておいて、別のプロセスから以下のようにアタッチすることもできる。
[root@foobar hacotest]# haconiwa run example001.haco -- /bin/sleep 1000 unshare(2) flag: 0xc020000 New container: Name = new-haconiwa001, PID = 17975 ## 別プロセスから [root@foobar hacotest]# haconiwa attach example001.haco -- /bin/bash Attached to contanier: Runner PID = 17991 [root@new-haconiwa001 /]# ps auxf USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 3 0.0 0.0 113120 1184 ? S 10:50 0:00 /bin/bash /tmp/haconiwa-attacher-17977-1464864637.sh20160602-17977-wcpyet root 4 0.0 0.1 115384 1988 ? S 10:50 0:00 \_ /bin/bash root 13 0.0 0.0 151028 1704 ? R+ 10:50 0:00 \_ ps auxf root 1 0.0 0.0 107896 616 ? S+ 10:50 0:00 /bin/sleep 1000
詳細は、 examplesディレクトリ配下 、より詳しくはソースコードを見て欲しい。
また、このgemは、基本的にCentOS 7上で開発しているが、 Fukuoka.rb の有志で試して頂いたところ、Debian sidでも割と動いているようだ(Thanks @minimum2scp)。いろいろな環境で試して欲しいかも...。
なぜ作ったか?
「自作Linuxコンテナの時代」を読んでめっちゃ影響されたこと、先日のコンテナ勉強会@福岡に参加して改めて自分の中でコンテナ技術が盛り上がったことが大きい。
実際、業務でもDrone経由でDockerを運用したり、 Sqale というサービスを見ていてLXCをいじったりして、コンテナ的なことが欲しいけれど、実際に必要なことは例えばリソースを制限したり、ファイルシステムを隔離したり、などと一部分だけだったりとか、いろいろ思うところがあったので、この手の技術を「簡単に組み合わせること」にフォーカスしたコンテナツールがあると良いのでは、と思って作ってみた。
例えば、 matsumotoryさんの rcon のように使ったり、たくさんのコンテナで同じrootfsをマウントして共有しまくったり、などといったニッチな要件を比較的容易にできる(ようにしたい)。
コンテナ周りのお話は面白い。でもDockerが出現してからは「Dockerをこう使いました」みたいな話が多いような印象があって、それはそれで非常に興味深いし貴重なんだけれど、一方でコンテナを支える技術要素を見てみると、それぞれは非常にシンプルで、綺麗に組み合わせられるようになっている。
クリシェ的な表現となってしまうが、「UNIXの哲学」的である。
ということで、この界隈は、Docker的な「全部入り」の使い方のみでなく、いろいろな可能性があるような気がしている。haconiwaの開発を通して改めてその思いが強まった。
今後
正直な話、何度も「CのAPI直接叩きたいよ〜〜」と思ったので、この実装はこの実装として、mrubyで書き直そうかな?などと思ったり。現在、例えば別途nsenterコマンドがないとダメだったりするが、そういう依存も軽くしたい。
また、現在のCRubyは基本的にマルチスレッドで動作するので、namespace関連のシステムコールと相性が良くない。このお話はもう少しまとまったら書きます...。
A process may not be reassociated with a new mount namespace if it is multithreaded.
などなど。そういう意味でもmrubyで書いた方が綺麗になりそう。
何より、さすがにこのコンテナで本番っぽいアプリを動かすのは安心感がないし、微妙な挙動も随所に見られるので、しばらく自作コンテナで遊びつつ地道に直していこうかな〜という感じ。
今の所、あくまでもPoCに過ぎないツールという扱いだけれど、おためしください。
最後に
haconiwa
の中には container の con
が入っています。箱庭自体は、僕の敬愛する変拍子系ローファイプログレバンド「箱庭の室内楽」から拝借しました。コンテナとかgemとかどうでもいいんで聞いてください。
開発にあたり、 capsh 、 libcontanier や nsenter の実装、そして @matsumoroty さん自身とそのソフトウェアからたくさんのアドバイス、ヒントをいただきました。この場を借りて感謝を。