Contents
- 1 1. Linux カーネルの OOM 機構と Kubernetes が参照する情報
- 2 2. Kubernetes における Eviction フロー(NodeProblemDetector を含む)
- 3 3. QoS クラスとリソース設定が Eviction に与える影響
- 4 4. AKS(Azure Kubernetes Service)向け実装ガイド
- 5 5. GKE(Google Kubernetes Engine)向け実装ガイド
- 6 6. 自動スケーリングと予防策:VPA + Cluster Autoscaler
- 7 7. OOMKilled インシデントレスポンスチェックリスト(ブランド別追加項目)
- 8 8. 最終まとめ(Key Takeaways)
1. Linux カーネルの OOM 機構と Kubernetes が参照する情報
| 項目 | 説明 |
|---|---|
| OOM Killer | メモリが枯渇したノードでカーネルが自動的にプロセスを SIGKILL するサブシステム。oom_score_adj に基づき、最も「犠牲価値」が低いタスク(=cgroup)から順に対象となります。 |
| pswapd | スワップ領域の再利用を試みるデーモンであり、OOM 判定には関与しません。メモリ圧迫時は swap reclaim を行い、一時的に memory.available が回復することがありますが、根本的な OOM 状態の検知はカーネルの out‑of‑memory ロジックが担います。 |
| cgroup v1/v2 の memory controller | Pod ごとに割り当てた memory.limit_in_bytes(ハードリミット)を超えると、メモリコントローラが即座に対象プロセスへ SIGKILL を送ります。これが コンテナ単位の OOMKilled の直接原因です。 |
| /proc/meminfo & memory.available | カーネルがノード全体の空きメモリを算出する指標。memory.available が閾値以下になると、NodeProblemDetector (NPD) や kubelet が「MemoryPressure」状態として NodeCondition を更新します。 |
ポイント
- ノードレベルの圧迫はカーネルが直接 OOM Killer を起動するか、memory.availableが低下してNodeCondition MemoryPressureが立ち上がるかのいずれかで対処されます。
- コンテナ単位の OOM は cgroup のハードリミット超過がトリガーとなり、Kubernetes からは Pod のステータスにOOMKilledが付与されます。
2. Kubernetes における Eviction フロー(NodeProblemDetector を含む)
- NPD の監視
- NPD は systemd サービスとして動作し、
/proc/meminfoと/sys/fs/cgroup/.../memory.usage_in_bytesを定期的に取得。 -
memory.available < evictionHard.memory.available(kubelet 設定)や 90 % 超過といった条件を満たすと、NodeCondition のMemoryPressure=Trueを設定します。 -
kubelet のリアクション
- kubelet は NodeCondition が
MemoryPressureに遷移したことを検知すると、eviction controller を起動。 -
設定ファイル (
KubeletConfiguration) のevictionHard,evictionSoft,evictionMinimumReclaimで定義された閾値に従い、QoS クラス別に Pod を選択し Graceful Eviction(Pod が削除対象になる前にPreStopフックが走る)を実行します。 -
OOM Killer の介在
- 上記 eviction で対象外の Pod がノード全体のメモリ不足状態をさらに悪化させた場合、カーネルは直接 OOM Killer を呼び出し、cgroup スコアリングに基づき最もスコアが低い Pod(=
oom_score_adjが高い)を即座にSIGKILLします。 - このとき Kubernetes は Pod のステータス に
Reason: OOMKilledを付与し、イベントとして記録されます。
まとめ:NPD → NodeCondition → kubelet eviction →(必要なら)カーネル OOM Killer の三段階フローが実際の動作です。単純化せずにそれぞれのコンポーネントが果たす役割を理解しておくことが、正しいチューニングの出発点になります。
3. QoS クラスとリソース設定が Eviction に与える影響
| QoS | 設定条件 | メモリ圧迫時の優先順位 |
|---|---|---|
| Guaranteed | 全コンテナで requests == limits が明示的に設定されている |
最低。memory.request が全体の 100 % とみなされ、NodeCondition が出ても最初は対象になりません。 |
| Burstable | 1 つ以上のコンテナで requests < limits(もしくは一部未設定) |
中間。kubelet は同クラス内で memory.request / memory.limit の比率が小さい Pod から順に evict します。 |
| BestEffort | 全てのコンテナで requests, limits が未設定(=0) |
最優先。NodeCondition が立つと最初に対象となります。 |
実務上のベストプラクティス
- 本番環境は Guaranteed に近づける設計が基本です。
-Burstableを使用する場合でも、requestsは必ず設定し、最低限保証できるメモリ を明示します(例:requests: 256Mi,limits: 512Mi)。
-BestEffortは バッチ処理や短命ジョブ に限定し、監視アラートで早期に検知できるようにします。
4. AKS(Azure Kubernetes Service)向け実装ガイド
4.1 Azure のネイティブ監視と NPD の連携
| コンポーネント | 役割 |
|---|---|
| Azure Monitor for containers | kubelet が出力する memory.available、NodeCondition、Pod の OOM イベントを Log Analytics に自動転送。 |
| NodeProblemDetector (AKS 拡張) | Azure Monitor エージェントと連携し、MemoryPressure を検知した際に node.kubernetes.io/memory-pressure アノテーションを付与します。 |
| kubelet の evictionHard | デフォルトは memory.available<100Mi. AKS ではポータルまたは CLI で --eviction-hard=memory.available<200Mi 等に上書き可能です。 |
カスタマイズ例(Azure CLI)
|
1 2 3 4 5 6 7 |
# ノードプールの kubelet 設定を上書き az aks nodepool update \ --resource-group MyRG \ --cluster-name MyAKSCluster \ --name np1 \ --kubelet-config '{"evictionHard":{"memory.available":"200Mi"}}' |
ポイント:
memory.availableは「実際に割り当て可能なメモリ」なので、スワップが有効でもこの指標は減少しません。したがって、スワップの使用量で OOM が回避できるケースは稀です。
4.2 Azure Advisor と自動スケールアウト
- Azure Advisor は「Node の MemoryPressure」頻度を分析し、
Cluster Autoscalerの有効化やノードサイズ変更を提案します。 - Cluster Autoscaler (AKS) は
az aks enable-addons --addons cluster-autoscalerで有効化し、最小・最大ノード数を設定できます。
|
1 2 3 4 5 6 |
az aks enable-addons \ --resource-group MyRG \ --name MyAKSCluster \ --addons cluster-autoscaler \ --min-count 3 --max-count 12 |
- 推奨:VPA と組み合わせる場合は、
--scale-down-delay-after-add=10m等でスケールインのタイミングを遅らせ、リソースが安定するまで待機させます。
4.3 AKS 向け Observability(Prometheus + Grafana)
| メトリクス | 説明 |
|---|---|
container_memory_working_set_bytes |
コンテナの実際に使用中のメモリ(RSS+Cache)。 |
kube_pod_container_resource_limits_memory_bytes |
Pod が宣言した limits.memory。 |
node_memory_Active_bytes / node_memory_MemTotal_bytes |
ノード全体の利用率。 |
PromQL 例(80 % 警告・90 % 致命的)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 80% Warning ( container_memory_working_set_bytes{job="kubelet",container!=""} / kube_pod_container_resource_limits_memory_bytes{job="kube-state-metrics"} ) > 0.80 # 90% Critical ( container_memory_working_set_bytes{job="kubelet",container!=""} / kube_pod_container_resource_limits_memory_bytes{job="kube-state-metrics"} ) > 0.90 |
- Alertmanager のルールは
evaluation_interval: 30s、for: 2m(Warning)/1m(Critical)に設定し、スパイクによる誤検知を抑えます。 - Azure Monitor と統合すれば、アラートが Action Group に流れ、Teams/PagerDuty へ即時通知できます。
5. GKE(Google Kubernetes Engine)向け実装ガイド
5.1 GKE 標準の NodeProblemDetector と kubelet 設定
| コンポーネント | デフォルト挙動 |
|---|---|
| NodeProblemDetector (GKE) | /proc/meminfo の MemAvailable を監視し、閾値 90 % 超過で node.kubernetes.io/memory-pressure 条件を付与。 |
| kubelet evictionHard | デフォルトは memory.available<100Mi. GKE は --eviction-hard=memory.available<200Mi,resource.memory.threshold=0.9 の形でカスタマイズ可能。 |
gcloud コマンド例(標準クラスター)
|
1 2 3 4 |
gcloud container clusters update my-gke-cluster \ --node-pool default-pool \ --kubelet-config=evictionHard=memory.available<200Mi,resource.memory.threshold=0.9 |
- Autopilot クラスタの場合は、ノードがユーザーに見えない代わりに GKE が自動的に Memory Pressure の検知 → Pod Eviction を実行します。
PodSecurityPolicyの制約を付けることで、過度なlimits設定を防げます。
5.2 GKE と Cloud Monitoring の連携
- Cloud Monitoring(旧 Stackdriver)により、
kube_node_status_condition{condition="MemoryPressure"}が自動的にメトリクス化されます。 - アラートポリシーで「MemoryPressure が 5 分以上継続」したら Pub/Sub → Cloud Functions で自動的に
Cluster Autoscalerを有効化することが可能です。
|
1 2 3 4 5 6 7 8 9 10 11 |
# Cloud Monitoring Alert Policy (YAML) conditions: - displayName: "Node Memory Pressure" conditionThreshold: filter: 'resource.type="k8s_node" AND metric.type="kubernetes.io/node/memory_pressure"' comparison: COMPARISON_GT thresholdValue: 0.0 duration: 300s notificationChannels: - projects/PROJECT_ID/notificationChannels/1234567890 |
5.3 GKE 向け Observability(Prometheus + Grafana)
GKE では Managed Prometheus が標準で有効化でき、kube_pod_container_resource_requests_memory_bytes と container_memory_working_set_bytes を組み合わせたダッシュボードがすぐに利用可能です。
|
1 2 3 4 5 6 7 |
# 使用率 %(Managed Prometheus 用) ( container_memory_working_set_bytes{cluster_name="my-gke-cluster"} / kube_pod_container_resource_limits_memory_bytes{cluster_name="my-gke-cluster"} ) * 100 |
- Alertmanager の代わりに Google Cloud Alerting を使用し、同様の閾値(80 %/90 %)で通知先を Cloud Pub/Sub → Slack に流す構成が推奨です。
6. 自動スケーリングと予防策:VPA + Cluster Autoscaler
| 機能 | 主な役割 | AKS の実装ポイント | GKE の実装ポイント |
|---|---|---|---|
| Vertical Pod Autoscaler (VPA) | requests/limits を自動的に推奨・更新。Pod 再起動が必要になるが、リソース過不足を根本から解消。 |
Azure Marketplace の VPA アドオンか、Helm chart (vpa-admission-controller) をデプロイ。recommendationOnly でまずは提案だけ取得し、CI でレビュー後に Auto に切替。 |
GKE では autoscaling-profile=optimize-utilization と組み合わせて VPA を Helm で導入。updateMode: Auto が推奨。 |
| Cluster Autoscaler (CA) | ノードプールのサイズを自動調整し、Pod のスケジューラが失敗したときにノード追加。 | Azure VM Scale Set と連携。--scale-down-delay-after-add=10m で急激なスケールイン防止。 |
GKE の autoscaling-profile=balanced がデフォルト。Node pool ごとに maxPodsPerNode を適切に設定し、VPA 推奨上限が収まるよう調整。 |
実践的フロー
1. VPA がrequestsを増やしたら、CA が自動でノード数を拡張(必要に応じて別サイズの VM/Node pool にシフト)。
2. CA がスケールアウトした瞬間、kube‑scheduler が保留中だった Pod を再度スケジュールし直す。
3. メモリ圧迫が解消されたら、CA はscale-down-unneeded-time(デフォルト 10 min)経過後に余剰ノードを削除。
この循環を 「Memory‑aware Autoscaling」 と呼び、AKS・GKE 共通のベストプラクティスとして推奨します。
7. OOMKilled インシデントレスポンスチェックリスト(ブランド別追加項目)
| # | アクション | AKS 向け具体例 | GKE 向け具体例 |
|---|---|---|---|
| 1 | Pod 定義のリソース検証 | az aks browse → Azure Policy で AllowedResources: limits.memory を必須化。 |
gcloud resource-manager policies create --constraint=constraints/k8s.allowedResourceLimits |
| 2 | CI/CD でシミュレーション実行 | GitHub Actions のステップで kubectl top pod と kube-score を組み合わせ、リソース不足を検知。 |
Cloud Build + kube-linter で同様にチェック。 |
| 3 | Prometheus アラートのサイレンス管理 | Azure Monitor の「Alert rule」→「Suppress during deployment window」設定。 | Cloud Alerting の「Notification channel」→「Mute」機能を活用。 |
| 4 | メモリリーク診断フロー | Azure Application Insights の Live Metrics でコンテナメトリックをリアルタイム可視化。 |
GKE の Cloud Profiler と Cloud Trace を組み合わせ、ヒープダンプ取得手順を Runbook に記載。 |
| 5 | VPA / CA 設定の妥当性レビュー | Azure Policy で vpa.autoscaling.k8s.io が Auto のみ許可し、maxAllowed 超過時は PR をブロック。 |
GKE の Config Connector に AutoscalingPolicy リソースをデプロイし、ポリシー違反を自動で PR に変換。 |
| 6 | インシデント対応 Runbook の整備 | Azure DevOps Wiki に「OOMKilled 対応フロー」ページ作成 → kubectl describe pod → az monitor metrics alert list. |
Google Cloud Documentation に同様の手順を Markdown で保存し、ChatOps (Google Chat Bot) と連携。 |
| 7 | 定期的な負荷テスト実施 | Azure Load Testing Service で memcached ストレスシナリオを走らせ、メモリ使用率が 85 % 超えるか検証。 |
GKE の kubetest2 と stress-ng イメージで同様に実行し、結果を Cloud Logging に保存。 |
注記:上表は AKS と GKE が提供するネイティブ機能・CLI を活用した例です。自社の CI/CD パイプラインや SRE ツールチェーンに合わせてカスタマイズしてください。
8. 最終まとめ(Key Takeaways)
- OOM の根本原因は二系統
- ノード全体の MemoryPressure → kubelet が eviction、必要なら OOM Killer。
-
コンテナ cgroup ハードリミット超過 → 直接
SIGKILL(Pod が即座にOOMKilled)。 -
NodeProblemDetector の役割は「状態フラグ付与」 に止まり、実際のプロセス殺害は kubelet またはカーネルが行うことを認識しておく。
-
QoS クラスとリソース設定は Eviction の優先順位を決定 する最重要パラメータ。
-
本番は Guaranteed に近づけ、Burstable は最低でも
requestsを必ず設定。 -
AKS と GKE の固有機能(Azure Monitor + Advisor、GKE Autopilot / Cloud Monitoring)を活用し、MemoryPressure → Eviction の自動化とスケールアウトの連携を実装する。
-
Observability は Prometheus/Grafana(AKS)または Managed Prometheus/Cloud Monitoring(GKE)でメトリクスとアラートを一元管理し、段階的閾値(80 % Warning / 90 % Critical)で過剰なノイズを抑制。
-
VPA + Cluster Autoscaler の組み合わせ が最も効果的な「Memory‑aware Autoscaling」戦略となり、OOM 発生リスクを根本から低減できる。
-
インシデントレスポンスは自動化(Azure Policy / GKE Config Connector)と定期的負荷テストで事前検証し、Runbook に落とし込んだ手順で迅速対応が可能。
以上を踏まえて、AKS・GKE 環境それぞれに最適化された メモリ管理パイプライン を構築すれば、OOMKilled の発生率は大幅に低減し、サービスの可用性とコスト効率が向上します。
本稿は 2024 年 11 月時点の Kubernetes v1.30、AKS 2024‑3、GKE 2024‑2 の仕様を元に執筆しています。バージョンアップや新機能追加に伴い、設定項目が変化する可能性がありますので、公式ドキュメントの定期的なレビューを推奨します。