파드가 'Running' 상태라고 해서 서비스가 '정상'이라고 믿는 것만큼 위험한 착각은 없다는 것을 알았다. 인프라가 살아있는 것과 애플리케이션이 비즈니스 로직을 처리할 준비가 된 것은 완전히 다른 이야기다.
이제, 서비스의 안정성을 극대화하는 두 가지 핵심 장치인 ReadinessProbe와 LivenessProbe에 대해 알아볼 것이다.
1. 파드 프로브(Probe)의 필요성: 안정적인 서비스 운영 전략
먼저 어떤 상황에서 이 도구들이 필요한지부터 이해해야 한다.

1. 파드 안에 컨테이너가 생기고 파드와 컨테이너의 상태가 러닝이 되면서 그 안에 있는 앱도 정상적으로 구동이 되고 있을 것.
2. 그리고 서비스에 연결이 되고 이 서비스의 IP가 외부에 알려지면서 많은 사람들이 실시간으로 접근.
3. 그럼 한 서비스에 두 개의 파드가 연결돼 있으니까 50%씩 트래픽이 나눠진다고 가정.
4. 이렇게 서비스가 운영이 되고 있다가 Node2 서버가 다운.
5. 그럼 그 위에 파드도 Failed이 되면서 사용자는 파드1로 100% 접속.
6. 그리고 파드1이 이 트래픽을 던져준다면 이 앱 서비스가 유지되는 데 문제가 없음.
7. 이제 여기 파드2는 오토 힐링 기능에 의해서 다른 노드에 재생성되려고 함. 그 과정에서 파드와 컨테이너가 러닝 상태로 다시 변경됨.
8. 그렇게 서비스와 연결이 되는데, 아직 앱이 구동 중인 순간이 발생.
9. 서비스와 연결이 되자마자 트래픽이 파드2로 유입.
10. 앱이 구동되고 있는 순간에는 사용자는 50% 확률로 에러 페이지를 보게 되는 문제가 생김.
1) ReadinessProbe: "준비 안 된 녀석에겐 트래픽을 주지 마라"
앱이 구동되는 순간의 트래픽 실패를 없애라.
- 문제 상황: 오토 힐링으로 파드가 재생성될 때, 파드 상태는 'Running'이지만 내부 앱은 여전히 부팅 중일 수 있다. 이때 서비스가 트래픽을 보내면 사용자는 50% 확률로 에러 페이지를 보게 된다.
- 해결책: ReadinessProbe를 설정하면 앱이 완전히 구동되기 전까지 서비스와 연결되지 않도록 막아준다. 파드는 'Running'이지만 트래픽은 준비된 다른 파드(Pod 1)로만 흐르게 하며, 준비가 확인된 순간 50:50으로 배분되는 것이다.
2) LivenessProbe: "좀비 상태의 앱을 강제로 살려내라"
앱 장애시의 약간의 에러는 감수해도, 지속적인 실패를 예방해라.
- 문제 상황: App이 장애가 났다. 톰캣(Tomcat) 프로세스는 살아있어 파드는 'Running'이지만, 내부 앱이 메모리 오버플로우나 버그로 인해 '500 Internal Server Error'를 뱉는 경우가 있다. 파드 입장에서는 프로세스가 살아있으니 정상으로 간주하고 트래픽을 계속 던져 장애를 지속시킨다.
- 해결책: LivenessProbe를 달아주면 앱의 장애를 감지하고 파드를 재시작(Restart) 시킨다. 잠시 에러는 발생하겠지만 서비스가 영구적인 불능 상태에 빠지는 것을 막아준다.
2. 세부적인 사용 방법과 메커니즘

두 Probe는 사용 목적만 다를 뿐 설정 가능한 속성은 동일하다. 이미 파드가 연결된 상태에서 하나의 파드를 더 연결하는 상황이다.
1) 공통 확인 방식 (Check Mechanisms)
셋 중에 하나를 반드시 선택해야 한다.
- httpGet: 특정 포트, 호스트, 패스(Path), 헤더 등을 체크한다.
- exec: 컨테이너 내에서 특정 명령어를 실행하고 결과(Exit Code)를 체크한다.
- tcpSocket: 지정된 포트가 열려 있는지 체크한다.
2) 시간 및 임계치 옵션 (Timers & Thresholds)
별도로(Optional) 설정하지 않으면 디폴트값이 적용된다.
- initialDelaySeconds: 최초 체크 전 대기 시간 (예: 5초).
- periodSeconds: 체크 간격 (예: 10초).
- timeoutSeconds: 결과 대기 시간 (디폴트 1초). 이 시간까지 결과가 와야한다.
- successThreshold: 몇 번 성공해야 최종 성공으로 인정할지 (예: 3회).
- failureThreshold: 몇 번 실패해야 최종 실패로 간주할지 (예: 3회).

아래 시나리오 전부, Pod/컨테이너는 Running인데, 그 안에서 일어나는 과정을 통해 회복되는 과정을 보는 것이다.
동작 시나리오: Readiness (Exec 방식)
프로브가 성공 전까지 Conditions(ContainerReady, Ready)는 'False' 이다. = 앱이 트래픽을 받을 Ready가 됐는지 판단한다.
- 파드 생성 후 노드 스케줄링 및 이미지 다운로드 완료.
- 파드/컨테이너는 'Running'이지만 프로브가 성공 전까지 Conditions(ContainerReady, Ready)는 'False' 유지.
- 엔드포인트(Endpoint)는 이 IP를 'NotReadyAddresses'로 간주하여 서비스 연결 안 함.
- 5초 대기 후 10초마다 ready.txt 파일 체크.
- 파일이 생성되어 3회 성공 확인 시, 상태가 'True'로 변하며 서비스와 연결됨.
동작 시나리오: Liveness (httpGet 방식)
프로브가 성공 전에도 Conditions(ContainerReady, Ready)는 'True' 이고, 후에도 변하지 않는다.
즉, 실패했을 때 컨테이너를 재시작(Restart) 시키는 것이 주 업무이다. = 컨테이너가 Alive인지 판단한다.
- /health 경로로 10초마다 헬스 체크 수행.
- 앱 장애로 인해 HTTP 500 에러 발생.
- 서비스가 장애가 난 것. 하지만, 파드는 Running 상태.
- 3회 실패(failureThreshold) 누적
- 이때, 잠깐 Conditions(ContainerReady, Ready)가 'Flase'가 된다.
- 쿠버네티스가 파드를 재시작(Restart).
💡 꼬리 질문
Q1: 만약 애플리케이션의 초기 부팅 시간이 매우 길어서 300초 이상 소요된다면, LivenessProbe의 failureThreshold와 initialDelaySeconds만으로 대응하는 것보다 더 효율적인 쿠버네티스의 세 번째 프로브는 무엇일까?"
결론1: StartupProbe를 사용해야 한다.
- 도입 배경: 부팅이 느린 앱에 LivenessProbe를 너무 일찍 적용하면, 앱이 아직 뜨지도 않았는데 실패로 간주하고 무한 재시작에 빠질 수 있다(Deadlock).
- 동작 방식: StartupProbe는 앱이 완전히 시작될 때까지 Liveness/Readiness 체크를 유예시킨다. StartupProbe가 성공해야 비로소 다른 프로브들이 동작하기 시작한다.
- 효율성: initialDelaySeconds를 무작정 길게 잡는 것보다, StartupProbe를 통해 부팅 완료 시점까지만 기다리게 설정하는 것이 훨씬 유연하고 안전한 설계다.
Q2: Liveness와 Readiness를 모두 설정한 파드에서, LivenessProbe가 먼저 실패하여 컨테이너가 재시작(Restart)되는 순간에 ReadinessProbe의 결과와 파드의 Ready 상태는 어떻게 변할까?
결론2: 컨테이너가 재시작되는 순간 모든 프로브 상태는 초기화되며, Ready 상태는 즉시 False가 된다.
- 동작 원리: LivenessProbe 실패로 인해 컨테이너가 재시작되면, 쿠버네티스는 해당 컨테이너를 다시 '부팅 중'인 상태로 간주한다.
- 상태 변화: 이때 ReadinessProbe는 다시 처음부터 성공 횟수(successThreshold)를 채워야 한다.
- 트래픽 차단: 재시작 중에는 당연히 앱이 응답할 수 없으므로 Ready 상태는 False가 되고, 서비스는 해당 파드로 트래픽을 보내지 않는다.
1. ReadinessProbe

- 초기 상태: 파드를 생성하면 ready.txt 파일이 없으므로 ReadinessProbe는 계속 실패한다.
- 상태 확인: kubectl describe pod 명령으로 확인하면 Ready와 ContainerReady 상태가 모두 False로 유지된다.
- kubectl describe endpoints 확인 시, 파드의 IP가 Addresses가 아닌 NotReadyAddresses 목록에 들어있다.

- 회복 과정: 파드가 떠 있는 노드에 접속하여 /tmp/readiness/ready.txt 파일을 수동으로 생성한다.
- 결과: 설정된 successThreshold: 3에 따라 3번의 성공을 확인한 직후, 파드의 상태가 True로 변하며 트래픽이 유입되기 시작한다.
apiVersion: v1
kind: Pod
metadata:
name: pod-readiness-exec1
labels:
app: readiness
spec:
containers:
- name: readiness
image: kubetm/app
ports:
- containerPort: 8080
readinessProbe:
exec:
command: ["cat", "/readiness/ready.txt"]
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 3
volumeMounts:
- name: host-path
mountPath: /readiness
volumes:
- name : host-path
hostPath:
path: /tmp/readiness
type: DirectoryOrCreate
terminationGracePeriodSeconds: 0
2. LivenessProbe
apiVersion: v1
kind: Pod
metadata:
name: pod-liveness-httpget1
labels:
app: liveness
spec:
containers:
- name: liveness
image: kubetm/app
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 3
terminationGracePeriodSeconds: 0
위 학습용 정리 내용 및 사진 자료는 "인프런_대세는 쿠버네티스(https://inf.run/Lv5RV)" 강의를 소스로 작성하였습니다
'Cloud Native > Kubernetes' 카테고리의 다른 글
| 4. Pod - Node Scheduling [중요] (0) | 2026.01.25 |
|---|---|
| 3. Pod - QoS Classes (request, limit) (0) | 2026.01.25 |
| 1. Pod - Lifecycle (0) | 2026.01.24 |
| 8. DaemonSet, Job, CronJob (1) | 2026.01.24 |
| 7. Deployment - Recreate, RollingUpdate (0) | 2026.01.23 |