
오늘 알게 된 거 아니고, 사실 꽤 됐는데 의외로 모르는 분이 많더라. 지난주에도 동료가 "JVM 앱이 livenessProbe 때문에 자꾸 재시작된다, initialDelaySeconds를 300초로 박았는데도 가끔 죽는다"는 얘길 했다. 그때 startupProbe 얘기를 꺼내면서 "어 진짜? 그런 게 있었어?"라는 반응이 나왔다. 1.20부터 GA였는데도 말이다.
근데 이게 한두 명 얘기가 아니라서, 짧게 정리해둔다.
initialDelaySeconds로 버티는 게 왜 문제냐
흔히 쓰는 패턴이 이거다.
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 180
periodSeconds: 10
failureThreshold: 3
3분 기다렸다가 체크 시작. 죽으면 30초 안에 재시작. 슬로우 스타트 앱(JVM, 캐시 워밍 하는 앱, DB 마이그레이션 거치는 앱)을 다루다 보면 이렇게 박게 된다.
문제는 두 가지다.
첫째, 평소엔 잘 뜨다가 가끔 4분 걸리는 경우. CI에서 의존성이 살짝 늦게 응답하거나, 노드가 좀 빡세거나. 그러면 4분째에 liveness가 fail로 진입하고, 30초 안에 kill. 무한 재시작 루프.
둘째, 한 번 떴으면 빠르게 죽음 감지하고 싶은데, 초기 지연 때문에 그게 안 된다. periodSeconds를 짧게 줘도 initialDelaySeconds만큼 무조건 기다린다. 운영 중 hang 감지가 느려진다.
startupProbe가 이걸 깔끔하게 푼다
startupProbe:
httpGet:
path: /health
port: 8080
periodSeconds: 10
failureThreshold: 30 # 최대 5분까지 시작 허용
livenessProbe:
httpGet:
path: /health
port: 8080
periodSeconds: 5 # 일단 뜨면 5초마다 빡세게 체크
failureThreshold: 3
startupProbe가 한 번 success를 내기 전까지 livenessProbe와 readinessProbe는 아예 동작하지 않는다. 그래서 startup 단계와 running 단계를 분리해서 설정할 수 있다. 시작은 느슨하게, 운영은 빡세게. 이게 핵심이다.
failureThreshold * periodSeconds가 startup에 허용되는 최대 시간이다. 위 예시는 5분. 평소 2분 걸리는 앱이면 여유 있게 5분 잡고, 그동안 liveness는 침묵.
자주 하는 실수
startupProbe path를 liveness와 다르게 잡는 거. 사람들이 /startup, /ready 이렇게 endpoint를 따로 만들려는데, 대부분 그냥 같은 /health로 두면 된다. 어차피 의미는 "프로세스가 응답하느냐"이고, startup 단계라는 건 단순히 응답을 기다려주는 시간일 뿐이다. endpoint를 따로 만들면 관리 포인트만 늘어난다.
failureThreshold를 너무 짧게 박는 거. 평균 시작 시간 기준이 아니라 P99 시작 시간 기준으로 계산해야 한다. 평균 2분이면 P99가 4-5분일 가능성이 높다. CI 노이즈, 디스크 IO, 콜드 이미지 풀까지 다 고려해서 잡는다. 부족하면 무한 재시작이고, 넘쳐도 어차피 startup 끝나면 안 쓰니까 후하게 줘도 손해 없다.
한 줄 결론
initialDelaySeconds로 버티고 있다면 startupProbe로 갈아타라. 시작 단계와 정상 운영 단계의 헬스체크 정책을 분리할 수 있다는 게 가장 큰 이득이다.
혹시 "우리 앱 시작이 너무 빨라서 startupProbe 필요 없는데?"라고 생각하는 분 있다면, 그래도 두는 걸 추천한다. 노드 빡셀 때 한 번씩 늦게 뜨는 경우가 의외로 많다. 비용도 거의 없다.
'IT > Kubernets' 카테고리의 다른 글
| kube-proxy 내부 동작 - iptables, IPVS, nftables 모드는 패킷을 어떻게 처리하나 (0) | 2026.05.12 |
|---|---|
| 배포할 때마다 503이 잠깐씩 튀던 이유 — Pod 종료 흐름 삽질 노트 (0) | 2026.05.12 |
| KEDA SQS scaler에서 새벽에 만난 함정 (0) | 2026.05.11 |
| Bottlerocket vs Talos, 워커노드 OS는 뭘 쓸까 (0) | 2026.05.11 |
| distroless 컨테이너에 sh가 없을 때, kubectl debug 한 줄로 끝내기 (0) | 2026.05.10 |