Apache HTTP server の mod_proxy_html メモ
最近、結構音楽ブログを更新しています。昔は音楽レビューといえばひたすら言葉でレビューするだけだったのが、最近は動画の埋め込みを行うようになって表現力のない私でも気楽にレビューができるようになってきました。
動画の埋め込みというと YouTube がまず思い浮かびますね。私の音楽ブログでもよく使っています。他に音楽ブログの性格上、V LIVEの動画を埋め込むこともあります。どちらも iframe を使った埋め込みコードが動画ページから生成できますので、気楽に貼り付けられます。
さて、私の音楽ブログは最近常時 SSL 化の流れで Let's Encrypt を使って SSL 化を行いました (Zenlogicの機能を使っただけ!!)。http でアクセスしても https に飛ばされます。https でアクセスするページに YouTube のコードを埋め込むのは何の問題もないのですが、V LIVE は埋め込む URL が http なので https でアクセスするページに埋め込みコードを貼り付けてもブロックされてしまいます。
となると、自分で運用している VPS でリバースプロキシの設定をやって、それを貼り付けたらいいんじゃないか? という考えが思い浮かぶのでやってみました。まあ例えば
ProxyPass "/vlive" "http://www.vlive.tv" ProxyPassReverse "/vlive" "http://www.vlive.tv"
ってな感じですぐに設定できました。早速喜んで埋め込みコードとして、自 VPS の URL を使ってみましたが、これだと iframe の src に書かれた先を読み込むのは https 化されましたが、その中でさらに呼ばれる js や css が相変わらず http なので、動画はブロックされたままでした。残念...
そこで確かそういう場合に使うモジュールあったよなあと思ってググってみると、proxy 通した場合のコンテンツ内の URL を変換する場合は
- mod_substitute
- mod_proxy_html
なんかを使うようですね。
そこでmod_proxy_htmlを試すかということで、mod_proxy_htmlの公式マニュアルを見ながら設定してみました (mod_proxy_html は以前使ったことあるような記憶があったので)。
ProxyHTMLEnable On ProxyHTMLExtended On ProxyHTMLURLMap http://www.vlive.tv/ https://www.example.com/ # 以下は mod_proxy_html と一緒にインストールされる proxy-html.conf 内で書かれている設定もあります ProxyHTMLLinks meta content ProxyHTMLLinks script src ProxyHTMLLinks link href : (snip)
とするけど、ブラウザでエラーになってしまいます(Chrome だと "ERR_CONTENT_DECODING_FAILED")。うーむ、としばらくいろいろ設定を試したのですがうまくいかずに諦めようかなという時にふと目に付いたのが公式マニュアルのコメント欄。
RequestHeader unset Accept-Encoding
これを加えると見事動作しました。マニュアル部分に注釈としてでも書いておいてほしいなー。
SetOutputFilter proxy-html
を設定しろみたいに書いてあるページもいくつか見つけましたが、コメント欄にあるように UTF-8 の部分が文字化けしてしまいますので不要です。
ハマったのでメモ代わりに残しておこうと思ってブログ書いたけど…、ふと今日検索してみると…
こんなページがひっかかった!! (^_^;) mod_substitute でも同じ問題が起きるようですね。なるほど、ブラウザの送るヘッダをそのまま送って圧縮した応答なんかが帰ってきた場合にうまく処理できないってことですか。
なぜハマってる最中にググった時に気づかなかったんだ!? というわけで書くほどでもなかったネタのようですが、せっかく書いたのでそのまま公開しておきます。
せっかく問題は解決したのに、V LIVE で貼り付けようとしていた動画を早速貼り付けようとしたら、YouTube でも公開されていたので、まだ音楽ブログでは活用できてません。
ip netns コマンドが意外にきめ細やかにコンテナを作ってくれる
(2016-07-26: 誤記修正しました "setns -> nsenter")
お手軽にシェルスクリプトなんかでコンテナを作る場合の強い味方といえば
- util-linux の unshare/nsenter コマンド
- iproute2 の ip netns コマンド
が代表的でしょう。"ip netns" は Network Namespace 作ってコマンド実行するだけの単純なコマンドかと思ったら、中では意外に色々細かくやってくれていることがわかったのでちょっと紹介しておきます。
以下は iproute2 4.2.0 で試しています。
/var/run/netns
まずよく知られているのが /var/run/netns 以下に Namespace 名のファイルを作ってくれることですね。これは、Namespace 内で動いているプロセスがなくなったら Namespace が消滅してくれるのを防ぐためです。だって ip netns add が終了したら、Namespace 内にはプロセスいなくなりますから。
まずはこの辺りで /var/run/netns を MS_SHARED にして、自身を bind mount して、ココをマウントポイントにしています。
636 while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) { :(snip) 644 /* Upgrade NETNS_RUN_DIR to a mount point */ 645 if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND, NULL)) { :(snip) 651 } (ip/ipnetns.cより)
そして
667 /* Bind the netns last so I can watch for it */ 668 if (mount("/proc/self/ns/net", netns_path, "none", MS_BIND, NULL) < 0) { (ip/ipnetns.cより)
ip netns add コマンドのプロセスディレクトリの ns/net ファイルを /var/run/netns 以下に bind mount していますね。このように Namespace を示す特殊なファイルを残したままにしておけば Namespace が消えません。
Namespace と veth 作成
ここで Network Namespace として "netns01" を作成し、ホストとコンテナ間は veth インターフェースを作成します。
# export NETNS="netns01" # export VETH="veth0"
それでは Network Namespace を作りましょう。
# ip netns add $NETNS # ip netns list netns01
簡単ですね。
それでは veth インターフェースを作りましょう。
# ip link add name $VETH-host type veth peer name $VETH-ns # ip link set $VETH-ns netns $NETNS # ip addr add 10.10.10.10/24 dev $VETH-host # ip link set $VETH-host up # ip netns exec $NETNS ip addr add 10.10.10.11/24 dev $VETH-ns # ip netns exec $NETNS ip link set $VETH-ns up
ホスト側は "veth-host"、コンテナ側は "veth-ns" という名前のペアを作りました。それぞれアドレスを与えて、インターフェースを up します。
では、この作成した Namespace で bash を実行してコンテナを作成してみましょう。
# ip netns exec $NETNS /bin/bash # echo $$ 11945 # ip a 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 11: veth0-ns@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether ba:aa:99:70:46:ab brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.10.10.11/24 scope global veth0-ns valid_lft forever preferred_lft forever inet6 fe80::b8aa:99ff:fe70:46ab/64 scope link valid_lft forever preferred_lft forever
"veth0-ns" インターフェースがあって、ちゃんとアドレスが割りあたってますね。まあ、これはそうなるようにコマンド実行していますので当たり前です。
コンテナ内の sysfs
ここで、Namespace 内で /sys 以下を見てみましょう。
# ls /sys/class/net -l 合計 0 lrwxrwxrwx 1 root root 0 7月 26日 20:01 lo -> ../../devices/virtual/net/lo/ lrwxrwxrwx 1 root root 0 7月 26日 20:01 veth0-ns -> ../../devices/virtual/net/veth0-ns/
ちゃんと Namespace 内のインターフェースのみ見えてますね。これは、この辺りの処理ですね。
66 if (unshare(CLONE_NEWNS) < 0) { 67 fprintf(stderr, "unshare failed: %s\n", strerror(errno)); 68 return -1; 69 } 70 /* Don't let any mounts propagate back to the parent */ 71 if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL)) { 72 fprintf(stderr, "\"mount --make-rslave /\" failed: %s\n", 73 strerror(errno)); 74 return -1; 75 } 76 /* Mount a version of /sys that describes the network namespace */ 77 if (umount2("/sys", MNT_DETACH) < 0) { 78 fprintf(stderr, "umount of /sys failed: %s\n", strerror(errno)); 79 return -1; 80 } 81 if (mount(name, "/sys", "sysfs", 0, NULL) < 0) { 82 fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno)); 83 return -1; 84 } (lib/namespace.cより)
- 66行目で Mount Namespace を作ってます
- 71行目で他の Mount Namespace に自身の Mount が伝播しないようにしています
- 77行目で現在の /sys を umount して
- 81行目で sysfs を改めて mount します
まあ、当たり前といえば当たり前ですが、ちゃんとここまで面倒見ててくれたんですね、ip netns。
/etc/netns
そして、以上の辺りのソースをつらつらと眺めていたら、気になる関数を見つけました。
86 /* Setup bind mounts for config files in /etc */ 87 bind_etc(name); (lib/namespace.cより)
これを見てみると
35 snprintf(netns_name, sizeof(netns_name), "%s/%s", etc_netns_path, entry->d_name); 36 snprintf(etc_name, sizeof(etc_name), "/etc/%s", entry->d_name); 37 if (mount(netns_name, etc_name, "none", MS_BIND, NULL) < 0) { (lib/namespace.cより)
"etc_netns_path" は /etc/netns/[namespace名] が入っていますので、その下のファイルを作成した Namespace 内に bind mount してくれるようです。
早速、ホスト上で /etc/netns/netns01/{hosts,resolv.conf} を作ってみました。
# cat /etc/netns/$NETNS/hosts 10.10.10.10 host01 10.10.10.11 ns01 # cat /etc/netns/$NETNS/resolv.conf nameserver 8.8.8.8
以上を準備してから、再度コンテナを作成します。
# ip netns exec $NETNS /bin/bash # cat /etc/resolv.conf nameserver 8.8.8.8 # cat /etc/hosts 10.10.10.10 host01 10.10.10.11 ns01
見事に作成した Namespace で実行されるコンテナでは準備したファイルが見えていますね。こんなとこまで面倒見てくれてたとは。(ちゃんと man ip-netns に書いてあるやん)
ip netns コマンドのソース、シンプルでコメントもちゃんと書かれてあって読みやすいのでコンテナ作成の勉強になる気がします。
cgroup なのか cgroups なのか
割とどーでもいい話(でも気になってた人多いはずw)
以前、第4回のコンテナ勉強会でも質問が出たのですが、cgroup/cgroups という機能の正式な名称は cgroup なのか cgroups なのか、というのはよくわかりませんでした。
私は、英語って単数・複数をきちんと使い分けるし、cgroup は複数のサブシステム・コントローラが存在するので、海外の人は "cgroups" と複数形で使うんだろうなあと思ってました。機能自体を指しているのか、コントローラ群を含めて指しているのかって、曖昧な文脈も多いですし。
しかし、この論争にもついにピリオドが打たれました。カーネル付属文書の cgroup-v2.txt をご覧ください。
"cgroup" stands for "control group" and is never capitalized. The
https://www.kernel.org/doc/Documentation/cgroup-v2.txt
singular form is used to designate the whole feature and also as a
qualifier as in "cgroup controllers". When explicitly referring to
multiple individual control groups, the plural form "cgroups" is used.
"cgroup" は "control group" を表します。大文字では表記することはありま
せん。単数形は全機能を表したり、"cgroup controllers" のように修飾子と
して全機能を表すために使います。明確に複数の個別の control groups を示
すときに、複数形の "cgroups" を使います。
Tejun Heo 氏は非英語ネイティブと想像しているのできっとその辺りが気になっていたんだ、なのでそこをはっきりさせたんだ、と妄想しています(笑)。
まあ相変わらず cgroup v1 については明確な定義が書かれてるわけではないんですがね (^_^;)
4.5 カーネルで stable となった cgroup の単一階層構造 cgroup v2 の io コントローラ
Control Group v2
以前も少し紹介していましたし、連載でも少し触れましたが、今広く (?) 使われている cgroup は色々問題があって、単一階層構造の cgroup が開発されていました。この辺りは
- Linux 3.16 から試せる cgroup の単一階層構造 (1) - TenForwardの日記
- Linux 3.16 から試せる cgroup の単一階層構造 (2) - TenForwardの日記
で紹介しました。
以前は開発中の機能だったため、マウントするときに "__DEVEL__sane_behavior" などというふざけたオプションが必要でした。(^^)
この後も順調に (?) 開発はすすみ、4.5 カーネルのリリースでついにこの機能が stable となったようで、"__DEVEL__" というプレフィックスも不要になりましたし、正式な機能で「まともなふるまい」なんてのはないだろうという話があったのかなかったのか知りませんが、名前も "Control Group v2" という名前になったようです。今までのは "v1" です。
ドキュメントは
にあります。
前に試した時は v1 にあったコントローラ (サブシステム) が全部現れていましたが、正式リリースとなった 4.5 の時点で有効なコントローラは memory, io, pid の 3 つだけのようです。
v1 の問題点のひとつに、コントローラがばらばらに実装されているため、コントローラ間の連携ができないという問題がありました。このため、blkio というブロックデバイスに対する I/O 制限を行うコントローラがあるにもかかわらず、通常のファイル I/O (の書き込み) に対する制限ができませんでした (memory と連携できていないため)。
この辺りは「第4回 コンテナ型仮想化の情報交換会@東京」で @hiro_kamezawa さんにお話頂いたので、詳細をお知りになりたい方はそちらをどうぞ。
v2 では、階層構造が単一となって、この辺りの制限ができるようになりました。昨年の LinuxCon で Heo Tejun 氏が ext2 に対応したという話をされていましたが、4.5 を見てみると ext2, ext4, btrfs に対して制限がかかるようです。
というわけで、この制限が働くのか簡単に試してみました。
kernel は 4.6-rc3、ファイルシステムは ext2 と ext4 で試しています。
かなり適当な確認なので、間違いとかあるかもしれませんので、気づいたら優しく教えてください。
v1 のおさらい
v2 を試す前に、まずは v1 の blkio コントローラのおさらいをしておきましょう。direct I/O 以外では制限がかかっていないことも確認してみました。
v1 準備
"test01" cgroup を作成して、/dev/vdb に対する 1MB/sec の読み書きの制限を設定してみました。
- cgroup 作成
# mkdir /sys/fs/cgroup/blkio/test01
- プロセスを "test01" へ登録
# echo $$ > /sys/fs/cgroup/blkio/test01/tasks
- /dev/vdbに対する制限を設定
# ls -l /dev/vdb
brw-rw---- 1 root disk 254, 16 Apr 13 06:30 /dev/vdb (デバイス番号の確認)
# echo "254:16 1048576" > /sys/fs/cgroup/blkio/test01/blkio.throttle.read_bps_device (読み込み制限)
# echo "254:16 1048576" > /sys/fs/cgroup/blkio/test01/blkio.throttle.write_bps_device (書き込み制限)
v1 を使った書き込み制限 (direct I/O)
# dd oflag=direct if=/dev/zero of=/data/testfile bs=4K count=1024 1024+0 records in 1024+0 records out 4194304 bytes (4.2 MB) copied, 4.00347 s, 1.0 MB/s
実行時に iostat を実行しました。出力の一部。
Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn vdb 258.59 0.00 1034.34 0 1024 vdb1 258.59 0.00 1034.34 0 1024
書き込みが 1MB/sec に制限されていますね。
v1 を使った読み込み制限 (direct I/O)
# dd iflag=direct if=/data/testfile of=/dev/null bs=4K count=1024 1024+0 records in 1024+0 records out 4194304 bytes (4.2 MB) copied, 4.0018 s, 1.0 MB/s
同様に iostat 出力の一部。
Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn vdb 261.22 1044.90 0.00 1024 0 vdb1 261.22 1044.90 0.00 1024 0
読み込みが 1MB/sec に制限されています。
v1 を使った書き込み制限
"oflag=direct" を指定せずに dd を実行してみると、
# dd if=/dev/zero of=/data/testfile bs=4K count=1048576 ^C636264+0 レコード入力 636264+0 レコード出力 2606137344 バイト (2.6 GB) コピーされました、 22.6348 秒、 115 MB/秒
# iostat -p vdb 1 | grep "vdb " :(略) vdb 311.00 12.00 315392.00 12 315392 vdb 339.00 12.00 344064.00 12 344064 vdb 456.57 12.12 434424.24 12 430080 vdb 389.53 4.65 351255.81 4 302080 vdb 11.00 0.00 9216.00 0 9216 vdb 39.00 8.00 33688.00 8 33688 vdb 35.00 0.00 31940.00 0 31940 vdb 0.00 0.00 0.00 0 0 vdb 0.00 0.00 0.00 0 0 :(略) vdb 0.00 0.00 0.00 0 0 vdb 0.00 0.00 0.00 0 0 vdb 84.21 4.21 73675.79 4 69992 vdb 140.43 0.00 126012.77 0 118452 vdb 11.11 4.04 9002.02 4 8912 vdb 507.22 12.37 443455.67 12 430152 vdb 410.10 12.12 376501.01 12 372736 vdb 1.00 0.00 912.00 0 912
制限はかかっていませんね。書き込まれたらしばらく 0 の時間があり、また書き込みが再開されているのがわかります。
v1 を使った読み込み制限
"iflag=direct" を外して実行します。実行前にキャッシュクリアします。
# echo 3 > /proc/sys/vm/drop_caches (キャッシュクリア) # dd if=/data/testfile of=/dev/null bs=4K count=1024 1024+0 records in 1024+0 records out 4194304 bytes (4.2 MB) copied, 4.0036 s, 1.0 MB/s
読み込みは制限がききますね。
Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn vdb 8.25 1055.67 0.00 1024 0 vdb1 8.25 1055.67 0.00 1024 0
cgroup v2 の io コントローラ
v2 の準備
v2 は "cgroup2" という名前でマウントします。名前以外は以前試した「まともなふるまい」時代とあまり変わりません。
- /sys/fs/cgroup にマウント。
mount -t cgroup2 cgroup /sys/fs/cgroup/
- ルート cgroup の確認。ファイルが 3 つだけです
# ls /sys/fs/cgroup/
cgroup.controllers cgroup.procs cgroup.subtree_control - 使えるコントローラを確認
# cat /sys/fs/cgroup/cgroup.controllers
io memory pids - "memory" と "io" をサブ cgroup で使えるようにします
# cat /sys/fs/cgroup/cgroup.subtree_control (サブ cgroup で使えるコントローラ一覧の確認。デフォルトは空)
# echo "+memory +io" > /sys/fs/cgroup/cgroup.subtree_control (io と memory を追加)
# cat /sys/fs/cgroup/cgroup.subtree_control (再度確認)
io memory (登録されている) - "test01" cgroup 作成
mkdir /sys/fs/cgroup/test01 (作成)
"test01"でioとmemoryが使えるのが確認できました
# ls /sys/fs/cgroup/test01 (test01ディレクトリの確認)
cgroup.controllers io.max memory.events memory.stat
cgroup.events io.stat memory.high memory.swap.current
cgroup.procs io.weight memory.low memory.swap.max
cgroup.subtree_control memory.current memory.max
# cat /sys/fs/cgroup/test01/cgroup.controllers (test01で使えるコントローラの確認)
io memory
v2 で direct I/O 制限
まずは v1 でもちゃんと制限された direct I/O を確認しました。
まずは書き込み。
# dd oflag=direct if=/dev/zero of=/data/testfile bs=4K count=1024 1024+0 レコード入力 1024+0 レコード出力 4194304 バイト (4.2 MB) コピーされました、 4.0041 秒、 1.0 MB/秒
Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn vdb 261.22 0.00 1044.90 0 1024 vdb1 261.22 0.00 1044.90 0 1024
読み込み。
# dd iflag=direct if=/data/testfile of=/dev/null bs=4K count=1024 1024+0 レコード入力 1024+0 レコード出力 4194304 バイト (4.2 MB) コピーされました、 4.00393 秒、 1.0 MB/秒
Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn vdb 261.22 1044.90 0.00 1024 0 vdb1 261.22 1044.90 0.00 1024 0
v1 と同じく制限されています。
v2 で読み込み制限
少し大きなファイルで確認しました。
# echo 3 > /proc/sys/vm/drop_caches # dd if=/data/testfile of=/dev/null bs=4K count=1048576 ^C4605+0 レコード入力 4604+0 レコード出力 18857984 バイト (19 MB) コピーされました、 18.1077 秒、 1.0 MB/秒
iostat の出力は
# iostat -p vdb 1 | grep "vdb " vdb 30.83 2378.02 10808.93 1864321 8473984 vdb 0.00 0.00 0.00 0 0 vdb 0.00 0.00 0.00 0 0 vdb 0.00 0.00 0.00 0 0 vdb 0.00 0.00 0.00 0 0 vdb 7.07 630.30 0.00 624 0 vdb 8.08 1034.34 0.00 1024 0 vdb 8.00 1024.00 0.00 1024 0 vdb 8.08 1034.34 0.00 1024 0 vdb 8.00 1024.00 0.00 1024 0 vdb 8.08 1034.34 0.00 1024 0 :(略)
これは v1 と同じように制限がかかります。
v2 で書き込み制限
さて、いよいよハイライト。
# dd if=/dev/zero of=/data/testfile bs=4K count=1048576 ^C51563+0 レコード入力 51563+0 レコード出力 211202048 バイト (211 MB) コピーされました、 35.7076 秒、 5.9 MB/秒
# iostat -p vdb 1 | grep "vdb " vdb 28.16 2182.44 9794.36 1888229 8473984 vdb 0.00 0.00 0.00 0 0 vdb 0.00 0.00 0.00 0 0 vdb 0.00 0.00 0.00 0 0 vdb 0.00 0.00 0.00 0 0 vdb 0.00 0.00 0.00 0 0 vdb 0.00 0.00 0.00 0 0 vdb 36.17 144.68 0.00 136 0 vdb 1.05 0.00 842.11 0 800 vdb 1.01 0.00 517.17 0 512 vdb 1.00 0.00 508.00 0 508 vdb 1.01 0.00 783.84 0 776 vdb 3.00 0.00 1160.00 0 1160 vdb 1.00 0.00 1004.00 0 1004 vdb 1.01 0.00 1034.34 0 1024 vdb 1.01 0.00 1034.34 0 1024 vdb 1.01 0.00 1034.34 0 1024 vdb 1.01 0.00 1034.34 0 1024 vdb 0.99 0.00 1013.86 0 1024 vdb 2.02 0.00 1046.46 0 1036 vdb 2.00 0.00 1024.00 0 1024 vdb 1.01 0.00 1034.34 0 1024
落ち着くまで少し時間があるのと、一瞬 1024 以上の値が出てますが、大体きれいに 1024 (KB) で制限されています。
まとめ
とりあえずディスクへの書き込みがちゃんと制限されているっぽいです (たぶん)。
cgroup namespace (2)
前回は /proc/$PID/cgroup ファイルが Namespace を反映した形で記載されているのを見ました。
とりあえずここまで。これだけだとすでにマウントされている cgroupfs はそのままの元のディレクトリ階層で見えるので、/proc/$PID/cgroup だけ見え方が変わっても意味がないような気がしますが、改めて cgroupfs のマウントを試すとエラーになりますし、どうするものなのかちょっとまだ見えてないので、またわかれば続編を書く予定です。
と書きましたが、試したところちゃんと cgroupfs も Namespace ごとに見えるようになったので紹介しておきます。前回何をボケて失敗していたのかわかりませんが、以下のように普通に簡単な処理をやっただけです。
- まずは "test01" cgroup を作成します (memory だけ)
# mkdir -p /sys/fs/cgroup/memory/test01/
- 現在のシェルを "test01" の tasks に登録します
# echo $$ > /sys/fs/cgroup/memory/test01/tasks
- namespace内の cgroupfs をホストから見て別のところにマウントするために、LXC コンテナ用のツリーを借ります
# cd /var/lib/lxc/test01/rootfs/
- unshare で chroot を実行します
# unshare -C chroot $PWD
- namespace 内で proc をマウントし、/sys/fs/cgroup を tmpfs でマウントします。これは特に不要な気がしますが
# mount -n -t proc proc /proc
# mount -n -t tmpfs none /sys/fs/cgroup/ - memory サブシステムを /sys/fs/cgroup/memory にマウントします
# mkdir /sys/fs/cgroup/memory
# mount -n -t cgroup -o memory memory /sys/fs/cgroup/memory/
マウントできたので、確認してみます。
# ls /sys/fs/cgroup/memory/ cgroup.clone_children memory.memsw.failcnt cgroup.event_control memory.memsw.limit_in_bytes cgroup.procs memory.memsw.max_usage_in_bytes memory.failcnt memory.memsw.usage_in_bytes memory.force_empty memory.move_charge_at_immigrate memory.kmem.failcnt memory.numa_stat memory.kmem.limit_in_bytes memory.oom_control memory.kmem.max_usage_in_bytes memory.pressure_level memory.kmem.slabinfo memory.soft_limit_in_bytes memory.kmem.tcp.failcnt memory.stat memory.kmem.tcp.limit_in_bytes memory.swappiness memory.kmem.tcp.max_usage_in_bytes memory.usage_in_bytes memory.kmem.tcp.usage_in_bytes memory.use_hierarchy memory.kmem.usage_in_bytes notify_on_release memory.limit_in_bytes tasks memory.max_usage_in_bytes
普通にマウントできていて、"test01" cgroup は存在しませんね。つまりここが cgroupfs のルートなわけです。
では、ここに "test02" cgroup を作ってみましょう。
root@enterprise:~# mkdir /sys/fs/cgroup/memory/test02 root@enterprise:~# ls -d /sys/fs/cgroup/memory/test02 /sys/fs/cgroup/memory/test02/ root@enterprise:~# ls /sys/fs/cgroup/memory/test02 cgroup.clone_children memory.memsw.failcnt cgroup.event_control memory.memsw.limit_in_bytes cgroup.procs memory.memsw.max_usage_in_bytes :(略)
/sys/fs/cgroup/memory 直下に test02 というディレクトリができて、中も普通にファイルができています。
"test02" にプロセスを登録して /proc/$PID/cgroup を確認してみましょう。
# echo $$ > /sys/fs/cgroup/memory/test02/tasks # echo $$ 8574 # cat /proc/self/cgroup 14:debug:/ 13:pids:/ 12:hugetlb:/ 11:net_prio:/ 10:perf_event:/ 9:net_cls:/ 8:freezer:/ 7:devices:/ 6:memory:/test02 5:blkio:/ 4:cpuacct:/ 3:cpu:/ 2:cpuset:/ 1:name=systemd:/
ちゃんと Namespace 内の cgroup ツリーになってますね。
ここで、元のホスト上の Namespace から "test01" と "test02" を確認してみましょう。
$ ls -d /sys/fs/cgroup/memory/test01 /sys/fs/cgroup/memory/test01/ $ ls -d /sys/fs/cgroup/memory/test01/test02 /sys/fs/cgroup/memory/test01/test02/
作成した cgroup namespace の外では "test01" の下に "test02" がありますね。tasks ファイルも確認してみると、
$ cat /sys/fs/cgroup/memory/test01/test02/tasks 8574
シェルの PID が登録されていますね。