設問と前提コンテキスト
cgroup v2を使用するLinuxホストにおいて、コンテナAには以下の演習制約が設定されています。
| 制約 | 具体的なcgroup v2の値 |
|---|---|
| メモリ | memory.max = 536870912 バイト(512 MiB) |
| CPU | cpu.max = 50000 100000(100 msごとに最大50 ms) |
| タスク数 | pids.max = 128 |
コンテナ内部では、アプリケーションは自身をPID 1、コンテナホスト名、独自のマウントテーブル、独自のネットワークインターフェースを持つものとして認識します。ランタイムがその環境をどのように作成するか、分離が実際にどこから生じているか、制限超過がどのように現れるかを説明してください。次に、共有カーネルのセキュリティ境界について説明し、docker run の成功だけでなく、観測可能なカーネル状態を用いて設定を証明してください。
この質問は、Linux、プラットフォーム、SRE、DevOps、インフラストラクチャ、クラウド、セキュリティ、バックエンドの各職種に適用されます。提示された値は面接用の制約であり、推奨されるデフォルト値ではありません。「コンテナ」とはLinux OCIスタイルのプロセスコンテナを指し、VMベースのコンテナ製品は異なる分離レイヤーを追加します。
面接官が評価しているポイント
第1のテストは、候補者が「軽量なVM」というフレーズを正確なプロセスモデルに置き換えられるかどうかです。Linuxコンテナはホスト上のプロセスツリーです。namespaceは、それらのプロセスが参照できるグローバルリソース(PID、マウント、ネットワークオブジェクト、IPCオブジェクト、ホスト識別情報、ユーザーID、cgroupパス、およびオプションでクロック)を変更します。ルートファイルシステムとプライベートなマウントビューがユーザー空間イメージを提供します。これらのいずれも、第2のカーネルを作成するわけではありません。
第2のテストは、可視性とリソース制御の分離です。namespaceは「このプロセスがどのインスタンスを観測または変更できるか?」に答えます。cgroupは「このグループがどれだけ消費でき、どのように計上されるか?」に答えます。PID namespaceはタスク数を制限しません。cgroupのPID制限はホストプロセスを隠しません。マウントnamespaceはマウントビューを変更し、rootfsはファイルを提供します。chroot 単体では、完全なコンテナでもセキュリティ境界でもありません。
第3のテストは、正確なcgroup v2ファイルから挙動を導き出すことです。memory.max はメモリのハード境界であり、回収(reclaim)が失敗した後にcgroupローカルのOOM killを引き起こす可能性があります。cpu.max は帯域幅制御です。100 msの期間中に50 msを消費した後は、クォータが利用可能になるまで実行可能な処理がスロットリングされます(killはされません)。pids.max は、制限に違反する fork() または clone() を EAGAIN で拒否します。候補者は、これらの結果を区別するイベントカウンターを挙げられる必要があります。
第4のテストは、セキュリティに関する判断力です。コンテナはホストカーネルを共有しているため、namespaceとcgroupはVMの境界と同等ではありません。ユーザーIDマッピング、最小限のcapabilityセット、no_new_privs、seccomp、AppArmorやSELinuxなどのLSM、読み取り専用またはマスクされたマウント、制限されたデバイスによって攻撃対象領域を削減します。特権(privileged)コンテナ、ホストのPID/ネットワークnamespace、Dockerソケット、広範なホストマウントは、意図せず重要な境界を取り払ってしまう可能性があります。
最後に、面接官は検証計画を求めています。回答では、境界の両側からnamespaceのinode識別情報、UID/GIDマッピング、cgroupの所属関係とコントローラーファイル、プロセスのcapability、seccomp状態、マウントの伝播(propagation)、ネットワークインターフェース、失敗カウンターを比較する必要があります。
回答前に確認すべき明確化のための質問
- どのランタイムおよびコンテナモードが対象ですか? Linux上のOCIランタイムを想定しています。rootlessモード、user namespaceのリマッピング、特権モード、VMベースのサンドボックスはトラストバウンダリを変化させます。
- 「0.5 CPU」はクォータを意味しますか、それとも相対的な重み(weight)ですか? ここでは、100,000マイクロ秒の期間あたり50,000マイクロ秒の帯域幅上限を意味します。
cpu.weightは競合時の相対的な配分のみを変更します。 - 512 MiBには何が含まれますか? cgroup v2は匿名メモリ、ページキャッシュ、カーネル構造体、ソケットバッファなどの主要な消費を計上しますが、すべてのホストリソースがこの単一ファイルで制御されるわけではありません。
- 128はプロセス数ですか、それともカーネルタスク数ですか? pidsコントローラーはカーネルタスクIDを使用するため、スレッドも予算を消費します。この詳細は、多数のスレッドを使用するランタイムにおいて重要です。
- スワップは有効化され、個別に制限されていますか?
memory.maxとmemory.swap.maxは異なる制御です。設問ではメモリ制限のみが固定されているため、スワップポリシーは推測するのではなく確認する必要があります。 - 実際にどのnamespaceが設定されていますか? OCI設定では、namespaceの新規作成、パス指定による既存namespaceへの参加、またはタイプの省略によるランタイムのnamespaceの継承が可能です。1つでも欠落していれば、実際の境界が変化します。
- 脅威モデルは何ですか? 悪意のある可能性のあるマルチテナントワークロードでは、プロセス分離に加えてVMまたはマイクロVM境界が必要になる場合があります。信頼できる内部ワークロードであれば、異なるバランスを受け入れることができます。
30秒の簡潔な回答フレームワーク
「Linuxコンテナとは、rootfsに対して起動され、選択されたnamespaceとcgroup内に配置されたホストプロセスツリーであり、ホストカーネルは共有されたままとなります。namespaceがビューを分離し、cgroupが消費量を計上および制限します。本設問では、memory.max=536870912 はメモリ回収失敗後にcgroup OOMを引き起こす可能性があり、cpu.max=50000 100000 は100 msあたり50 msの消費後にfairクラスの処理をスロットリングし、pids.max=128 は制限を超えるforkやcloneを EAGAIN で拒否します。
適切であればUIDマッピング、最小限のcapability、no_new_privs、seccomp、AppArmorやSELinuxのポリシー、安全なマウント、制限されたデバイスを追加します。両側からnamespaceの識別情報、UIDマップ、マウント、インターフェース、有効なcgroupファイル、capability、セキュリティ状態を検証し、その後、境界テストを実行して一致する memory.events、cpu.stat、pids.events の証拠を確認します。」
ステップバイステップの詳細解説
ステップ1:ホストプロセスモデルから始める
ランタイムはルートファイルシステムと設定を含むOCIバンドルを受け取ります。代表的なセットアップ手順は次のとおりです。
- バンドル、実行可能ファイル、マウント、namespaceの選択、認証情報、リソース設定を検証する。
- cgroupサブツリーを作成または選択し、コントローラーの値を書き込む。
- 新しいnamespaceを作成するか、設定された既存のnamespaceに参加する。
- user namespaceが使用されている場合は、UID/GIDマッピングを確立する。
- マウント伝播を安全にし、rootfsと特殊ファイルシステムをマウントして、プロセスのルートを切り替える。
- 新しいネットワークnamespaceが使用されている場合、ネットワークデバイスを作成または移動し、ルートを設定する。
- 認証情報、capability、
no_new_privs、seccomp、LSMラベルまたはプロファイルを構成する。 - プロセスをcgroupにアタッチし、設定されたアプリケーションを
execする。
正確な順序やヘルパープロセスはランタイムによって異なります。不変なのは観測可能なカーネル状態です。アプリケーションは、namespaceの所属、認証情報、マウント、フィルター、cgroupパスを持つ、ホストによってスケジュールされるプロセスのままであり続けます。部分的なセットアップ後にランタイムがクラッシュした場合、クリーンアップ処理によってマウント、インターフェース、namespaceピン、cgroupを削除する必要があります。「コンテナ」という用語は、自動的にクリーンアップを実行するカーネルオブジェクトではありません。
ステップ2:各namespaceに1つの責務を割り当てる
主要なnamespaceは相互に補完し合います。
| Namespace | 分離されるビュー | 重要な境界 |
|---|---|---|
| PID | プロセスID番号空間と可視性 | 同じタスクが内部PIDとホストPIDを持つ。コンテナのPID 1は子プロセスを回収(reap)し、シグナルを適切に処理する必要がある |
| Mount | マウントポイントと伝播 | マウントテーブルを変更するものであり、基盤となるカーネルやバッキングストレージを自動的に変更するわけではない |
| Network | インターフェース、ルート、ポート、ソケット、ネットワークスタック | vethペア、ブリッジ、ルーティング、または別のネットワークドライバーによって接続性が意図的に再導入される |
| UTS | ホスト名およびNISドメイン名 | 識別情報の提示であり、認証ではない |
| IPC | System V IPCおよびPOSIXメッセージキュー | マウントを通じて意図的に共有されたファイルやソケットはワークロードを接続し得る |
| User | UID/GIDマッピングおよびnamespaceスコープのcapability | 内部のUID 0を特権のないホストUIDにマッピングできる |
| Cgroup | cgroup階層のビュー | リソースの強制はコントローラーから行われ、cgroup namespaceビューから行われるわけではない |
| Time | ブートクロックおよびモノトニッククロックのオフセット | 任意の独立したウォールクロックハードウェアを提供するわけではない |
OCIのnamespaceリストから省略されたnamespaceタイプは、ランタイムから継承されます。--pid=host、ホストネットワーキング、または他のコンテナのnamespaceへの参加は意図的な場合もありますが、回答では完全にプライベートなコンテナとして説明し続けるのではなく、失われた分離性を指摘しなければなりません。
ファイルシステムの境界には、マウントnamespaceとrootfsの両方が必要です。privateまたはslaveの伝播モードにより、コンテナのマウントイベントがホストへ予期せず伝播するのを防ぎます。読み取り専用マウント、マスクされたパス、最小限の /dev、明示的なバインドマウントによってアクセスを絞り込みます。ホストのルートやコンテナエンジンのソケットを書き込み可能でバインドマウントすると、プロセスのプライベートなホスト名に関係なく、直接的で重大な侵害経路が作られます。
ステップ3:3つのリソース制限の結果を導き出す
メモリ: memory.max=536870912 は、cgroupとその子孫に対する主要なハードリミットです。使用量が制限に近づくと、カーネルは回収(reclaim)を試みます。使用量が制限に達し削減できない場合、cgroupはOOM処理に入ります。デフォルトモードでは、OOMキラーはそのcgroup内のタスクを選択する可能性があり、memory.oom.group=1 は1つの不可分なワークロードとしての処理を要求できます。一時的に制限を超える読み取り値が発生することもあります。memory.current、memory.peak、および memory.events 内の max、oom、oom_kill、oom_group_kill フィールドを確認してください。これらのカウンターやカーネル/ランタイムの証拠なしに、すべての SIGKILL をcgroup OOMと診断してはなりません。
CPU: cpu.max=50000 100000 は、グループ内のfairクラスのタスクが各100,000マイクロ秒の期間中に最大50,000マイクロ秒消費できること(平均帯域幅0.5 CPU)を意味します。複数のスレッドがクォータを並行して消費し、期間の早い段階で使い切る可能性があります。その場合、実行可能なタスクはクォータが利用可能になるまでスロットリングされます(強制終了はされません)。cpu.stat 内の usage_usec、nr_periods、nr_throttled、throttled_usec を調査してください。したがって、期間の境界付近でのレイテンシスパイクは、ホストCPUに空きがある場合でもクォータのスロットリングである可能性があります。
タスク: pids.max=128 は、カーネルタスクに対する階層的なハードリミットです。スレッドもカウントされます。新しいタスクがポリシーに違反する場合、fork() または clone() は EAGAIN で失敗します(既存のタスクは実行を継続します)。pids.current、pids.peak、および pids.events 内の max カウントを調査してください。既存のタスクを移動したり、設定された制限を下げたりすると、一時的に pids.current > pids.max となることがありますが、ポリシーに違反する新規作成は依然としてブロックされます。
親cgroupも子cgroupを制約します。子は、その祖先が許可していないCPU、メモリ、またはタスク容量を取得することはできません。逆に、これら3つの設定がすべてのリソースを自動的に制限するわけではありません。ストレージ容量、I/O、ファイルディスクリプタ、ネットワーク帯域幅、デバイス、カーネルグローバルオブジェクトには、それぞれの制御と運用上の制限が必要です。
ステップ4:共有カーネルの周囲にセキュリティ制御を階層化する
user namespaceを使用すると、プロセスは内部でUID 0でありながら、外部では通常の非特権UIDにマッピングされます。これにより、namespaceエスケープやホストファイルへの誤ったアクセスの影響が軽減されますが、マッピングとファイルシステムの所有権は一緒に設計する必要があります。user namespaceがない場合、capabilityやアクセス可能なオブジェクトが制限されていたとしても、コンテナ内のrootは依然としてホストのUID 0です。
capabilityは従来のroot特権を分割します。すべてのcapabilityを付与するのではなく、最小限のセットから開始します。capabilityの破棄は、ファイルcapability、set-user-IDの実行、または別の経路を通じてプロセスがそれを再取得できない場合にのみ有用です。制限されたセットと no_new_privs により、その意図を監査可能にします。
seccompはシステムコールをフィルタリングし、呼び出しと引数に基づいて許可、拒否、トラップ、強制終了、ログ記録、または通知を行うことができます。これにより到達可能なカーネル攻撃面が減少しますが、アプリケーションレベルの認可は理解しません。AppArmorやSELinuxなどのLSMは、ファイル、プロセス、ソケット、その他のオブジェクトに対する操作にポリシーを適用します。読み取り専用ファイルシステム、マスクされた /proc パス、最小限のデバイスセットが独立した制約を追加します。
これらは多層防御のレイヤーであり、相互の代替ではありません。cgroupは主にアカウンティングとリソースのサービス拒否(DoS)に対処するものであり、あるコンテナが別のコンテナのデータを読み取るのを防ぐものではありません。namespaceは主にビューを分離するものであり、共有カーネルにパッチを当てるものではありません。悪意のある可能性のあるテナントの場合、カーネルエクスプロイトのリスクやコンプライアンス要件により、VM、マイクロVM、またはサンドボックス化されたカーネル境界が正当化される場合があります。
ステップ5:両側からカーネル状態を検証する
ホスト側から、まずコンテナのinitプロセスとcgroupパスを特定します。一般的な調査の概要は以下のとおりです。
pid=<host-pid-of-container-init>
cg=/sys/fs/cgroup/<container-cgroup>
readlink /proc/$pid/ns/{pid,mnt,net,uts,ipc,user,cgroup}
cat /proc/$pid/uid_map
cat /proc/$pid/gid_map
cat /proc/$pid/cgroup
cat "$cg/memory.current" "$cg/memory.max" "$cg/memory.events"
cat "$cg/cpu.max" "$cg/cpu.stat"
cat "$cg/pids.current" "$cg/pids.max" "$cg/pids.events"
grep -E '^(CapPrm|CapEff|CapBnd|NoNewPrivs|Seccomp):' /proc/$pid/statusnamespaceのシンボリックリンクのデバイス/inode識別情報を、ホストおよび別のコンテナと比較します。識別情報が異なることは、異なるnamespaceインスタンスであることを証明しますが、それ単体でマウント、ルート、ポリシーの安全性を証明するわけではありません。実際のマウントテーブルと伝播、ネットワークリンクとルート、実効capabilityセット、seccompモード、LSMラベル、デバイスノードを調査します。
コンテナ内部から、/proc/1/status、/proc/self/cgroup、mount、hostname、可視プロセス、インターフェース、ルート、UID/GID、namespaceリンクを記録します。認可されたホストからの nsenter は診断のみに使用してください。namespaceへの侵入は特権アクセスであり、境界が破綻したことの証拠ではありません。
最後に、使い捨ての環境で制限付きの障害テストを実行します。メモリを徐々に割り当てて失敗を memory.events と相関させます。CPU負荷を実行してレイテンシを nr_throttled と相関させます。次の作成が EAGAIN を返し pids.events がインクリメントされるまでスレッドまたはプロセスを作成します。ホストレベルのプレッシャーが発生する前にテストを停止し、兄弟cgroupが正常な状態を維持していることを確認します。
ステップ6:観測結果を受け入れ基準に変換する
妥当性のある受け入れ記録には、値、識別情報、および結果が含まれます。
- 分離が必要な箇所ではnamespace IDが異なり、意図的な共有がある箇所でのみ一致していること。
- UID 0のマッピング、実効capability、
NoNewPrivs、seccompモード、LSMラベルが脅威モデルと一致していること。 - マウント伝播、バインドマウント、マスクされたパス、書き込み可能なパス、デバイスアクセスがOCI設定と一致していること。
- 有効なcgroupにおいて、
memory.max、cpu.max、pids.maxがそれぞれ536870912、50000 100000、128と等しいこと。 - メモリプレッシャーによって関連するメモリエントカウンターが変化し、CPU負荷によってタスクをkillすることなくスロットリングカウンターが増加し、128タスクがすでに課金されている場合に129番目のタスク作成が拒否されること。
- 各テスト中、親および兄弟のcgroupが自身の予算内に収まっていること。
- 再起動および強制終了テストにおいて、予期しないマウント、インターフェース、namespaceピン、タスクが存在するcgroupが残らないこと。
129番目のタスクに関する記述は、有効な階層に正確に128タスクがすでに課金されており、並行して終了するタスクがないことを前提としています。実際のテストでは、アプリケーションのタスクが1つであると仮定せず、作成直前に pids.current を読み取ってください。
優れた回答例
「まず、ホストプロセスモデルから説明します。ランタイムはOCIのrootfsと設定を受け取り、要求されたPID、mount、network、UTS、IPC、user、cgroup、timeの各namespaceを作成または参加させ、マウントとネットワークを設定し、プロセスツリーをcgroupにアタッチし、認証情報とセキュリティポリシーを適用して、アプリケーションをexecします。内部のPID 1は、外部では別のPIDを持つホストプロセスにすぎません。コンテナは専用のユーザー空間ビューを持ちますが、ホストカーネルは共有されたままです。
namespaceとcgroupは異なる問題を解決します。PID namespaceはプロセスの可視性を変更し、mount namespaceとrootfsは可視ファイルシステムを変更し、network namespaceは専用のインターフェース、ルート、ポート、ソケットを提供します。user namespaceは内部のUID 0を特権のないホストUIDにマッピングできます。cgroupはプロセスツリーを計上および制御しますが、ホストオブジェクトを隠すことはありません。
提示されたcgroup v2の値について、memory.max=536870912 は512 MiBのハード境界です。カーネルは回収を試み、使用量を削減できない場合はcgroup OOM処理を呼び出すことがあります。memory.events を確認して max、oom、oom_kill を区別します。cpu.max=50000 100000 はfairクラスの処理に対して100 msあたり最大50 msを供給します。クォータが使い果たされると、利用可能になるまで実行可能なタスクはスロットリングされ、cpu.stat は nr_throttled と throttled_usec を報告します(CPU制限によるkillはありません)。pids.max=128 はスレッドを含むカーネルタスクをカウントします。制限に違反するforkまたはcloneは EAGAIN を返し、pids.events がその到達を記録します。
カーネルが共有されているため、適切であればuser namespace、最小限のcapabilityセット、no_new_privs、seccomp、AppArmorまたはSELinuxポリシー、読み取り専用またはマスクされたマウント、最小限のデバイスセットを階層化します。明示的で信頼できる要件がない限り、特権モード、ホストnamespace、広範なホストマウント、エンジンソケットへのアクセスは拒絶します。悪意のあるマルチテナンシーには、VMまたはマイクロVM境界が必要になる場合があります。
検証にあたっては、ホストとコンテナの両側から /proc/{PID}/ns/* のデバイス/inode識別情報、UID/GIDマップ、マウント、インターフェース、cgroupパス、有効なコントローラーファイル、capability、seccompモード、LSMラベルを比較します。次に、制約をかけたメモリ、CPU、タスクのテストを実行し、一致するカーネルカウンターと障害モードを確認します。単に起動しただけのコンテナは、分離を証明したことにはなりません。」
よくある間違いと改善策
- コンテナを小さなVMと呼ぶ → 共有カーネルが見えなくなり、誤ったセキュリティ前提を生む → namespace、cgroup、ファイルシステム、認証情報、ポリシー状態を持つホストプロセスとして説明する。
- namespaceがCPUとメモリを制限すると述べる → namespaceはビューを分離するものであり、消費を制限するものではない → リソース制限をcgroupコントローラーとファイルに対応付ける。
- cgroupがファイルやプロセスを分離すると述べる → cgroupはタスクをグループ化、計上、制約する → 可視性をPIDおよびmount namespaceに対応付ける。
chrootをコンテナとして扱う → 見かけのルートを変更してもPID、ネットワーク、ユーザー、リソースの分離は追加されない → rootfsをmountおよびその他の必要なnamespace、さらにポリシーと組み合わせる。- CPU制限がプロセスをkillすると主張する → CPUクォータは通常、実行可能なfairクラスの処理をスロットリングする → スロットリングの確認には
cpu.statをチェックする。 - メモリ使用量が正確に512 MiBで止まることを期待する → 回収、計上のタイミング、一時的な超過により瞬間的な読み取り値は複雑になる →
memory.maxとイベントカウンターを使用して強制された結果を特定する。 pids.maxに対してプロセスのみをカウントする → コントローラーはカーネルタスクをカウントするため、スレッドも消費する → 制限テストの前にpids.currentを調査する。- コンテナ内のrootは無害であると仮定する → user namespaceがなければホストのUID 0のままであり、他の制御によってのみ制約される →
uid_mapとcapabilityを調査する。 - namespaceによる分離をセキュアなテナント境界と同等とみなす → カーネルの脆弱性や危険なホストマウントはプロセス境界を越える可能性がある → 脅威モデルを明示し、ポリシーまたはVM境界を追加する。
- 設定のみを確認し、実効状態を確認しない → ランタイムフラグは上書きされたり継承されたり、部分的に失敗したりする可能性がある →
/procとcgroupファイルを読み取り、各制限を実際にテストする。
フォローアップの質問
フォローアップ1:コンテナ内でPID 1に特別な処理が必要なのはなぜか?
PID namespaceの最初のプロセスは、その子孫に対してPID 1として見えます。これは孤立した子プロセスを養子(adopt)として引き取り、回収(reap)しなければなりません。そうしないとゾンビプロセスが蓄積し、pidsの予算を消費します。また、PID 1には特別なシグナル処理のセマンティクスがあるため、シグナルを転送しないラッパーを使用すると正常な終了(graceful termination)が失敗する可能性があります。アプリケーションフレームワークがこれらを処理していると思い込まず、実際のinitプロセス、子の回収、シグナル転送、シャットダウンのタイムアウトを検証してください。
フォローアップ2:cpu.max と cpu.weight の違いは何か?
cpu.max はfairクラスの処理に対して期間あたりの最大帯域幅を設定します。該当グループが現在のクォータを使い切った後は、ホストにアイドルCPUがある場合でもcgroupをスロットリングできます。cpu.weight は競合時に実行可能な兄弟cgroup間での比例的な優先度であり、それ自体で0.5 CPUのハード上限を定義するものではありません。本番環境のポリシーでは、異なる目的のために両方を使用することがあります。
フォローアップ3:コンテナのrootはホスト上で非特権になり得るか?
はい。user namespaceが内部のUID 0を外部の非特権UID範囲にマッピングしている場合に可能です。/proc/{PID}/uid_map と /proc/{PID}/gid_map でマッピングを確認してください。これによりホスト特権は絞り込まれますが、バインドマウントの所有権、下位ID(subordinate ID)の割り当て、所有user namespace内でのcapability、カーネル攻撃面については依然としてレビューが必要です。
フォローアップ4:ファイルシステムのセキュリティにおいてプライベートなmount namespaceだけでは不十分なのはなぜか?
マウントテーブルは分離されますが、そこにどのバッキングファイルシステムやバインドマウントを表示するかはランタイムが決定します。/ の書き込み可能なバインドマウントを含むプライベートnamespaceは、依然としてホストルートを公開してしまいます。マウント元、伝播、書き込み可能フラグ、マスクされたパスおよび読み取り専用パス、デバイスノード、プロセスの認証情報およびLSMポリシーを総合的にレビューしてください。
フォローアップ5:VMまたはマイクロVMを選択すべきなのはどのような場合か?
相互に信頼できないテナントが任意のコードを実行する場合、共有カーネルエスケープが許容リスクを超える場合、コンプライアンス上カーネルの完全な分離が求められる場合、またはカーネルバージョンやモジュールが異なる必要がある場合は、より強力な境界を選択してください。トレードオフとして、起動時間、メモリ、イメージサイズ、運用のオーバーヘッドが増加します。この判断は、コンテナかVMかというラベルだけでなく、脅威モデルと計測されたプラットフォームの制約に従って下されます。
フォローアップ6:OOM killされていないが動作が遅いコンテナをどのように診断するか?
アプリケーションのレイテンシと、cpu.stat のスロットリング、memory.events のhigh/maxプレッシャー、Pressure Stall Information(PSI)、I/Oコントローラーの統計、ホストのスケジューリング、ネットワークエラーを相関させます。OOMカウンターが安定している状態で nr_throttled または throttled_usec が増加している場合は、CPUクォータが原因であることを示唆しています。メモリ回収やI/Oプレッシャーもプロセスをkillすることなく処理を失速(stall)させる可能性があるため、診断にはタイムスタンプと有効なcgroupの階層関係を揃える必要があります。