🔍 검색 키워드: k8s OOMKilled, 쿠버네티스 메모리 부족, 포드 강제 종료, 메모리 리소스 요청, 리미트 설정
Kubernetes OOMKilled 에러 완벽 해결 가이드
1. 증상: OOMKilled 에러 메시지
Pod이 갑자기 재시작되고 로그에 다음과 같이 나타난다:
$ kubectl describe pod my-app-5f8d4c9d7b-xyz12
...
Last State: Terminated
Reason: OOMKilled
Exit Code: 137
Killed: True
Events:
Type Reason Age Message
---- ------ --- -------
Normal Created 2m Created container app
Normal Started 2m Started container app
Normal Killing 1m Killing container app (killed due to memory limit exceeded)
Pod의 상태가 계속 Pending이거나 CrashLoopBackOff 상태에 빠진다. 다른 Pod들은 정상인데 특정 Pod만 반복적으로 재시작된다.
2. 원인 분석
메모리 리미트 설정 부족
애플리케이션이 사용하는 실제 메모리가 Pod에 할당된 메모리 한계를 초과했다. kubelet이 OOM(Out of Memory) 상태를 감지하면 강제로 Pod을 kill한다.
메모리 누수
애플리케이션 코드에 메모리 누수가 있어서 시간이 지날수록 메모리 사용량이 증가한다. Node의 물리적 메모리도 한계가 있어 OOMKilled 발생.
Node 자원 부족
Node 레벨의 메모리가 부족하면 kubelet은 eviction policy에 따라 Pod들을 순차적으로 종료한다.
사이드카 컨테이너
logging agent, service mesh proxy(Istio sidecar) 등 추가 컨테이너들의 메모리 누적.
3. 해결방법
방법 1: Memory Request/Limit 올바르게 설정
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: app
image: my-app:latest
resources:
requests:
memory: "256Mi" # Pod 스케줄링 시 보장받는 메모리
limits:
memory: "512Mi" # 절대 초과 불가능한 한계
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
requests: Scheduler가 Node 할당 결정 시 사용
limits: cgroup을 통해 강제로 제한
방법 2: 메모리 사용량 모니터링
# Pod의 실제 메모리 사용량 확인
$ kubectl top pod my-app-5f8d4c9d7b-xyz12 -n default
NAME CPU(cores) MEMORY(bytes)
my-app-5f8d4c9d7b-xyz12 150m 387Mi
# Node 전체 메모리 상태
$ kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
worker-node1 1200m 60% 5432Mi 68%
Prometheus + Grafana로 시간대별 메모리 추이를 분석. 대부분 정상이지만 특정 시간에 메모리 스파이크 발생하는지 확인.
방법 3: 메모리 누수 디버깅 (Node.js 예시)
// Node.js 힙 덤프 수집
const heapdump = require('heapdump');
app.get('/heapdump', (req, res) => {
const fileName = `/tmp/heapdump-${Date.now()}.heapsnapshot`;
heapdump.writeSnapshot(fileName, (err, filename) => {
if (err) return res.status(500).send(err);
res.send(`Heap dump written to ${filename}`);
});
});
// Kubernetes manifest에 보안 컨텍스트 추가
securityContext:
readOnlyRootFilesystem: true
runAsNonRoot: true
allowPrivilegeEscalation: false
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
방법 4: HPA(Horizontal Pod Autoscaler) 설정
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 70
메모리 사용율이 70% 도달하면 자동으로 Pod 개수 증가.
4. 정리표
| 구분 | 내용 | 해결도 |
|---|---|---|
| 증상 | Pod이 OOMKilled로 반복 재시작됨 | - |
| 원인 1 | 메모리 limit 설정 부족 | ✓ 높음 |
| 원인 2 | 애플리케이션 메모리 누수 | ✓ 중간 |
| 원인 3 | Node 자원 전체 부족 | ✓ 중간 |
| 원인 4 | 사이드카 컨테이너 누적 | ✓ 낮음 |
| 해결 1 | Request/Limit 재설정 | 즉시 효과 |
| 해결 2 | 메모리 모니터링 (top, Prometheus) | 원인 파악 필수 |
| 해결 3 | 메모리 누수 디버깅 | 근본 해결 |
| 해결 4 | HPA 자동 스케일링 | 장기 대책 |
핵심: k8s OOMKilled는 "메모리가 부족하다"는 신호. requests는 넉넉하게, limits는 필요한 만큼만 설정하고, 정기적으로 메모리 프로파일링을 해야 한다.
댓글 없음:
댓글 쓰기