Liveness 및 Readiness 프로브 구성

KubernetesBeginner
지금 연습하기

소개

로그, 이벤트, 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 의 실제 동작을 연결해 보았습니다.