#cgroups (Control Group)

プロセスグループのリソースの利用を制限・隔離するLinux カーネルの機能。

##cgroups の仕組み

cgroups はプロセスをグループ単位で管理し、そのグループに対してリソースの制限・計測・優先度付けを行う。

主な役割は以下の 3 つ。

  • 制限 (Limiting): CPU・メモリなどの使用量に上限を設ける
  • 計測 (Accounting): グループ内のリソース使用量を追跡する
  • 制御 (Controlling): プロセスの一時停止・再開などを行う

プロセスは必ずいずれかの cgroup に属しており、子プロセスは親の cgroup を継承する。

##サブシステム (コントローラ)

cgroups はリソース種別ごとに コントローラ (サブシステム) と呼ばれる独立した機能として分かれている。

cat /proc/cgroups
#subsys_name	hierarchy	num_cgroups	enabled
cpuset	0	75	1
cpu	0	75	1
cpuacct	0	75	1
blkio	0	75	1
memory	0	75	1
devices	0	75	1
freezer	0	75	1
net_cls	0	75	1
perf_event	0	75	1
net_prio	0	75	1
hugetlb	0	75	1
pids	0	75	1
rdma	0	75	1
misc	0	75	1
コントローラ概要
cpuCPU 時間のスケジューリングと使用率の制限
cpuset使用する CPU コアや NUMA ノードの割り当て
memoryメモリ・スワップの使用量制限と計測
blkioブロックデバイスへの I/O 帯域の制限 (v1)
ioブロック I/O の制限 (v2 での名称)
pidsグループ内で生成できるプロセス数の制限
net_clsネットワークパケットへのクラス ID 付与
freezerグループ内プロセスの一時停止・再開

##/sys/fs/cgroup の構造

cgroups は仮想ファイルシステムとして /sys/fs/cgroup に公開されている。ファイルを読み書きすることでリソース設定の確認・変更が行える。

# v2 の場合のディレクトリ構造 (例)
/sys/fs/cgroup/
├── cgroup.controllers     # 利用可能なコントローラ一覧
├── cgroup.procs           # このグループに属するプロセスの PID 一覧
├── memory.max             # メモリ上限
├── cpu.max                # CPU 使用率上限
└── mygroup/               # 作成したサブグループ
    ├── cgroup.procs
    ├── memory.max
    └── cpu.max

各ファイルの意味はコントローラごとに決まっており、例えば memory.max はそのグループのメモリ上限 (バイト) を表す。

##基本的な操作

cgroups v2 はディレクトリとファイルの操作だけで管理できる。

# サブグループを作成
mkdir /sys/fs/cgroup/mygroup

# メモリ上限を 256MB に設定
echo "268435456" > /sys/fs/cgroup/mygroup/memory.max

# CPU 使用率を 50% に制限 (100ms 周期で 50ms まで)
echo "50000 100000" > /sys/fs/cgroup/mygroup/cpu.max

# プロセスをグループに追加 (PID を書き込む)
echo $$ > /sys/fs/cgroup/mygroup/cgroup.procs

# グループの削除 (プロセスがいない状態で)
rmdir /sys/fs/cgroup/mygroup

systemd 環境では systemd-cglssystemctl set-property 経由で操作することも多い。

# cgroup ツリーを表示
systemd-cgls

# サービスのメモリ上限を設定
sudo systemctl set-property nginx.service MemoryMax=512M

##コンテナとの関係

Namespace がプロセスの「見え方」を分離するのに対し、cgroups は「リソース使用量」を制限する。Docker などのコンテナランタイムはこの両者を組み合わせている。

# Docker コンテナにメモリ・CPU 制限を付けて起動
docker run --memory="256m" --cpus="0.5" ubuntu:22.04

# コンテナの cgroup を確認 (v2 環境)
# /sys/fs/cgroup/system.slice/docker-<container_id>.scope/ 以下に作成される
cat /sys/fs/cgroup/system.slice/docker-$(docker ps -q | head -1).scope/memory.max

コンテナに --memory--cpus オプションを渡すと、ランタイムが対応する cgroup ファイルに値を書き込む仕組みになっている。