【ITニュース解説】Kubernetes: Pod resources.requests, resources.limits and Linux cgroup
2025年09月15日に「Dev.to」が公開したITニュース「Kubernetes: Pod resources.requests, resources.limits and Linux cgroup」について初心者にもわかりやすく解説しています。
ITニュース概要
KubernetesのPodリソース設定(requests/limits)は、コンテナが利用できるCPUやメモリの量と優先度をLinuxのcgroupを通じて制御する。requestsはリソース保証と優先度、limitsは最大使用量を決定する。CPU limitsは過度なスロットリングを引き起こす可能性があり、注意が必要だ。
ITニュース解説
KubernetesのPodを扱う上で、resources.requestsとresources.limitsは非常に重要な設定項目である。これらはPodがどれだけのリソース(CPUやメモリ)を要求し、どれだけ使用できるかの最大値を定義するが、その裏側ではLinuxカーネルの「cgroup(コントロールグループ)」という仕組みが密接に関わっている。この解説では、それらがどのように連携し、コンテナのリソースが実際に管理されているのかを初心者にもわかりやすく説明する。
まず、KubernetesのPodで設定するresources.requestsとresources.limitsについてである。resources.requestsは、Podが起動する際に「これくらいのリソースが欲しい」とKubernetesに伝える値である。これは主に、Podをどのノード(Kubernetesクラスタ内のサーバー)に配置するかを決める際の基準となり、またPodに最低限保証されるリソース量を示す。一方、resources.limitsは、Podが「最大でこれ以上のリソースは使わない」という上限値である。この上限を超えてリソースを使おうとすると、Linuxカーネルによって制限がかけられる。具体的には、メモリのlimitsを超過すると、システム全体のメモリが不足している場合にそのPodは「OOMKiller(Out Of Memory Killer)」によって強制終了される可能性がある。CPUのlimitsを超過すると、「CPUスロットリング」という状態になり、CPUの処理速度が意図的に抑制される。
これらのリソース制限や保証を実際に実現するのが、Linuxカーネルのcgroupという機能である。cgroupは、OS上で動作するプロセスをグループ化し、そのグループに対してCPU、メモリ、ネットワーク、ディスクI/Oといったシステムリソースの使用量を制御する仕組みである。cgroupの大きな特徴は、プロセスが親子関係のような階層構造でグループ化される点である。親グループに設定されたリソース制限は、その子グループ全体に適用されるため、複数のコンテナやアプリケーションが協調してリソースを消費する状況で全体のバランスを保つことができる。これらのcgroupに関する設定ファイルは、Linuxシステムの/sys/fs/cgroup/ディレクトリ以下に配置されている。
cgroupにはバージョン1とバージョン2があり、現在ではcgroup v2が新しい標準として利用されることが多い。cgroup v2では、リソース制御の考え方やファイル名が整理され、より統一的な管理が可能になっている。例えば、CPUの時間配分はcpu.maxファイルで、メモリの上限はmemory.maxファイルで設定される。cpu.maxは「quota(割り当て時間)」と「period(期間)」という二つの値で構成される。例えば、100ミリ秒の期間のうち50ミリ秒までしかCPUを使えないように設定すれば、そのプロセスグループは50ミリ秒ごとに最大100ミリ秒のCPU時間を割り当てられることになる。
Kubernetesのresources.limits.cpuは、このcgroupのcpu.maxに直接対応する。例えば、PodにCPUリミットを1コア(1000ミリコア)と設定した場合、cgroupでは100ミリ秒の期間につき100ミリ秒のCPU時間を使用できるような設定になる。しかし、このCPUリミットの設定は、場合によってはパフォーマンスを低下させる可能性があるため、設定しないほうが良いとされる場合がある。なぜなら、たとえシステム全体に十分なCPUリソースが残っていても、cgroupで設定された割り当て時間を使い切ってしまうと、そのプロセスは一時的に停止させられてしまう(スロットリングされる)からである。これは、システムのアイドル状態が続いているときでも、設定された上限を超えるとプロセスが待たされてしまうことを意味する。
一方、resources.requests.cpuは、cgroupのcpu.weight(cgroup v2の場合)またはcpu.shares(cgroup v1の場合)という設定に対応する。これは、複数のプロセスグループが同時にCPUリソースを要求して競合する場合に、どのグループにCPU時間をより多く割り当てるかを決めるための相対的な優先度を示す値である。Linuxカーネルの「Completely Fair Scheduler(CFS)」というCPUスケジューラは、このcpu.weightの値に基づいて、各グループにCPU時間を公平に、かつ優先度に応じて比例配分する。つまり、CPUが忙しいときに、cpu.weightの値が高いプロセスグループほど、より多くのCPU時間を獲得できる。ただし、システムに十分なCPUリソースがある場合は、すべてのプロセスが必要なだけCPU時間を使えるため、cpu.weightの影響は小さくなる。
KubernetesのCPU単位は、1CPUユニットが1物理コアまたは1仮想コアに相当し、1000ミリコアと表現される。この1CPUユニットは、cgroupの内部では1024 CPU sharesという値に変換される。Kubernetesは、このように設定されたrequestsやlimitsの値を、ノード上でコンテナを起動する「コンテナランタイム(ContainerDやCRI-Oなど)」に渡し、コンテナランタイムがその情報をcgroupの設定へと変換する。具体的には、Podがデプロイされると、ノード上の/sys/fs/cgroup/kubepods.slice/以下にそのPodに対応するcgroupディレクトリが作成され、その中にcpu.maxやcpu.weight、memory.maxといったファイルが生成され、Kubernetesの指定に応じた値が書き込まれる。
例えば、Podにresources.requests.cpu: "1"と設定すると、cgroupのcpu.sharesは1024となる。これがcgroup v2のcpu.weightに変換される際、特定の計算式に基づいてより小さな値(例:39)となるが、これは他のcgroupとの相対的な割合を定めるための内部的な変換である。
また、KubernetesにはPodの「QoSクラス(Quality of Service Class)」という概念がある。これはrequestsとlimitsの設定状況によって「Guaranteed(保証済み)」「Burstable(バースト可能)」「BestEffort(ベストエフォート)」の3種類に分類される。例えば、requestsとlimitsが両方設定されており、かつ両者の値が等しいPodはGuaranteed QoSクラスに分類される。このQoSクラスは、システム全体のメモリ不足時にどのPodから終了させるか、あるいはどのcgroupにリソースを多く割り当てるかといった、ノード上でのPodの振る舞いに影響を与える重要な要素である。それぞれのQoSクラスに対応するcgroupのサブディレクトリが/sys/fs/cgroup/kubepods.slice/以下に作成され、そこに属するPodのリソースが管理される。
まとめると、Kubernetesのresources.requestsとresources.limitsという設定は、見た目以上に深いところでLinuxカーネルのcgroupと連携している。requestsは主にCPU競合時の優先度(cpu.weight)とPodの配置(resources.requests.memory)に影響し、limitsはリソースの上限(cpu.max, memory.max)を定め、超過時にはスロットリングやOOMKillerの対象となる。これらの連携によって、Kubernetesは複数のコンテナが混在する環境下でも、安定したリソース管理とパフォーマンスの制御を実現しているのである。