소개
로그, 이벤트, exec 및 포트 포워딩은 애플리케이션을 검사하는 데 유용합니다. 프로브 (Probes) 를 사용하면 Kubernetes 가 애플리케이션을 지속적으로 검사할 수 있습니다. Readiness 프로브는 "이 Pod 가 트래픽을 수신해야 하는가?"라는 질문에 답하며, Liveness 프로브는 "이 컨테이너를 재시작해야 하는가?"라는 질문에 답합니다.
이번 실습에서는 Readiness 와 Liveness 를 각각 구성해 봅니다. 먼저 /ready 엔드포인트를 생성한 후에만 준비 상태 (Ready) 가 되는 애플리케이션을 만듭니다. 그 다음, Liveness 프로브가 포함된 다른 애플리케이션을 생성하고 kubectl exec를 사용하여 상태 확인 파일을 삭제함으로써 Kubernetes 가 컨테이너를 재시작하는 과정을 관찰합니다.
프로브 실습을 위한 네임스페이스 준비
이 단계에서는 프로브 실습을 위한 깨끗한 네임스페이스를 준비합니다.
/home/labex/project에서 시작합니다. 프로브 매니페스트는 이 디렉토리에 보관합니다.
mkdir -p /home/labex/project
cd /home/labex/project
Kubernetes API 서버에 접근 가능한지 확인합니다. VM 이 막 시작되어 노드가 아직 준비되지 않았다면, 몇 초 기다린 후 명령어를 다시 실행하세요.
kubectl get nodes --request-timeout=5s
예상 출력:
NAME STATUS ROLES AGE VERSION
labex-v135 Ready control-plane ... v1.35...
클러스터 네트워킹 Pod 가 준비될 때까지 기다립니다. 프로브와 서비스는 정상적인 Pod 네트워킹에 의존합니다.
kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s
예상 출력:
pod/calico-node-... condition met
ckad-prep-probes라는 이름의 네임스페이스를 생성하고 현재 네임스페이스로 설정합니다:
kubectl create namespace ckad-prep-probes
kubectl config set-context --current --namespace=ckad-prep-probes
현재 네임스페이스를 확인합니다:
kubectl config view --minify --output 'jsonpath={..namespace}'; echo
예상 출력:
ckad-prep-probes
Readiness 프로브 구성
이 단계에서는 Readiness 프로브를 구성하고, 서비스가 준비된 (Ready) Pod 만 사용하는지 관찰합니다.
컨테이너는 즉시 HTTP 서버를 시작하지만, 몇 초 후에 /www/ready 파일을 생성합니다. Readiness 프로브는 포트 8080에서 GET /ready를 확인합니다. 해당 경로가 존재하기 전까지 Pod 는 Running 상태일 수 있지만 Ready 상태는 아니며, 서비스는 해당 Pod 로 트래픽을 보내지 않아야 합니다.
readiness-web.yaml을 생성합니다:
cat > readiness-web.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: readiness-web
spec:
replicas: 2
selector:
matchLabels:
app: readiness-web
template:
metadata:
labels:
app: readiness-web
spec:
terminationGracePeriodSeconds: 0
containers:
- name: web
image: busybox:1.36
command:
- /bin/sh
- -c
- |
mkdir -p /www
echo readiness-ok > /www/index.html
(sleep 12; echo ready > /www/ready) &
httpd -f -p 8080 -h /www
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 1
periodSeconds: 2
failureThreshold: 1
---
apiVersion: v1
kind: Service
metadata:
name: readiness-web
spec:
selector:
app: readiness-web
ports:
- port: 80
targetPort: 8080
EOF
매니페스트를 적용하고 생성 직후 Pod 상태를 확인합니다:
kubectl apply -f readiness-web.yaml
sleep 3
kubectl get pods -l app=readiness-web
예상 출력에서는 Running 상태이지만 아직 Ready 가 아닌 Pod 가 보일 수 있습니다:
NAME READY STATUS RESTARTS AGE
readiness-web-... 0/1 Running 0 ...
Deployment 가 사용 가능해질 때까지 기다립니다:
kubectl rollout status deployment/readiness-web --timeout=120s
예상 출력:
deployment "readiness-web" successfully rolled out
EndpointSlice 를 통해 서비스 엔드포인트를 검사합니다. Readiness 프로브가 통과된 후, 서비스는 두 개의 준비된 엔드포인트를 가져야 합니다.
kubectl get endpointslice -l kubernetes.io/service-name=readiness-web
예상 출력:
NAME ADDRESSTYPE PORTS ENDPOINTS
readiness-web-... IPv4 8080 ... + 1 more...
클라이언트 Pod 를 생성하고 서비스를 테스트합니다:
kubectl run probe-client --image=busybox:1.36 --restart=Never --command -- sleep 3600
kubectl wait --for=condition=Ready pod/probe-client --timeout=120s
kubectl exec probe-client -- wget -qO- http://readiness-web
예상 출력:
readiness-ok
Liveness 프로브 구성
이 단계에서는 상태 확인 파일을 검사하는 Liveness 프로브를 구성합니다.
Liveness 프로브는 Kubernetes 가 컨테이너를 재시작해야 할지 결정합니다. 이 예제에서는 컨테이너 내부에서 test -f /tmp/healthy를 실행하는 exec 프로브를 사용합니다. 컨테이너는 시작 시 해당 파일을 생성하므로 처음에는 정상 상태로 시작됩니다.
liveness-web.yaml을 생성합니다:
cat > liveness-web.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: liveness-web
spec:
replicas: 1
selector:
matchLabels:
app: liveness-web
template:
metadata:
labels:
app: liveness-web
spec:
terminationGracePeriodSeconds: 0
containers:
- name: web
image: busybox:1.36
command:
- /bin/sh
- -c
- |
touch /tmp/healthy
mkdir -p /www
echo liveness-ok > /www/index.html
httpd -f -p 8080 -h /www
ports:
- containerPort: 8080
livenessProbe:
exec:
command:
- test
- -f
- /tmp/healthy
initialDelaySeconds: 3
periodSeconds: 3
failureThreshold: 1
EOF
매니페스트를 적용하고 Deployment 가 준비될 때까지 기다립니다:
kubectl apply -f liveness-web.yaml
kubectl rollout status deployment/liveness-web --timeout=120s
예상 출력:
deployment.apps/liveness-web created
deployment "liveness-web" successfully rolled out
Pod 이름을 저장하고 상태 확인 파일이 존재하는지 확인합니다:
LIVE_POD="$(kubectl get pods -l app=liveness-web -o jsonpath='{.items[0].metadata.name}')"
echo "$LIVE_POD"
kubectl exec "$LIVE_POD" -- test -f /tmp/healthy
echo "health file exists"
예상 출력에는 Pod 이름과 다음 내용이 포함됩니다:
health file exists
Pod 를 설명 (describe) 하여 Liveness 프로브 구성을 확인합니다:
kubectl describe pod "$LIVE_POD" | grep -A3 'Liveness:'
예상 출력:
Liveness: exec [test -f /tmp/healthy] delay=3s timeout=1s period=3s
Liveness 재시작 유도
이 단계에서는 상태 확인 파일을 삭제하고 Liveness 프로브가 컨테이너를 재시작하는 것을 지켜봅니다.
Pod 객체는 그대로 유지되면서 내부 컨테이너만 재시작될 수 있습니다. 그렇기 때문에 새로운 Pod 이름을 기대하는 대신 컨테이너 재시작 횟수 (restart count) 를 관찰합니다.
현재 Pod 이름을 저장합니다:
LIVE_POD="$(kubectl get pods -l app=liveness-web -o jsonpath='{.items[0].metadata.name}')"
echo "$LIVE_POD"
컨테이너 내부에서 상태 확인 파일을 삭제합니다:
kubectl exec "$LIVE_POD" -- rm /tmp/healthy
재시작 횟수가 0 보다 커질 때까지 관찰합니다. Liveness 프로브는 3 초마다 실행되므로 잠시 시간이 걸릴 수 있습니다.
for i in $(seq 1 20); do
RESTARTS="$(kubectl get pod "$LIVE_POD" -o jsonpath='{.status.containerStatuses[0].restartCount}')"
echo "restart-count=$RESTARTS"
if [ "$RESTARTS" != "0" ]; then
break
fi
sleep 3
done
예상 출력:
restart-count=1
컨테이너가 재시작된 후, 시작 명령어가 /tmp/healthy를 다시 생성합니다. 파일이 복구되었는지 확인합니다:
kubectl exec "$LIVE_POD" -- test -f /tmp/healthy
echo "health file recreated"
예상 출력:
health file recreated
Pod 이벤트를 읽고 Liveness 실패 기록을 확인합니다:
kubectl describe pod "$LIVE_POD" | sed -n '/Events:/,$p'
예상 출력:
Warning Unhealthy ... Liveness probe failed
Normal Killing ... Container web failed liveness probe
요약
애플리케이션의 두 가지 주요 프로브를 모두 구성해 보았습니다. Readiness 프로브는 Pod 가 서비스 엔드포인트에 합류하는 시점을 제어했고, Liveness 프로브는 상태 확인 파일이 삭제된 후 컨테이너를 재시작했습니다. 또한 EndpointSlice, Pod 설명, 재시작 횟수 및 이벤트를 검사하여 프로브 구성과 Kubernetes 의 실제 동작을 연결해 보았습니다.


