5-1. cgroupとcgroupfs
ここからはcgroup (Control Group) を使ったリソース制限を実装していきます。
実装に入る前に、cgroupについて深掘りしてみましょう。
cgroup (Control Group)
cgroupは、特定のプロセス群にリソース制限をかけるための機構です。
cgroupには、複数のプロセスを所属させることができ、そのプロセスが合計で使うリソースに制限をかけることができます。
現在のcgroup (v2) では、以下のようなリソースに対して制限がかけられます。
それぞれのリソースに制限をかける機構はコントローラーと呼ばれ、利用者はそれぞれのコントローラーに対して制限を設定します。
cpu: CPU時間の配分・上限memory: メモリ・スワップの使用量上限io: ブロックI/Oの制限pids: プロセス・スレッド数の上限cpuset: 使用CPU・NUMAノードの割り当てfreezer: プロセス群の凍結・再開hugetlb: Huge Pageの使用量制限
Namespaceで区切るリソースと、cgroupで制限するリソースの違いをなんとなく感じていただければ幸いです。
cgroupのバージョン
cgroupにはv1とv2が存在します。
- v1
- コントローラーごとに個別の階層をマウントする方式
- Linux 2.6.24から
- v2
- すべてのコントローラーを単一階層で管理する方式
- Linux 3.10から実験的、Linux 4.5から正式
cgroup v2は、v1の階層設計上の課題を解決するために設計された後継で、現在cgroupを扱う場合は基本的にv2が前提となります。
現在ほとんどのコンテナランタイムがv2をデフォルトで使うようになっており、今回のハンズオンもv2を前提に進めます。
cgroupfs
ここからは、cgroup v2を前提に解説します。
cgroupfsは、cgroupを管理するための仮想ファイルシステムです。
通常は/sys/fs/cgroupディレクトリにマウントされ、このディレクトリがcgroupのルート階層となります。
cgroupの階層構造
cgroupは、階層構造を持つことが特徴です。
入れ子構造になっており、親cgroupの制限は子cgroupにも引き継がれます。
/sys/fs/cgroup
├── system.slice
│ └── service-a.slice
└── user.slice
└── user-1000.slice
└── container.slice例えば、system.sliceにメモリ上限を設定すると、その配下にある service-a.sliceと、そこに所属するプロセスはその制限を受けます。
つまり、子cgroupとそこに所属するプロセスのリソース使用量の合計が、親cgroupに設定された制限を超えないように制御されます。
cgroupの制御ファイル
cgroupfsの各ディレクトリには、そのcgroupに対するあらゆるコントローラー設定用のファイルが存在します。
例えば、以下のようなファイルがあります。
| ファイル | 役割 | 例 |
|---|---|---|
cgroup.controllers | 利用可能なコントローラーの一覧 | cpu memory io |
cgroup.subtree_control | 子cgroupで有効にするコントローラー | +cpu +memory |
cgroup.procs | cgroupに所属するプロセスのPID | 1234 |
cpu.max | CPU使用時間の上限 | 50000 100000 |
memory.max | メモリ使用量の上限 | 512M |
memory.current | 現在のメモリ使用量 | 104857600 |
これらのファイルに対して設定を書き込むことで、cgroupの制御が可能です。