2013年9月11日水曜日

namespaceとcgroupで、Linuxを仲良く使う

Linuxのnamespaceとcgoup(Control Groups) のメモです。特にCのプログラムから使うところ。基本機能だと思うのですが、日本語ページが少ないので。

一つコンピュータを複数の人で使うのに、最近はなぜか仮想マシンが流行みたいなのですが、いろいろもったいないで、OS上で仲良く使えばいいのにと。OSのユーザとパーミッションくらいで仲良く使える世の中がいいと思うのですが、せち辛いのか・物騒なのか、File Systemやネットワークはオレ専用がいいとか、アイツがCPUやメモリを独り占めするのは許さねえ、とかが問題なんでしょうか。

namespaceがもろもろのオレ専用(isolation)、cgroupが独り占め関連(リソース分配)みたいな話なんじゃないかと。

1. namespace概要


参考文献は、Namespaces in operation, part 1: namespaces overview あたりかと。

kernelバージョン依存ですが、ざっと、以下を分離して使うことができるようです。

namespaceプログラムのflag kernel 分離するもの
Mount CLONE_NEWNS2.4.19マウントポイント(というかファイルシステム)
UTS CLONE_NEWUTS2.6.19nodename/domainname(というかホスト名/NISドメイン名)
IPC CLONE_NEWIPC2.6.19System V IPCとPOSIX message queues
PID CLONE_NEWPID2.6.24プロセスID(pid)空間
Network CLONE_NEWNET(2.6.24) 2.6.29ネットワークデバイス
User CLONE_NEWUSER(2.6.23) 3.8ユーザやグループ(uidとかgidとか)

例えば、Cのプログラムの中で、
  unshare(CLONE_NEWNS | CLONE_NEWNET)
とか引数に好きなのを並べると、それ以降の処理はnamespace分離されて動作するって感じかと。(cloneとかでも)

2. cgroup (control group)


参考文献は、CGROUPS, CGROUPまわりその他資料, Redhat(RHEL6)の資料などなど。

cgroupを作って、pidをcgroupにひもづけることで、プロセス毎のリソース利用制限ができます。作ったcgroupに対してできること(リソース制限設定など)は、環境依存ですが、ざっと、以下です。

sybsystemできることの例
cpu1秒に N micro secondまでとか、全部で N micro secondまでとかの、半分ずつシェアしようとかの制限
cpusets何番目のCPUを使うとか、どのメモリノードを使うとかの、制限
memoryN byteまでとかの制限
hugetlbN byteまでとかの制限
blkioブロックIO制限で、HDDとかのデバイス毎に、読み込み N byte/secondまで、とかの制限
devicesどのデバイスが使えるとかの制限
freezer処理を止めちゃう。
net_clsネットワークパケットに印をつける。(その印をもとに、別途、tc(linux traffic control)が流量制限したりする)
net_prioネットワークデバイス毎のプライオリティ設定

cgroupを使う、cgroupに制限を設定する、プロセスをcgroupにひもづけるなんかは、
コマンド、特別なディレクトリ(subsys_mount_point)の操作、静的設定・ルール設定、プログラムから、
とかの方法があります。

利用には、少し準備が必要かもです。

CentOS6あたりでは、
yum -y install libcgroup
service cgconfig start
chkconfig cgconfig on

プログラムで遊ぶなら
yum -y install libcgroup-devel

確認(subsys_mount_pointを見てみる)は、
ls -la /cgroup/
total 8
drwxr-xr-x. 10 root root 4096 Sep 11 21:27 .
dr-xr-xr-x. 23 root root 4096 Sep 11 21:26 ..
drwxr-xr-x.  2 root root    0 Sep 11 21:27 blkio
drwxr-xr-x.  3 root root    0 Sep 11 21:27 cpu
drwxr-xr-x.  2 root root    0 Sep 11 21:27 cpuacct
drwxr-xr-x.  2 root root    0 Sep 11 21:27 cpuset
drwxr-xr-x.  2 root root    0 Sep 11 21:27 devices
drwxr-xr-x.  2 root root    0 Sep 11 21:27 freezer
drwxr-xr-x.  3 root root    0 Sep 11 21:27 memory
drwxr-xr-x.  2 root root    0 Sep 11 21:27 net_cls

Ubuntu12.04あたりでは、
apt-get -y install cgroup-lite

プログラムで遊ぶなら
apt-get -y install libcgroup-dev

確認(subsys_mount_pointを見てみる)は、
ls -la /sys/fs/cgroup/
total 0
drwxr-xr-x 10 root root 200 Aug 30 05:49 .
drwxr-xr-x  6 root root   0 Aug 30 05:29 ..
drwxr-xr-x  2 root root   0 Aug 30 05:49 blkio
drwxr-xr-x  2 root root   0 Aug 30 05:49 cpu
drwxr-xr-x  2 root root   0 Aug 30 05:49 cpuacct
drwxr-xr-x  2 root root   0 Aug 30 05:49 cpuset
drwxr-xr-x  2 root root   0 Aug 30 05:49 devices
drwxr-xr-x  2 root root   0 Aug 30 05:49 freezer
drwxr-xr-x  2 root root   0 Aug 30 05:49 memory
drwxr-xr-x  2 root root   0 Aug 30 05:49 perf_event


3. プログラムから使う


namespaceは、cloneunshareでflag指定するだけ、
cgroupは、libcgroupで、グループを作ったり、グループにプロセスを割り当てたり、
する感じです。

3-1. namespaceの例


#include <sched.h>

...
  unshare(CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWNET | CLONE_NEWUTS);

  // 以降、指定したnamespaceが分離されて実行される


例えば、pivot_rootと一緒に使うと、ファイルシステムも別な感じでいいのじゃないかと思うんですが、正解の自身がないです。
#include <stdio.h>
#include <sched.h>
#include <sys/mount.h>

...
  int r;
  r = unshare(CLONE_NEWNS);
  if(rc != 0){ perror("unshare"); exit(1);}

  mkdir("/var/tmp/myjail01");
  mkdir("/var/tmp/myjail01/old_root");
  chdir("/var/tmp/myjail01");

  r = pivot_root("/var/tmp/jail1", "/var/tmp/jail1/old_root");
  if(rc != 0){ perror("pivot_root"); exit(2);}

  chdir("/");
  umount2("old_root", MNT_DETACH);

  // 以降、マウントポイントが分離され、勝手なルートディレクトリで動作するつもり

 

3-2. cgroupの例


mycgroup01を作って、CPU共有の重み500、メモリ制限1MBにして、プログラム自身を、mycgroup01内で実行(=制限をうける)する例です。


#include <libcgroup.h>
// gcc test.c -lcgroup

...
  // 初期化 
  cgroup_init();

  // cgroupをふわっと作る
  struct cgroup *cg1 = cgroup_new_cgroup("mycgroup01");

  // 制限を追加 
  struct cgroup_controller * cg1cpu = cgroup_add_controller(cg1, "cpu");
  cgroup_add_value_int64(cg1cpu, "cpu.shares", 500);

  struct cgroup_controller * cg1mem = cgroup_add_controller(cg1, "memory"); 
  cgroup_add_value_int64(cg1mem, "memory.limit_in_bytes", 1234000);

  // cgroupをほんとうに作る 
  cgroup_create_cgroup(cg1, 0);

  // このタスク自身を、今作ったcgroupに入れる(上記制限の配下に入れる)
  cgroup_attach_task(cg1);

  ...以降、上記制限の配下に入るので、
 ・制限(1234000byte)を超えたmallocとかmemsetとかしてみると、止まる
 ・無限ループとかにしてcpu.shares値をかえたバージョンと二つ同時に動かすと、shares値の割合どおりにCPUが使われる
 とか

4. 応用


ちらほら見たところでは、以下で使われているらしく、
libvertでKVM使うとcgroupついてくるとか、
LXCのバックエンドはこんなんじゃないかとか、
OpenStackとやらもネットワーク部分で使われているらしい

ほかには、
あやしい人のshellを置き換えたり、いまいち怪しいブラウザをラップしたり、
あやしい人のプログラムを隔離して実行したり(Webアプリとか、自分の自信の無いプログラムとかも)
とか、OSだけで昔ながらのシンプルなサーバー共同利用がいいなあ、と。

--
以上

3 件のコメント:



  1. Awesome article. It is so detailed and well formatted that i enjoyed reading it as well as get some new information too.


    SAP ABAP Training in Chennai


    SAP HR training in Chennai

    返信削除
  2. I simply couldn’t depart your site before suggesting that I really enjoyed the usual information an individual supply in your visitors? Is going to be again steadily to check out new posts.
    GRE Coaching in Chennai

    返信削除
  3. I simply couldn’t depart your site before suggesting that I really enjoyed the usual information an individual supply in your visitors? Is going to be again steadily to check out new posts.
    GRE Coaching in Chennai

    返信削除