MeWrite Docs

Container killed due to OOM (Out of Memory)

コンテナがメモリ不足で強制終了された場合のエラー

概要

DockerコンテナやKubernetes Podがメモリ制限を超過し、OOM Killer(Out of Memory Killer)によって強制終了された場合のエラーです。

エラーメッセージ

Container killed due to OOM
OOMKilled: true
Reason: OOMKilled
Exit code: 137

kubectl describe pod:
State: Terminated
Reason: OOMKilled
Exit Code: 137

原因

  1. メモリリーク: アプリケーションのメモリリーク
  2. メモリ制限が低すぎる: 設定した制限がアプリに不十分
  3. 急激なメモリ使用: 一時的な大量データ処理
  4. JVMヒープ設定: JavaアプリのヒープサイズとContainer制限の不整合
  5. キャッシュの肥大化: インメモリキャッシュの無制限増加

解決策

1. Dockerでメモリ制限を増やす

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# メモリ制限を指定して実行
docker run -m 2g --memory-swap 2g myapp

# docker-compose.yml
services:
  app:
    image: myapp
    deploy:
      resources:
        limits:
          memory: 2G
        reservations:
          memory: 1G

2. Kubernetesでリソース設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    spec:
      containers:
      - name: myapp
        image: myapp:latest
        resources:
          requests:
            memory: "512Mi"
            cpu: "250m"
          limits:
            memory: "1Gi"
            cpu: "500m"

3. JVMのメモリ設定

1
2
3
4
5
6
7
8
9
# Dockerfile
FROM openjdk:17-slim

# コンテナのメモリ制限を認識させる
ENV JAVA_OPTS="-XX:+UseContainerSupport \
               -XX:MaxRAMPercentage=75.0 \
               -XX:InitialRAMPercentage=50.0"

CMD ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Kubernetes
containers:
- name: java-app
  image: java-app:latest
  env:
  - name: JAVA_OPTS
    value: "-Xmx768m -Xms512m"
  resources:
    limits:
      memory: "1Gi"

4. Node.jsのメモリ設定

1
2
3
4
5
6
7
# Dockerfile
FROM node:20-slim

# ヒープサイズを制限
ENV NODE_OPTIONS="--max-old-space-size=1536"

CMD ["node", "server.js"]
1
2
3
4
5
6
7
8
9
# Kubernetes
containers:
- name: node-app
  env:
  - name: NODE_OPTIONS
    value: "--max-old-space-size=1536"
  resources:
    limits:
      memory: "2Gi"

5. メモリ使用量の監視

1
2
3
4
5
6
7
8
# Dockerのメモリ使用量を確認
docker stats

# Kubernetesのメモリ使用量
kubectl top pods

# コンテナ内でメモリ確認
docker exec container_id cat /sys/fs/cgroup/memory/memory.usage_in_bytes

6. メモリリークの検出(Node.js)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// メモリ使用量をログ出力
setInterval(() => {
  const used = process.memoryUsage();
  console.log({
    rss: `${Math.round(used.rss / 1024 / 1024)} MB`,
    heapTotal: `${Math.round(used.heapTotal / 1024 / 1024)} MB`,
    heapUsed: `${Math.round(used.heapUsed / 1024 / 1024)} MB`,
    external: `${Math.round(used.external / 1024 / 1024)} MB`,
  });
}, 30000);

7. メモリリークの検出(Python)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import tracemalloc
import gc

# メモリ追跡を開始
tracemalloc.start()

# 処理を実行
do_something()

# スナップショットを取得
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')

print("Top 10 memory consumers:")
for stat in top_stats[:10]:
    print(stat)

# ガベージコレクション
gc.collect()

8. Vertical Pod Autoscaler(VPA)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# VPA設定
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: myapp-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp
  updatePolicy:
    updateMode: "Auto"
  resourcePolicy:
    containerPolicies:
    - containerName: myapp
      minAllowed:
        memory: "256Mi"
      maxAllowed:
        memory: "4Gi"

9. Horizontal Pod Autoscaler(HPA)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# HPA設定(負荷分散でOOM回避)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: myapp-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 70

10. プロセスの優先度設定

1
2
3
4
5
6
# oom_score_adj を設定(Kubernetes)
containers:
- name: critical-app
  securityContext:
    # OOM Killerに殺されにくくする(-1000〜1000)
    # 注意: 特権が必要な場合がある

11. スワップの無効化確認

1
2
3
4
5
6
7
# スワップが無効か確認(Kubernetesでは通常無効)
cat /proc/swaps
swapon -s

# Dockerでスワップを制限
docker run -m 1g --memory-swap 1g myapp  # スワップ無効
docker run -m 1g --memory-swap 2g myapp  # 1GBスワップ許可

診断フロー

  1. kubectl describe pod または docker inspect でOOMKilledを確認
  2. kubectl top pod または docker stats でメモリ使用量を確認
  3. アプリケーションログでメモリ関連のエラーを確認
  4. プロファイラーでメモリリークを調査
  5. リソース制限を調整

よくある間違い

  • JVMのヒープサイズとコンテナ制限を同じにする(ネイティブメモリも必要)
  • requestsとlimitsを同じにしない(QoS Classに影響)
  • メモリリークを制限増加で対処しようとする
  • 開発環境の設定を本番にそのまま使う

関連エラー

参考リンク

Docker の他のエラー

最終更新: 2025-12-13