Kubernetes StatefulSet 으로 띄운 NiFi 파드(nifi-0, nifi-1, nifi-2)가 RESTARTS 42~45 회를 기록하며 반복 재시작됐다. nifi-bootstrap.log 에는 JVM 이 죽었다 다시 뜬 흔적과 AvailableLocalPorts: 28,231 (권장 55,000 미만), SocketTimeWaitDuration: 120초 (권장 1초) 경고가 있었다. cgroup 메모리 한도는 6 GiB, CPU limit 4 였다. 최종 판정은 커널 OOM 이 아니라 kubelet 의 liveness probe 실패에 의한 SIGKILL(exit 137) 이었다.
exit code 137 = 128 + 9 = SIGKILL 이며 보낸 주체가 둘이다. 구분은 Last State 의 Reason 필드에서만 된다.
| Reason | 주체 | 의미 |
|---|---|---|
OOMKilled + 137 |
커널 | cgroup 메모리 초과 |
Error + 137 |
kubelet | liveness 실패, 노드 압박 eviction, terminationGracePeriodSeconds 내 미종료로 SIGKILL 승격 등 |
kubectl describe pod nifi-0 | grep -A15 "Last State"
kubectl get events --field-selector involvedObject.name=nifi-0 --sort-by=.lastTimestamp | tail -30
kubectl describe pod nifi-0 | grep -iE "Unhealthy|Liveness|Killing|Back-off"
kubectl get pod nifi-0 -o jsonpath='{range .status.containerStatuses[*]}{.name}{"\t"}{.restartCount}{"\t"}{.lastState.terminated.reason}{"\t"}{.lastState.terminated.finishedAt}{"\n"}{end}'
kubectl get pod nifi-0 -o jsonpath='{.spec.containers[*].livenessProbe}' | jq
컨테이너 안에서 본 memory.failcnt = 0, oom_control = 0 은 증거가 되지 못한다. 컨테이너가 재시작되면 cgroup 이 새로 만들어져 카운터가 초기화되고, 컨테이너 안의 dmesg 로는 노드 커널 링버퍼가 보이지 않을 수 있다. 로그 파일이 PV 에 있으면 컨테이너가 죽었다 살아나도 같은 파일에 append 되므로 로그가 끊기지 않는 것도 정상이며, [main] RunBootstrapCommand 가 Java Version 부터 다시 찍히는 것이 새 부트스트랩 JVM 기동의 증거다.
당시 probe 설정은 exec [/bin/bash -c curl -sf http://${POD_IP}:8080/nifi-api/system-diagnostics] delay=30s timeout=5s period=30s failure=5 였다. 기동 예산은 30 + 5 × 30 = 180초 인데 NiFi 2.x 클러스터는 ZooKeeper 리더 선출과 플로우 동기화까지 보통 2~5분이 걸린다. startupProbe 가 없으니 3분 안에 API 가 안 열리면 SIGKILL → 재기동 → 또 초과 → 반복하는 루프가 된다.
이미 떠 있던 NiFi 가 죽은 건은 원인이 두 갈래다. system-diagnostics 는 힙 · GC · 디스크 사용량을 실시간 수집하는 무거운 엔드포인트라 CPU limit 4 에서 cgroup throttling 이나 Full GC 가 겹치면 5초 timeout 을 쉽게 넘긴다. 또 exec probe 의 curl 은 매번 ephemeral 포트를 하나 소모하고 그 포트는 TIME_WAIT 로 120초 묶이는데, net.ipv4.ip_local_port_range = 32768 60999 (60999 − 32768 = 28231, NiFi 경고 숫자와 일치) 상황에서 클러스터 통신까지 포트를 먹으면 curl 이 소스 포트를 못 잡아 실패한다. NiFi 는 정상인데 probe 만 실패하는 전형적 패턴이다.
kubectl exec nifi-0 -c nifi -- ss -s | head
kubectl exec nifi-0 -c nifi -- cat /sys/fs/cgroup/cpu.stat # nr_throttled, throttled_time
kubectl exec nifi-0 -c nifi -- sh -c 'time curl -sf -o /dev/null -w "%{http_code} %{time_total}\n" http://127.0.0.1:8080/nifi-api/system-diagnostics'
startupProbe:
httpGet: { path: /nifi-api/system-diagnostics, port: 8080 }
failureThreshold: 30
periodSeconds: 10 # 최대 5분 확보
livenessProbe:
httpGet: { path: /nifi, port: 8080 } # 가벼운 엔드포인트
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 5
httpGet 으로 바꾸면 kubelet 이 직접 체크하므로 포트 소모도 프로세스 fork 도 없다.system-diagnostics 는 startup 확인용으로만 쓰고 liveness 는 가벼운 경로로 둔다.net.ipv4.ip_local_port_range = "10240 65535", net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30 을 적용한다. NiFi 경고는 안내일 뿐 NiFi 가 알아서 늘리지 않는다.같은 대화에서 NiFi 가 아닌 Impala 의 S3 테이블 INSERT 실패도 다뤘다. 그 내용은 Impala S3A 버퍼 디렉터리 오류 에 따로 정리했다.