Kubernetes에서 Pod의 STATUS가 Running이라고 해서 애플리케이션이 트래픽을 받을 준비까지 끝났다는 뜻은 아니다. 컨테이너 프로세스는 떠 있을 수 있지만, readiness probe가 실패하면 Pod는 Ready 상태가 되지 않는다. 이 경우 Deployment rollout은 새 ReplicaSet을 만들었더라도 available replica를 확보하지 못해 멈춘 것처럼 보인다.
이번 실습에서는 nginx Deployment가 rollout 중 0 of 2 updated replicas are available 상태에 머물렀다. 원인은 readiness probe가 nginx가 실제로 응답하는 /와 80 포트가 아니라 /ready와 8080 포트를 바라보고 있었기 때문이다.
공식 Kubernetes 문서 기준으로 readiness probe는 컨테이너가 트래픽을 받을 준비가 되었는지 판단하는 검사다.
probe가 실패하면 해당 Pod IP는 매칭되는 Service의 EndpointSlice에서 ready backend로 취급되지 않는다. 즉 readiness는 단순한 상태 표시가 아니라, rollout과 트래픽 라우팅 모두에 영향을 준다.
참고 문서:
문제의 핵심은 readiness probe가 애플리케이션이 실제로 listen하지 않는 포트와 경로를 확인했다는 점이다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: cka-a01
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.25
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 2
periodSeconds: 5
failureThreshold: 3
nginx 기본 이미지는 80 포트에서 / 경로에 응답한다. 그런데 probe는 8080 포트의 /ready를 확인하고 있었다.
rollout 상태를 확인하면 Deployment가 available replica를 만들지 못하고 있었다.
kubectl rollout status deploy/web -n cka-a01
Waiting for deployment "web" rollout to finish: 0 of 2 updated replicas are available...
Pod가 완전히 죽은 상태라면 이미지 pull 실패, CrashLoopBackOff, 프로세스 종료 등을 의심할 수 있다. 하지만 이 경우 핵심은 컨테이너 시작이 아니라 readiness였다. Events를 보면 kubelet이 readiness probe를 반복해서 실패시키고 있었다.
kubectl get events -n cka-a01 --sort-by=.lastTimestamp
Warning Unhealthy pod/web-79cd87b765-75bqm Readiness probe failed:
Get "http://<pod-ip-1>:8080/ready": dial tcp <pod-ip-1>:8080: connect: connection refused
Warning Unhealthy pod/web-79cd87b765-vp9fc Readiness probe failed:
Get "http://<pod-ip-2>:8080/ready": dial tcp <pod-ip-2>:8080: connect: connection refused
여기서 중요한 단서는 connect: connection refused다. kubelet이 Pod IP의 8080 포트로 HTTP 요청을 보냈지만, 그 포트에서 수신 중인 프로세스가 없었다.
Deployment 자체가 ReplicaSet과 Pod를 만들지 못한 것은 아니었다. 컨테이너도 시작됐다. 하지만 readiness probe가 잘못된 endpoint를 검사했기 때문에 Pod가 Ready로 전환되지 않았다.
원인은 두 가지 필드였다.
readinessProbe:
httpGet:
- path: /ready
- port: 8080
+ path: /
+ port: 80
initialDelaySeconds: 2
periodSeconds: 5
failureThreshold: 3
nginx가 실제로 응답하는 경로와 포트에 맞춰 readiness probe를 변경했다.
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 2
periodSeconds: 5
failureThreshold: 3
이 수정은 애플리케이션 로직을 바꾸는 것이 아니라 Kubernetes가 준비 상태를 확인하는 방법을 실제 컨테이너 동작에 맞춘 것이다.
수정 후 Deployment와 Pod 상태는 정상으로 돌아왔다.
kubectl get deploy,pod -n cka-a01 -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/web 2/2 2 2 12m web nginx:1.25 app=web
NAME READY STATUS RESTARTS IP NODE
pod/web-785b864f78-9mcbm 1/1 Running 0 <pod-ip-1> minikube
pod/web-785b864f78-mblc2 1/1 Running 0 <pod-ip-2> minikube
describe pod에서도 readiness probe가 http://:80/로 바뀐 것을 확인할 수 있다.
kubectl describe pod -n cka-a01 -l app=web
Ready: True
Readiness: http-get http://:80/ delay=2s timeout=1s period=5s #success=1 #failure=3
rollout도 성공했다.
kubectl rollout status deploy/web -n cka-a01
deployment "web" successfully rolled out
revision도 1에서 2로 변경됐다.
kubectl rollout history deploy/web -n cka-a01
REVISION CHANGE-CAUSE
1 <none>
2 <none>
마지막으로 nginx 로그에서 kubelet probe 요청이 HTTP 200으로 처리되는 것을 확인했다.
kubectl logs -n cka-a01 deploy/web --tail=30
<kubelet-source-ip> - - [28/Aug/2026:15:51:49 +0000] "GET / HTTP/1.1" 200 615 "-" "kube-probe/1.28" "-"
<kubelet-source-ip> - - [28/Aug/2026:15:51:51 +0000] "GET / HTTP/1.1" 200 615 "-" "kube-probe/1.28" "-"
이런 증상이 보이면 다음 순서로 확인한다.
kubectl rollout status deploy/<name> -n <namespace>
kubectl get pod -n <namespace> -o wide
kubectl get events -n <namespace> --sort-by=.lastTimestamp
kubectl describe pod -n <namespace> -l app=<label>
kubectl logs -n <namespace> deploy/<name> --tail=30
Deployment는 ReplicaSet을 관리하고, ReplicaSet은 Pod를 만든다. 하지만 Deployment가 available replica를 확보하려면 Pod가 단순히 생성되고 컨테이너가 시작되는 것만으로는 부족하다. Pod가 readiness probe를 통과해야 한다.
흐름은 다음과 같다.
Deployment
-> ReplicaSet
-> Pod
-> kubelet readiness probe
-> Ready=True
-> Deployment available replica 증가
Pod는 Running이면서 동시에 Ready=False일 수 있다. 이 상태에서는 프로세스는 떠 있지만 Kubernetes는 아직 이 Pod를 트래픽 처리 가능한 backend로 보지 않는다.
이 실습에서는 rollback보다 forward fix가 적절했다. 문제 필드가 명확했고, /ready:8080에서 /:80으로 바꾸는 작은 설정 오류였기 때문이다.
다만 새 revision이 더 큰 장애를 만들었거나 원인이 불분명하다면 다음 명령으로 이전 revision으로 되돌릴 수 있다.
kubectl rollout undo deploy/web -n cka-a01
운영 환경에서는 rollback과 forward fix를 기계적으로 고르기보다, 현재 장애 영향과 원인의 명확성을 함께 봐야 한다. 원인이 작고 확실하면 forward fix가 빠를 수 있고, 원인이 불명확하거나 고객 영향이 커지고 있으면 known-good revision으로 되돌리는 판단이 더 안전할 수 있다.
이번 문제의 핵심은 Running과 Ready를 구분하는 것이다. 컨테이너가 시작됐더라도 readiness probe가 실패하면 Deployment는 available replica를 확보하지 못한다. Events에는 kubelet이 어떤 endpoint를 검사했고 왜 실패했는지가 남는다.
Kubernetes troubleshooting에서 Events는 단순 참고 정보가 아니다. 특히 readiness, scheduling, image pull, mount 실패처럼 control plane과 kubelet이 판단한 이유를 볼 때 가장 먼저 확인할 만한 evidence다.