1 cgroupとは
cgroups1はLinuxカーネルの機能の一つで、プロセスを階層的に管理し、リソースの配分を決められる仕組みである。(cgroupsにはv1とv2という2つのバージョンが存在するが、現在ではv2が主流なので、ここではv2についてのみ説明する)
cgroupsのインターフェースはファイルシステムとして提供されており、通常のファイルシステムと同様に、mkdir
やcat
のようなコマンドでアクセスすることができる。多くの環境ではcgroupsのファイルシステムは/sys/fs/cgroup
にマウントされている。
1.1 cgroupsのインターフェース
cgroupsファイルシステム上にある、一つのディレクトリが一つのcgroupとして機能する(ここでの「cgroup」は仕組み全体のことではなく、一つのグループのことを指す)。
以下はcgroupの一例
$ tree /sys/fs/cgroup/system.slice/cron.service
/sys/fs/cgroup/system.slice/cron.service
├── cgroup.controllers
├── cgroup.events
├── cgroup.freeze
├── cgroup.kill
├── cgroup.max.depth
├── cgroup.max.descendants
├── cgroup.pressure
├── cgroup.procs
├── cgroup.stat
├── cgroup.subtree_control
├── cgroup.threads
├── cgroup.type
├── cpu.pressure
├── cpu.stat
├── io.pressure
├── memory.current
├── memory.events
├── memory.events.local
├── memory.high
├── memory.low
├── memory.max
├── memory.min
├── memory.numa_stat
├── memory.oom.group
├── memory.peak
├── memory.pressure
├── memory.reclaim
├── memory.stat
├── memory.swap.current
├── memory.swap.events
├── memory.swap.high
├── memory.swap.max
├── memory.zswap.current
├── memory.zswap.max
├── pids.current
├── pids.events
├── pids.max
└── pids.peak
1 directory, 38 files
上の例だと、「/sys/fs/cgroup/system.slice/cron.service」がcgroupを表すディレクトリになっている。
ディレクトリの下に大量のファイルが配置されており、これらがcgroupのインターフェースとして機能するファイルとなっている。たとえば、「memory.max」はメモリ使用量の上限、「pids.max」はプロセス数の上限を設定するファイルである。
ファイルに書き込むことでリソース管理の設定を変更でき、cat
コマンドなどを使って現在の設定を出力することができる(読み込み専用や書き込み専用のインターフェースファイルもある)。
各cgroupに割り当てられているプロセスのPIDは、cgroup.procs
という名前のファイルで管理されている。
$ cat /sys/fs/cgroup/system.slice/cron.service/cgroup.procs
704
cgroup.procs
に直接PIDを書き込むと、プロセスをcgroupに割り当てることができる。
# echo 920 >> /sys/fs/cgroup/system.slice/cron.service/cgroup.procs
2 systemdによるcgroups管理
systemdを使用する環境の場合、一般的な設定では、systemdがシステム全体のcgroupsの設定を管理する。システムのリソース管理の設定を変更したい場合、通常はsystemdのインターフェースを操作することになる。
systemd-cgls
コマンドを使うと、systemdが管理しているcgroupsの全体像を見ることができる。systemd-cgtop
コマンドではcgroupが現在使用しているリソースを確認できる。
systemdのリソース管理について、詳しくは23を参照のこと。
2.1 systemdユニット
systemdのユニットの中で、リソース管理に関わるのは次の3つである。
2.1.1 service
serviceはsystemdの中でも最も一般的な、プロセスを管理するユニットである。apache、nginx、mariadbなど、systemctl
コマンドで操作する機会の多いプログラムのほとんどはserviceとして管理されている。
systemdでは、基本的に一つのserviceに対して一つのcgroupが割り当てられる。これにより、各serviceに対して個別にリソース管理の設定をすることが可能になっている。
2.1.2 slice
sliceは階層的にリソースを管理するためのユニットである。一つのsliceに対して一つのcgroupが割り当てられるが、serviceとは違って、slice自身はプロセスを管理しない。
下のように、serviceやsliceをまとめて全体を管理するのが主な役目である。
CGroup: /system.slice
├─ModemManager.service
├─NetworkManager.service
├─avahi-daemon.service
├─bluetooth.service
2.1.3 scope
scopeはserviceと同様にプロセスを管理するユニットである。一つのscopeに対して一つのcgroupが割り当てられる。
serviceとの主な相違点は以下の2つ。
- systemdがプロセスを開始しない(ユーザーセッションから開始される)
- メインプロセスがなく、複数プロセスを管理する
serviceユニットの場合、systemdがプロセスの開始と終了を担当する(そのため、serviceとして開始されたプロセスの親プロセスは必ずsystemdになる)のだが、scopeの場合はそうではなく、外で開始されたプロセスをscopeに登録し、リソース等を管理する。
また、serviceでは基本的に一つのメインプロセスを管理する(そのプロセスの子プロセスも管理下に入るが、あくまでメインは一つ)が、scopeは複数のプロセスを管理する。
-
https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html (公式ドキュメント) ↩
-
https://www.freedesktop.org/software/systemd/man/latest/systemd.resource-control.html (
man systemd.resource-control
で閲覧できるマニュアルと同じ内容) ↩ -
https://systemd.io/CONTROL_GROUP_INTERFACE/ (systemd公式サイトのリソース管理に関する解説) ↩