Skip to content

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にも引き継がれます。

plaintext
/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.procscgroupに所属するプロセスのPID1234
cpu.maxCPU使用時間の上限50000 100000
memory.maxメモリ使用量の上限512M
memory.current現在のメモリ使用量104857600

これらのファイルに対して設定を書き込むことで、cgroupの制御が可能です。