Help us understand the problem. What is going on with this article?

Haconiwa を改めて紹介する

More than 1 year has passed since last update.

OSS紹介 Advent Calendar 2017 にかこつけて、自作オーエスエスを紹介していくスタンス。ということで20日の記事です。

Haconiwaは、いわゆるLinuxコンテナランタイムです。コンテナといえばクジラっぽいロゴのやつが有名ですが、Haconiwaはmrubyを組み込んでおり、コンテナに関するLinuxカーネルの機能を自分で組み合わせて使える点、フック機構など様々なAPIにより自分自身を拡張できる点、に特徴があります。

リリースして RubyKaigi 2016 でおしゃべりしてから大体1年(雑...)経っているのですが、改めて紹介してみます。みるぞ!

インストール

手元にUbuntu Zestyの環境があるので雑にインストールします(Xenialならリポジトリ追加もできますがLTS以外は用意していなかった...)

$ wget --content-disposition https://packagecloud.io/udzura/haconiwa/packages/ubuntu/xenial/haconiwa_0.8.9-1_amd64.deb/download.deb
$ sudo apt install ./haconiwa_0.8.9-1_amd64.deb
$ haconiwa version
haconiwa: v0.8.9

今日(!!)リリースした0.8.9が最新です。

試しに動かす

Haconiwaの設定ファイル兼Ruby DSLを Hacofile と呼んでいます。[^1]: 一部でしか呼んでいない雰囲気があるので呼んでいきたい。

$ haconiwa new qiita.haco                                                                                                    
assign  new haconiwa name = haconiwa-9bdfc517                                                                                                     
assign  rootfs location = /var/lib/haconiwa/9bdfc517                                                                                              
create  qiita.haco

作られた qiita.haco は文法としては普通のRubyのスクリプトです。bootstrap/provisionのブロックを以下のように変更してみます。

qiita.haco
  config.bootstrap do |b|
    b.strategy = "debootstrap"
    b.variant = "minbase"
    b.debian_release = "stretch"
  end

  config.provision do |p|
    p.run_shell <<-SHELL
apt -y update
apt -y install procps iproute2 ruby
    SHELL
  end

この状態で sudo haconiwa create qiita.haco と打つと、DSLに沿ってコンテナのrootfsの作成とプロビジョニングをしてくれます。

なおこの設定の場合は、debootstrapコマンドを使うので事前インストールしておいてください。

screen-qiita.png

rootfsの作成が完了したらコンテナに入ってみます。

$ sudo haconiwa run qiita.haco -T -- /bin/bash
Create lock: #<Lockfile path=/var/lock/.haconiwa-9bdfc517.hacolock>
Container fork success and going to wait: pid=11736
root@haconiwa-9bdfc517:/# ps auxf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.3  18164  3180 ?        S    09:32   0:00 /bin/bash
root         2  0.0  0.2  36632  2836 ?        R+   09:32   0:00 ps auxf
root@haconiwa-9bdfc517:/#

PIDも 1 から開始しているし、コンテナですね。やった!

コンテナ機能を試す

コンテナの機能を「個別に」有効にして検証してみるということをします。

cgroup

以下のような設定を追記します。

  config.cgroup["cpu.cfs_period_us"] = 100000
  config.cgroup["cpu.cfs_quota_us"]  =  30000
  config.cgroup["pids.max"] = 128

この設定を入れてコンテナに入って、Rubyなどで無限にフィボナッチ数を計算させてみます。

$ sudo haconiwa run qiita.haco -T -- /bin/bash
Create lock: #<Lockfile path=/var/lock/.haconiwa-9bdfc517.hacolock>
Container fork success and going to wait: pid=11910
root@haconiwa-9bdfc517:/# ruby -e \
  'def fib(n);n<2?1:fib(n-2)+fib(n-1);end;loop{fib rand(32)}'

しかし、cgroupの制限が効いているので、 30000us/100000us の30%までしかCPU利用率が上がらないことがわかります。

スクリーンショット 2017-12-20 18.36.34.png

また、プロセス数の上限も制限をしているので、このコンテナでfork bomb攻撃(危ないのでコードの掲載はしません:( )を実行してみても、無事に攻撃が収まることがわかります。 pids.max の制限をしていない場合 ホストごと落ちる ので気をつけましょう。

## fork bomb コマンドを発行
...
bash: fork: Resource temporarily unavailable
bash: fork: Resource temporarily unavailable
bash: fork: Resource temporarily unavailable
bash: fork: Resource temporarily unavailable
bash: fork: Resource temporarily unavailable
bash: fork: Resource temporarily unavailable
bash: fork: Resource temporarily unavailable
bash: fork: Resource temporarily unavailable
bash: fork: Resource temporarily unavailable
bash: fork: Resource temporarily unavailable
bash: fork: Resource temporarily unavailable
bash: fork: Resource temporarily unavailable

root@haconiwa-9bdfc517:/# ps auxf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.3  18300  3316 ?        S    09:38   0:00 /bin/bash
root       828  0.0  0.2  36632  2904 ?        R+   09:40   0:00 ps auxf

seccomp

seccompも試せます。以下のようなDSLを書いて、またコンテナを立ち上げてみます。

  config.seccomp.filter(default: :allow) do |rule|
    rule.kill :mkdir
    rule.kill :fchownat
  end

すると、見た目は普通のbashセッションですが、このコンテナの中では、rootであるにもかかわらず mkdir の操作や chown の操作などが一切できなくなっていることがわかります。

root@haconiwa-9bdfc517:/# touch hoge.txt                                 
root@haconiwa-9bdfc517:/# chown www-data hoge.txt 
Bad system call
root@haconiwa-9bdfc517:/# mkdir /tmp/test
Bad system call

このように、Haconiwaでは特定のシステムコール呼び出しを制限するサンドボックス環境を作ることができ、そのホワイトリスト/ブラックリストをRubyで記述可能です。

ネットワーク機能

今日のリリースで入った機能です。ブリッジとveth/network namespaceを用いいてコンテナに仮想的なネットワークを割り振ることができます。

最初にブリッジが必要なので、以下のコマンドで生成しましょう。

$ sudo haconiwa init --bridge --bridge-ip=10.254.254.1/24
Command success: ip link add haconiwa0 type bridge exited 0
Command success: ip addr add 10.254.254.1/24 dev haconiwa0 exited 0
Command success: ip link set dev haconiwa0 up exited 0

デフォルトでは haconiwa0 というブリッジができます。

$ ip a s haconiwa0
5: haconiwa0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
    link/ether 56:98:fb:4e:2f:3b brd ff:ff:ff:ff:ff:ff
    inet 10.254.254.1/24 scope global haconiwa0
       valid_lft forever preferred_lft forever
    inet6 fe80::5498:fbff:fe4e:2f3b/64 scope link 
       valid_lft forever preferred_lft forever

このブリッジの 10.254.254.1/24 の範囲で一つIPを決め、Hacofileで設定してみましょう。

  config.network.container_ip = "10.254.254.2"
  config.network.namespace = config.name

このHacofileでコンテナを立ち上げると、ちゃんと 10.254.254.2 が割り当てられたコンテナになり、またホストのネットワークとちゃんと分離されることがわかります。

root@haconiwa-9bdfc517:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
10: e6d4d690_g@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 02:6b:df:0e:d9:38 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.254.254.2/24 scope global e6d4d690_g
       valid_lft forever preferred_lft forever
    inet6 fe80::6b:dfff:fe0e:d938/64 scope link 
       valid_lft forever preferred_lft forever

Haconiwaには他にも様々な機能(特に、便利なフック機能など...)がありますが、無限に紹介記事が長くなってしまいそうなので、この辺りにしておきます。

ぜひいろいろ試してみてください!

udzura
投稿しているコードは、指定が無い限り MIT とします。
http://udzura.hatenablog.jp
pepabo
「いるだけで成長できる環境」を標榜し、エンジニアが楽しく開発できるWebサービス企業を目指しています。
https://pepabo.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした