ローファイ日記

出てくるコード片、ぼくが書いたものは断りがない場合 MIT License としています http://udzura.mit-license.org/

haconiwaの室内楽 - Re: 自作Linuxコンテナの時代

haconiwa という、いわゆるLinuxコンテナに関する様々な技術を組み合わせて、自分のためのコンテナを作ることができるRuby製のツールと、そのDSLを作った。ひとまずこれぐらいはやりたいということができていそうなので、バージョン 0.2.0 としてリリースした。

github.com

使い方

ほぼREADMEの日本語版。

前提として、以下のライブラリとコマンドが必要になるので入れておいて欲しい。

  • libcap (libcap.so.2FFI 経由で使う)
  • nsenter (yum install util-linux とかそういう感じで入れる)

ひとまず動かしたい場合は、rbenvなどが整った環境で、gemとして入れるのがいいと思う。多分Ruby 2.0 以降で動く気がする。

$ gem install haconiwa
$ rbenv rehash

そして、現在のhaconiwaはファイルシステムに関しては何も機能がないので、別のツール、例えば debootstraplxc-create などで準備しておく。

$ lxc-create -t centos -n sample --dir /tmp/udzura

で、ひとまず以下のようなRubyDSLファイルを 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コンテナの時代」を読んでめっちゃ影響されたこと、先日のコンテナ勉強会@福岡に参加して改めて自分の中でコンテナ技術が盛り上がったことが大きい。

blog.yuuk.io

ct-study.connpass.com

実際、業務でもDrone経由でDockerを運用したり、 Sqale というサービスを見ていてLXCをいじったりして、コンテナ的なことが欲しいけれど、実際に必要なことは例えばリソースを制限したり、ファイルシステムを隔離したり、などと一部分だけだったりとか、いろいろ思うところがあったので、この手の技術を「簡単に組み合わせること」にフォーカスしたコンテナツールがあると良いのでは、と思って作ってみた。

例えば、 matsumotoryさんの rcon のように使ったり、たくさんのコンテナで同じrootfsをマウントして共有しまくったり、などといったニッチな要件を比較的容易にできる(ようにしたい)。

コンテナ周りのお話は面白い。でもDockerが出現してからは「Dockerをこう使いました」みたいな話が多いような印象があって、それはそれで非常に興味深いし貴重なんだけれど、一方でコンテナを支える技術要素を見てみると、それぞれは非常にシンプルで、綺麗に組み合わせられるようになっている。

クリシェ的な表現となってしまうが、「UNIXの哲学」的である。

ということで、この界隈は、Docker的な「全部入り」の使い方のみでなく、いろいろな可能性があるような気がしている。haconiwaの開発を通して改めてその思いが強まった。

今後

正直な話、何度も「CのAPI直接叩きたいよ〜〜」と思ったので、この実装はこの実装として、mrubyで書き直そうかな?などと思ったり。現在、例えば別途nsenterコマンドがないとダメだったりするが、そういう依存も軽くしたい。

また、現在のCRubyは基本的にマルチスレッドで動作するので、namespace関連のシステムコールと相性が良くない。このお話はもう少しまとまったら書きます...。

setns(2) - Linux manual page

A process may not be reassociated with a new mount namespace if it is multithreaded.

などなど。そういう意味でもmrubyで書いた方が綺麗になりそう。

何より、さすがにこのコンテナで本番っぽいアプリを動かすのは安心感がないし、微妙な挙動も随所に見られるので、しばらく自作コンテナで遊びつつ地道に直していこうかな〜という感じ。

今の所、あくまでもPoCに過ぎないツールという扱いだけれど、おためしください。

最後に

haconiwa の中には container の con が入っています。箱庭自体は、僕の敬愛する変拍子系ローファイプログレバンド「箱庭の室内楽」から拝借しました。コンテナとかgemとかどうでもいいんで聞いてください。

www.youtube.com

開発にあたり、 capsh 、 libcontanier や nsenter の実装、そして @matsumoroty さん自身とそのソフトウェアからたくさんのアドバイス、ヒントをいただきました。この場を借りて感謝を。