1 cgroupとは?
cgroup(Control Groups)は、複数のプロセスをひとつのグループとして管理し、グループ単位で CPU、メモリ、I/O などのシステムリソースの使用量を制御・監視する仕組みです。cgroup v2 は AlmaLinux 8 で導入され、AlmaLinux 9 以降ではデフォルトの cgroup として利用されています。
本記事で使用している環境では、cgroup v2 が使用されています。以下のコマンドを実行することで、使用されている cgroup のバージョンが v2 であることを確認できます。
[root@server ~]# mount | grep cgroup
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,seclabel,nsdelegate,memory_recursiveprot)
2 検証環境
2.1 ソフトウェアのバージョン
各ノードのAlmaLinuxバージョンは以下のとおりです。
[root@control ~]# cat /etc/redhat-release
AlmaLinux release 9.7 (Moss Jungle Cat)
各ノードのカーネルバージョンは以下のとおりです。
[root@control ~]# uname -r
5.14.0-611.5.1.el9_7.x86_64
2.2 ノードのリソース
4GBのメモリを割り当てています。
[root@server ~]# free -h
total used free shared buff/cache available
Mem: 3.5Gi 558Mi 3.0Gi 9.1Mi 252Mi 3.0Gi
Swap: 2.0Gi 0B 2.0Gi
4コアのCPU(4 vCPU) を搭載しています。
[root@server ~]# lscpu -xe
CPU NODE SOCKET CORE L1d:L1i:L2:L3 ONLINE
0 0 0 0 0:0:0:0 yes
1 0 1 1 2:2:2:2 yes
2 0 2 2 4:4:4:4 yes
3 0 3 3 6:6:6:6 yes
lscpuコマンドの詳しい使い方は、以下のページをご覧ください。
3 インタフェースファイルについて
/sys/fs/cgroup/ 配下に任意の名前のディレクトリを作成することで、新しいcgroup を作成することができます。以下は、test という名前の cgroup を作成するときの例です。
[root@server ~]# mkdir /sys/fs/cgroup/test
作成したディレクトリ配下に自動生成されるファイルは、以下の 2 種類に分類されています。これらのファイルを介して cgroup の設定や状態確認を行います。
| 種類 | ファイル名 | 役割 |
|---|---|---|
| コア・インタフェースファイル | cgroup. というプレフィックスから始まる | プロセスの所属管理(cgroup.procs)や、子 cgroup へ割り当てるコントローラの制御(cgroup.subtree_control)など、cgroup そのものの共通管理を行う |
| コントローラ・インタフェースファイル | cpu. や memory. など、制御対象のリソース名から始まる | CPU の使用率制限やメモリの上限設定など、特定のリソースを制限・制御する |
(1) コア・インタフェースファイル
コア・インタフェースファイルは、以下のように cgroup. で始まるファイルです。
[root@control ~]# ls /sys/fs/cgroup/test/cgroup.*
/sys/fs/cgroup/test/cgroup.controllers /sys/fs/cgroup/test/cgroup.max.depth /sys/fs/cgroup/test/cgroup.subtree_control
/sys/fs/cgroup/test/cgroup.events /sys/fs/cgroup/test/cgroup.max.descendants /sys/fs/cgroup/test/cgroup.threads
/sys/fs/cgroup/test/cgroup.freeze /sys/fs/cgroup/test/cgroup.procs /sys/fs/cgroup/test/cgroup.type
/sys/fs/cgroup/test/cgroup.kill /sys/fs/cgroup/test/cgroup.stat
| 種類 | 概要 |
|---|---|
| cgroup.controllers | この cgroup で利用可能なコントローラ(cpu、memoryなど)の一覧を表示します |
| cgroup.procs | この cgroup に所属するプロセスの PID を表示します。PID を書き込むと、そのプロセスを元の cgroup から、この cgroup に移動します |
| cgroup.threads | この cgroup に所属するスレッドの TID を表示します |
| cgroup.max.depth | 作成できる子 cgroup の最大階層数を表示または設定します |
| cgroup.max.descendants | 作成できる子孫 cgroup の最大数を表示または設定します |
| cgroup.subtree_control | 子 cgroup に対して有効化するコントローラを設定します |
| cgroup.stat | cgroup の状態情報(子 cgroup 数など)を表示します |
(2) コントローラ・インタフェースファイル
各コントローラには専用のインタフェースファイルが用意されており、コントローラ名で始まるファイルとして配置されています。たとえば、cpuset コントローラには以下のようなインタフェースファイルがあります。
[root@control ~]# ls /sys/fs/cgroup/test/cpuset.*
/sys/fs/cgroup/test/cpuset.cpus /sys/fs/cgroup/test/cpuset.cpus.exclusive.effective /sys/fs/cgroup/test/cpuset.mems.effective
/sys/fs/cgroup/test/cpuset.cpus.effective /sys/fs/cgroup/test/cpuset.cpus.partition
/sys/fs/cgroup/test/cpuset.cpus.exclusive /sys/fs/cgroup/test/cpuset.mems
4 親プロセス移動時の子プロセスの cgroup 所属
本章では、cgroup v2 におけるプロセスの移動と cgroup 継承の動作を検証します。具体的には、以下の2点を確認することを本章の目的とします。
(1) 既存の子プロセスへの影響:
bash から sleep プロセスを起動した状態で、親プロセスである bash を別の cgroup へ移動した際、すでに起動している子プロセス(sleep)の所属 cgroup が変化するかどうか?
(2) 新規子プロセスへの継承:
bash を別の cgroup へ移動した後、その bash から新たにプロセスを起動した際、子プロセスが親プロセス(bash)の所属する cgroup を継承するかどうか?
4.1 動作確認
/sys/fs/cgroup/ 配下に test という名前の cgroup を作成します。
[root@control ~]# mkdir /sys/fs/cgroup/test
現在のシェル自身のPIDを確認します。$$ は現在のシェル自身の PID(プロセスID)を格納している特殊変数です。以降の作業でこのプロセスを移動させるため、あらかじめ PID を確認しておきます。
[root@control ~]# echo $$
2244
現在の bash プロセスがどの cgroup に所属しているかを確認します。通常、ログイン直後はシステム(systemd)がログインセッションに対して自動的に割り当てた cgroup に所属しています。
[root@control ~]# cat /proc/$$/cgroup
0::/user.slice/user-0.slice/session-3.scope
sleep 600 を現在の bash の子プロセスとしてバックグラウンドで起動します。ここでは PID 2923 が割り当てられました。
[root@control ~]# sleep 600 &
[1] 2923
sleep 600 の親プロセスが bash (sleepの親プロセスのPID が2244)であることを確認します。
[root@control ~]# ps -C sleep -o comm,pid,ppid,args
COMMAND PID PPID COMMAND
sleep 2923 2244 sleep 600
bash の子プロセスとして起動した sleep 600 も、この時点では親プロセス(bash)と同じ初期 cgroup に自動的に所属していることを確認します。
[root@control ~]# cat /proc/2923/cgroup
0::/user.slice/user-0.slice/session-3.scope
bash 自身の PID を、先ほど作成した test ディレクトリ内の cgroup.procs に書き込みます。cgroup v2 では、この操作によって指定したプロセス単体のみが移動します。
[root@control ~]# echo $$ > /sys/fs/cgroup/test/cgroup.procs
bash が test cgroup へ移動されたことを確認します。
[root@control ~]# cat /proc/$$/cgroup
0::/test
親プロセス(bash)を test へ移動させても、移動前から存在していた子プロセス sleep 600 の所属 cgroup は変化していないことを確認します。cgroup v2 では、親を移動しても既存の子プロセスは追従しないことが分かります。
[root@control ~]# cat /proc/2923/cgroup
0::/user.slice/user-0.slice/session-3.scope
test cgroup の cgroup.procs を確認します。移動した bash(2244)のほかに、一時的に実行された cat コマンド自身(PID: 3016)など、その瞬間 test 配下で動いているプロセスのみが表示されます。
[root@control ~]# cat /sys/fs/cgroup/test/cgroup.procs
2244
3016
test cgroup に移動した bash から、新たに sleep 800 をバックグラウンドで起動します。
[root@control ~]# sleep 800&
[2] 3030
ps コマンドで確認すると、移動前に起動した sleep 600 と、移動後に起動した sleep 800 の双方が、同じ bash(PID: 2244)を親に持っていることが分かります。
[root@control ~]# ps -C sleep -o comm,pid,ppid,args
COMMAND PID PPID COMMAND
sleep 2923 2244 sleep 600
sleep 3030 2244 sleep 800
test cgroup のプロセス一覧を確認します。bash に加え、新たに起動した sleep 800 がこの cgroup に含まれていることが確認できます(3051 は cat コマンドの PID です)。
[root@control ~]# cat /sys/fs/cgroup/test/cgroup.procs
2244
3030
3051
bash 自身が現在も test cgroup に所属し続けていることを確認します。
[root@control ~]# cat /proc/$$/cgroup
0::/test
移動後の bash から起動した sleep 800 の cgroup を確認します。親プロセスの現在の cgroup をしっかりと継承し、test に所属していることが確認できました。移動前に起動した sleep 600 の結果と対比することで、cgroup 伝播のタイミングが明確になります。
[root@control ~]# cat /proc/3030/cgroup
0::/test
4.2 後始末
実験用に変更した環境を元の状態に戻します。(cgroup は内部にプロセスが残っていると削除できないため、プロセスを終了させるか元の cgroup に戻す必要があります)
[root@control ~]# jobs
[1]- 実行中 sleep 600 &
[2]+ 実行中 sleep 800 &
実験用に起動した 2 つの sleep プロセス(ジョブ番号 %1 と %2)に終了シグナルを送り、プロセスを破棄します。
[root@control ~]# kill %1 %2
[1]- Terminated sleep 600
[2]+ Terminated sleep 800
作成した test cgroup を削除できるようにするため、bash プロセス(PID: 2244)を実験開始前の初期 cgroup(session-3.scope)へ移動します。
[root@control ~]# echo 2244 > /sys/fs/cgroup/user.slice/user-0.slice/session-3.scope/cgroup.procs
bash の所属が最初のログインセッションの cgroup に正しく戻っていることを確認します。
[root@control ~]# cat /proc/$$/cgroup
0::/user.slice/user-0.slice/session-3.scope
[root@control ~]# rmdir /sys/fs/cgroup/test
4.3 実験の結果まとめ
- cgroup の移動は指定したプロセス単体にのみ適用される:親プロセスを別の cgroup へ移動させても、すでに起動している子プロセスの cgroup は変わりません
- 新規プロセスは生成時の親プロセスの cgroup を継承する:親プロセスの移動後に、新しく起動した子プロセスは、その時点の親と同じ cgroup を自動的に引き継ぎます
5 コア・インタフェースファイルの使い方
5.1 cgroup.controllers
cgroup.controllers は、その cgroup において、利用可能なすべてのリソースコントローラ(CPUやメモリなどを制御する機能)の一覧を確認するための、読み取り専用のファイルです。
test という名前の cgroup ディレクトリを作成します。
[root@control ~]# mkdir /sys/fs/cgroup/test
作成した test ディレクトリ直下にある cgroup.controllers の中身を cat コマンドで表示してみます。出力結果を見ると、cpuset や cpu など、この cgroup で利用可能なリソースコントローラを確認することができます。
[root@control ~]# cat /sys/fs/cgroup/test/cgroup.controllers
cpuset cpu io memory hugetlb pids rdma misc
ちなみに、AlmaLinux10.2では、dmemコントローラが利用できるようになっています。
[root@control ~]# cat /sys/fs/cgroup/test/cgroup.controllers
cpuset cpu io memory hugetlb pids rdma misc dmem
その他の検証については、以下の AlmaLinux 10 の記事を参考にしてください。