LXCで学ぶコンテナ入門 -軽量仮想化環境を実現する技術

第48回 cgroup v2から使うコントローラとmiscコントローラ

この記事を読むのに必要な時間:およそ 9.5 分

おひさしぶりです。今年はこれまで結局一回もこの連載の記事を書きませんでした。年末が近づきAdvent Calendarの季節になり,毎年参加しているAdvent Calendarの案内が今年もあったので,また記事でAdvent Calendarに参加しようと思い戻ってきました。この記事はLinux Advent Calendar 2021の21日目の記事です。

仕事が忙しかったりして,なかなかこの連載に手が回らなかった一方で,今年は2013年以来開催してきたコンテナの勉強会をオンラインで2回開催できました。4月にSeccompをテーマにした勉強会10月に「Rustとコンテナ」をテーマにした勉強会を開催しました。どちらもこの連載で触れてきたような基本的な内容からさらに深い内容,この連載では全く触れていない内容まで,非常に広く深いお話が聞ける勉強会になりました。どちらも動画がアーカイブ公開されていますので,ご興味のあるテーマがあればぜひご覧になってください。

さて,これまで7回にわたって,この連載でcgroup v2について紹介してきました。これまではcgroupを作ったり,それぞれのcgroupでどのようなコントローラを有効にしてリソース制限を行うか? といった,cgroupコア部分が持つ,cgroup自身の階層構造を構成する機能を中心に解説してきました。

今回から,実際のリソース制限を行うコントローラをcgroup v2でどのように使うか? といったところを紹介していきたいと思います。

コントローラの使い方と言っても,ほとんどのコントローラでは基本はcgroup v1のときと大きく変わりません。そこで,今回は操作方法を細かく説明するのではなく,cgroup v2のコントローラを全体的に見ながら,cgroup v1から制御方法が変わったところを紹介したり,cgroup v1から動きが変わったところをつまみ食いしながら軽く説明をしていきたいと思います。同時に最近追加された新しいコントローラについても紹介します。

cgroup v2で使えるコントローラ

現時点(5.15カーネル時点)でcgroup v2で使えるコントローラは次の通りです。

表1 cgroup v2で使えるコントローラ(5.15カーネル)

コントローラ名 使えるようになったバージョン
cpu 4.15
cpuset 5.0
device 4.15
freezer 5.2
hugetlb 5.6
io 4.5
memory 4.5
misc 5.13
perf_event 4.11
pids 4.5
rdma 4.11

5.13カーネルを使っており,デフォルトでcgroup v2のみがマウントされているUbuntu 21.10の環境では,root cgroup配下のcgroup.controllersは次のようになっています。

$ uname -r
5.13.0-21-generic
$ grep cgroup /proc/self/mountinfo
35 25 0:30 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime shared:9 - cgroup2 cgroup2 rw,nsdelegate,memory_recursiveprot
$ cat /sys/fs/cgroup/cgroup.controllers 
cpuset cpu io memory hugetlb pids rdma misc

Ubuntu 21.10のような新しい環境では,上記のようにデフォルトでcgroup v2のみを使うようになっています。しかし現時点では,多くのシステムでcgroup v1のみがマウントされているか,cgroup v1とv2の両方がマウントされていると思います。

第37回で説明したとおり,cgroup v1とv2両方がマウントされている場合は,cgroup v1側で有効になっていないコントローラのみがcgroup v2で使えます。このような環境で特定のコントローラをcgroup v2で使いたい場合は,起動時にカーネルパラメータcgroup_no_v1=を使ってcgroup v2で使いたいコントローラを指定します。allを指定するとcgroup v1側では全コントローラが無効になります。

ここでcgroupを1つ作成し,/sys/fs/cgroup/cgroup.controllersに出現しているコントローラを全部,子cgroupで使えるようにしてみましょう。このあたりの操作方法については第38回をご覧ください。

$ sudo mkdir /sys/fs/cgroup/test
$ echo "+cpuset +cpu +io +memory +hugetlb +pids +rdma +misc" | sudo tee /sys/fs/cgroup/cgroup.subtree_control
(使えるコントローラすべてを子cgroupで使えるようにする)
+cpuset +cpu +io +memory +hugetlb +pids +rdma +misc
$ cat /sys/fs/cgroup/cgroup.subtree_control 
cpuset cpu io memory hugetlb pids rdma misc

このように,cgroup.subtree_controlファイルに子cgroupで使いたいコントローラを,コントローラ名の前に+をつけて書き込むと登録できました。登録すると,子cgroupでコントローラが有効になり,cgroupディレクトリ内にはコントローラ用のファイルが出現するのでした。この例ではcgroup.controllers内に書かれているコントローラすべてを書いています。実際は,Ubuntu 21.10ではデフォルトでいくつかコントローラは登録されていますので,このように全部を追加する必要はありません。

次のように,全コントローラをcgroup.subtree_controlに登録すると大量のファイルが出現します。

$ ls /sys/fs/cgroup/test/
cgroup.controllers      cpuset.cpus            hugetlb.1GB.events.local  io.stat              memory.stat
cgroup.events           cpuset.cpus.effective  hugetlb.1GB.max           io.weight            memory.swap.current
cgroup.freeze           cpuset.cpus.partition  hugetlb.1GB.rsvd.current  memory.current       memory.swap.events
cgroup.max.depth        cpuset.mems            hugetlb.1GB.rsvd.max      memory.events        memory.swap.high
cgroup.max.descendants  cpuset.mems.effective  hugetlb.2MB.current       memory.events.local  memory.swap.max
cgroup.procs            cpu.stat               hugetlb.2MB.events        memory.high          misc.current
cgroup.stat             cpu.uclamp.max         hugetlb.2MB.events.local  memory.low           misc.max
cgroup.subtree_control  cpu.uclamp.min         hugetlb.2MB.max           memory.max           pids.current
cgroup.threads          cpu.weight             hugetlb.2MB.rsvd.current  memory.min           pids.events
cgroup.type             cpu.weight.nice        hugetlb.2MB.rsvd.max      memory.numa_stat     pids.max
cpu.max                 hugetlb.1GB.current    io.max                    memory.oom.group     rdma.current
cpu.pressure            hugetlb.1GB.events     io.pressure               memory.pressure      rdma.max

ちなみにroot cgroup内を見てみると,次のようになっています。

$ ls -F /sys/fs/cgroup/
cgroup.controllers      cgroup.threads         dev-mqueue.mount/  memory.numa_stat                sys-kernel-config.mount/
cgroup.max.depth        cpu.pressure           init.scope/        memory.pressure                 sys-kernel-debug.mount/
cgroup.max.descendants  cpuset.cpus.effective  io.cost.model      memory.stat                     sys-kernel-tracing.mount/
cgroup.procs            cpuset.mems.effective  io.cost.qos        misc.capacity                   system.slice/
cgroup.stat             cpu.stat               io.pressure        -.mount/                        test/
cgroup.subtree_control  dev-hugepages.mount/   io.stat            sys-fs-fuse-connections.mount/  user.slice/

子cgroupよりはファイル数が大幅に少ないことがわかります。root cgroupはリソース制限が行えないので,基本的にはコントローラ用のファイルは出現しません。しかし,一部のコントローラ用のファイルについては,全体の統計情報を見れるようにroot cgroupに出現します。

rootでもroot以外でも,cgroup自体を操作したり,cgroup自体の情報を見るファイルはcgroup.で始まり,コントローラ用のファイルはコントローラ名が頭に付きます。

deviceコントローラ

ここで改めて先ほども見たcgroup.controllersファイルを見てみましょう。このファイルには使えるコントローラが一覧されています。

$ cat /sys/fs/cgroup/cgroup.controllers 
cpuset cpu io memory hugetlb pids rdma misc

先の表1とcgroup.controllersファイルを見比べると,deviceがないことに気づいた方もいらっしゃるのではないでしょうか。

cgroup.controllers内に記載がないからといって,cgroup v2でdeviceコントローラが使えないわけでも,Ubuntuカーネルでdeviceコントローラが有効になっていないわけではありません。

$ grep CGROUP_DEVICE /boot/config-5.13.0-21-generic 
CONFIG_CGROUP_DEVICE=y

cgroup v2からは,deviceコントローラには他のコントローラのようなインターフェースファイルがなくなり,最近流行の(?)eBPFプログラムをcgroupにアタッチして制限を行うようになりました。デバイスへのアクセスを行おうとすると,そのアタッチしたプログラムへ制御が移り,プログラムが成功もしくは失敗を返して制御を行います※1⁠。

※1)
eBPFを使って制御を行う様子は @udzura さんによるDevice access filtering in cgroup v2に解説があります。

著者プロフィール

加藤泰文(かとうやすふみ)

2009年頃にLinuxカーネルのcgroup機能に興味を持って以来,Linuxのコンテナ関連の最新情報を追っかけたり,コンテナの勉強会を開いたりして勉強しています。英語力のない自分用にLXCのmanページを日本語訳していたところ,あっさり本家にマージされてしまい,それ以来日本語訳のパッチを送り続けています。

Plamo Linuxメンテナ

Twitter:@ten_forward
技術系のブログ:http://tenforward.hatenablog.com/