#!/bin/bash
# 실습 #15 ③ — OOM Killed 재현 + dmesg 커널 로그 확인
# - 메모리 256m 한도 컨테이너가 그 이상을 잡으려 하면 커널 OOM killer 가 컨테이너 PID 1 종료
# - stress-ng 대신 python bytearray 로 메모리 점진 할당 (VM·AVX 안전)
# - dmesg 의 oom-killer 라인 + docker inspect .State.OOMKilled = true 직접 확인
set -e

# 1) 메모리 부하 스크립트 (호스트 → 컨테이너 안에 한 줄 명령)
sudo docker rm -f lab-oom 2>/dev/null || true

# 2) 256m 한도, swap 도 256m (= 추가 swap 없음 → 한도 초과 즉시 OOM)
#    python3 가 bytearray 로 메모리를 50MB 씩 잡으며 천장 돌파
sudo docker run -d --name lab-oom \
    --memory="256m" \
    --memory-swap="256m" \
    --oom-kill-disable=false \
    python:3-alpine \
    python3 -c "
import time
chunks = []
for i in range(20):
    chunks.append(bytearray(50 * 1024 * 1024))  # 50 MiB 씩
    print(f'allocated {(i+1)*50} MiB', flush=True)
    time.sleep(1)
print('done')
"

# 3) 종료될 때까지 대기 (최대 30초)
echo "=== OOM 대기 중 ==="
for i in $(seq 1 30); do
    STATUS=$(sudo docker inspect -f '{{.State.Status}}' lab-oom 2>/dev/null || echo missing)
    OOM=$(sudo docker inspect -f '{{.State.OOMKilled}}' lab-oom 2>/dev/null || echo unknown)
    EXIT=$(sudo docker inspect -f '{{.State.ExitCode}}' lab-oom 2>/dev/null || echo unknown)
    if [ "$STATUS" = "exited" ]; then
        echo
        echo "=== 결과 ==="
        echo "  status     : $STATUS"
        echo "  OOMKilled  : $OOM       (true 면 cgroup memory.max 초과로 강제 종료)"
        echo "  ExitCode   : $EXIT      (137 = 128 + SIGKILL 9)"
        break
    fi
    sleep 1
done

# 4) 컨테이너 로그 — 어디까지 할당하다 죽었는지
echo
echo "=== 컨테이너 로그 (마지막 10줄) ==="
sudo docker logs --tail 10 lab-oom

# 5) 커널 dmesg 의 oom-killer 라인
echo
echo "=== dmesg OOM 라인 (최근) ==="
sudo dmesg | grep -iE "oom|killed process" | tail -10 || echo "(dmesg 접근 권한 또는 출력 없음)"

# 6) 정리
echo
echo "정리:"
echo "  sudo docker rm -f lab-oom"
echo
echo "관전 포인트:"
echo "  - --memory-swap 을 한도와 같게 두면 swap 사용 X → 즉시 OOM"
echo "  - 운영은 알람으로 OOM 잡고, restart=on-failure 로 자동 복구 + Prometheus oom_kill 메트릭"
echo "  - --oom-kill-disable 은 위험 (호스트 전체 freeze 위험) — 사용 금지"
