Kubernetes の OOMKilled エラー:原因と解決策
冒頭まとめ OOMKilled は、コンテナがメモリの都合で外から止められたことを示します。ただし、止めた理由は2通りあり、対処が正反対になります。 1つ目は、そのコンテナ自身に設定された上限を超えた場合です。この場合、超えたコンテナだけが止められます。機器に空きがあっても関係ありません。 2つ目は、機器全体のメモリが尽きた場合です。この場合、自分の上限を超えていないコンテナでも止められることがあります。誰が選ばれるかは、あらかじめ設定された優先度で決まります。 そして、この優先度を決めているのは上限ではありません。要求量です。kubelet のソースには計算式が定義されており、要求量を保証する種類なら最も殺されにくい値、上限も要求量も書かない種類なら最も殺されやすい値、その中間の種類なら「1000 から、要求量を機器のメモリ量で割った比率に1000を掛けた値を引いた数」になります。注釈には、要求量を超えて使うコンテナは実質的に最も殺されやすい値になり、優先的な対象になる、と書かれています。 ここが実務上いちばん重要な点です。「上限を上げる」という対処は、1つ目にしか効きません。2つ目に対しては、要求量を正しく設定することが効きます。上限だけを大きくして要求量を書かないままにすると、2つ目の状況ではむしろ殺されやすいままです。 なお、kubelet が能動的に対象を退去させる仕組みは別物で、状態名も違います。こちらの既定のしきい値は、空きが100メガバイトを下回った時点です。 エラーの概要 一覧では、繰り返せば待機中の表示になります。判断の材料は詳細のほうにあります。 Last State: Terminated Reason: OOMKilled Exit Code: 137 Started: Wed, 29 Jul 2026 11:02:14 +0900 Finished: Wed, 29 Jul 2026 11:19:48 +0900 終了コードの 137 は、128に9を足した値です。9番は強制終了の信号なので、ソフトウェアが自分で終了したのではなく、外から止められたことを示します。理由の欄が OOMKilled になっていれば、止めた理由はメモリです。 開始から終了までの時間も重要です。数分から数時間かけて止まっている場合、使用量が徐々に増えている可能性があります。起動直後に止まる場合は、初期化の時点で上限を超えています。 種類の判定は、要求量と上限の書き方で決まります。 kubectl get pod <ポッド名> -o jsonpath='{.status.qosClass}' 要求量と上限が等しければ最も保護される種類、どちらも書いていなければ最も保護されない種類、その中間はそれ以外です。 まず最初に:自分の上限か、機器の枯渇か 第一に、止められたコンテナの使用量が、自分の上限に達していたかを確認します。達していれば1つ目です。 第二に、同じ時刻に、同じ機器の上で他のコンテナも止まっていないかを確認します。複数が同時に止まっていれば、2つ目の可能性が高くなります。 第三に、機器全体のメモリの状況を確認します。空きが逼迫していた形跡があれば2つ目です。 この区別を付けずに上限だけを上げると、1つ目なら直り、2つ目なら悪化します。上限を上げたコンテナがより多くを使うようになり、機器全体の逼迫が早まるためです。 よくある原因と解決手順 原因1:自分の上限を超えている 最も分かりやすい形です。設定した上限に対して、実際の使用量が足りていません。 まず、上限と実測を並べます。 kubectl get pod <ポッド名> \ -o jsonpath='{range .spec.containers[*]}{.name}{" req="}{.resources.requests.memory}{" lim="}{.resources.limits.memory}{"\n"}{end}' kubectl top pod <ポッド名> --containers Before(上限が実態に対して低い): ...