プローブの設計と中断バジェット
한국어 원문으로 표시합니다.
목표
세 가지 프로브를 검사 방식(httpGet/tcpSocket/exec)과 타이밍 필드까지 지정해서 만들고, Deployment 의 준비 상태와 종료 동작, 그리고 PodDisruptionBudget 을 설계할 수 있게 된다.
왜 중요한가
프로브를 안 붙인 Deployment 는 롤링 업데이트의 안전장치가 전부 무력화된 상태다. maxUnavailable: 0 을 줘도 컨테이너가 뜬 즉시 Ready 로 간주되어 초기화 중인 파드로 트래픽이 흘러 들어간다. 반대로 프로브를 너무 공격적으로 잡으면 정상 파드가 계속 재시작되면서 오히려 장애를 만든다. 그래서 프로브는 "붙였는가"가 아니라 "숫자를 계산해서 붙였는가"가 관건이다.
liveness 와 readiness 를 헷갈리면 사고가 커진다. 의존 서비스(DB)가 잠깐 죽었을 때 그걸 liveness 로 검사하면, 모든 파드가 동시에 재시작을 반복하며 DB 가 살아나도 회복이 늦어진다. 외부 의존성은 readiness 로 검사한다 — 트래픽만 안 받으면 되고 재시작할 이유는 없다.
startup 프로브는 이 둘 사이의 긴장을 푼다. liveness 에 initialDelaySeconds: 300 을 주면 운영 중 장애 감지도 5분 늦어지지만, startup 으로 300초 예산을 따로 주면 기동 후에는 liveness 를 촘촘하게 유지할 수 있다.
단계
- 네임스페이스
ckad-obs를 만들고 파드web-live를 만든다. 이미지nginx:1.27,livenessProbe는httpGet으로 path/healthz, port80,initialDelaySeconds: 5,periodSeconds: 10. - 파드
db-ready를 만든다. 이미지nginx:1.27,readinessProbe는tcpSocketport5432,initialDelaySeconds: 10,periodSeconds: 5,failureThreshold: 3. - 파드
file-check를 만든다. 이미지busybox:1.36,command: ["/bin/sh","-c","sleep 3600"],livenessProbe는exec으로command: ["cat","/tmp/healthy"],periodSeconds: 5,failureThreshold: 2. - 파드
legacy-app을 만든다. 이미지nginx:1.27.startupProbe는httpGetpath/startup, port8080,failureThreshold: 30,periodSeconds: 10(= 300초 예산). 같은 컨테이너에livenessProbe도httpGetpath/healthz, port8080,periodSeconds: 10으로 붙인다. - 파드
budget-app을 만든다. 이미지nginx:1.27,readinessProbe는httpGetpath/ready, port80,initialDelaySeconds: 15. 첫 실패 이후 20초 안에 엔드포인트에서 빠지도록periodSeconds와failureThreshold를 직접 정한다. 조건은periodSeconds × failureThreshold ≤ 20,failureThreshold ≥ 3,periodSeconds ≥ 2. - Deployment
api를 만든다. 레플리카 3, 라벨app=api, 이미지nginx:1.27. 컨테이너에readinessProbe(httpGet/ready:8080)와livenessProbe(httpGet/healthz:8080)를 붙이고,terminationMessagePolicy: FallbackToLogsOnError를 지정한다. - PodDisruptionBudget
api-pdb를 만든다.minAvailable: 2,selector는app=api. - Deployment
api에startupProbe를 추가한다 —httpGetpath/startup, port8080,failureThreshold: 12,periodSeconds: 5. 그리고 파드 스펙의terminationGracePeriodSeconds를60으로 설정한다. 기존 readiness/liveness 프로브와 레플리카 3은 그대로 유지한다.
참고
kubectl explain pod.spec.containers.livenessProbe/.startupProbe로 필드 이름을 확인한다.kubectl create deployment api --image=nginx:1.27 --replicas=3 -n ckad-obs --dry-run=client -o yaml > api.yaml로 뼈대를 뽑고 프로브를 손으로 채우는 편이 빠르다.- 이 환경에서는
kubectl logs와kubectl exec이 동작하지 않는다. 그 명령들은 이 모듈의 퀴즈에서 다룬다. - 흔한 실수 1: 프로브를 파드 수준(
spec.livenessProbe)에 쓰는 것. 컨테이너 수준 필드다. - 흔한 실수 2: PDB 의
selector에 Deployment 이름을 넣는 것. 파드 라벨이어야 한다. - 흔한 실수 3:
terminationGracePeriodSeconds를 컨테이너 밑에 쓰는 것. 파드 스펙 수준이다.
HTTP liveness 프로브
네임스페이스 ckad-obs 를 만들고 파드 web-live 를 만든다. 이미지 nginx:1.27, livenessProbe 는 httpGet 으로 path /healthz, port 80, initialDelaySeconds: 5, periodSeconds: 10.
livenessProbe.httpGet 에 path 와 port 를 준다. 프로브는 컨테이너 밑에 있고 파드 수준이 아니다. 응답 코드 200~399 면 성공으로 본다.
TCP readiness 프로브
파드 db-ready 를 만든다. 이미지 nginx:1.27, readinessProbe 는 tcpSocket port 5432, initialDelaySeconds: 10, periodSeconds: 5, failureThreshold: 3.
tcpSocket 은 포트만 있으면 된다 — 연결이 맺어지면 성공이다. readiness 는 실패해도 재시작하지 않고 엔드포인트에서만 빠진다.
exec 프로브
파드 file-check 를 만든다. 이미지 busybox:1.36, command: ["/bin/sh","-c","sleep 3600"], livenessProbe 는 exec 으로 command: ["cat","/tmp/healthy"], periodSeconds: 5, failureThreshold: 2.
exec.command 는 문자열 배열이고 셸을 거치지 않는다. 종료 코드 0 이면 성공이다. 파일 존재만 확인하려면 굳이 셸을 부를 필요가 없다.
startup 프로브로 느린 기동 감싸기
파드 legacy-app 을 만든다. 이미지 nginx:1.27. startupProbe 는 httpGet path /startup, port 8080, failureThreshold: 30, periodSeconds: 10 (= 300초 예산). 같은 컨테이너에 livenessProbe 도 httpGet path /healthz, port 8080, periodSeconds: 10 으로 붙인다.
startup 프로브가 성공하기 전까지 liveness/readiness 는 아예 시작하지 않는다. 기동 예산은 periodSeconds × failureThreshold 로 계산한다. 이 파드에는 liveness 도 함께 붙인다.
감지 지연을 계산해서 값 정하기
파드 budget-app 을 만든다. 이미지 nginx:1.27, readinessProbe 는 httpGet path /ready, port 80, initialDelaySeconds: 15. 첫 실패 이후 20초 안에 엔드포인트에서 빠지도록 periodSeconds 와 failureThreshold 를 직접 정한다. 조건은 periodSeconds × failureThreshold ≤ 20, failureThreshold ≥ 3, periodSeconds ≥ 2.
첫 실패부터 조치까지 걸리는 시간은 대략 periodSeconds × failureThreshold 다. 요구된 상한 안에 들어오면서 failureThreshold 를 충분히 크게 두어 일시적 실패에 흔들리지 않게 만든다. 정답은 하나가 아니다.
Deployment 에 프로브와 종료 메시지 정책 붙이기
Deployment api 를 만든다. 레플리카 3, 라벨 app=api, 이미지 nginx:1.27. 컨테이너에 readinessProbe(httpGet /ready:8080)와 livenessProbe(httpGet /healthz:8080)를 붙이고, terminationMessagePolicy: FallbackToLogsOnError 를 지정한다.
Deployment 의 프로브는 spec.template.spec.containers[] 밑에 들어간다. 종료 메시지 정책은 같은 컨테이너 수준 필드이고, 값이 두 가지뿐이니 kubectl explain 으로 확인한다.
PodDisruptionBudget 으로 자발적 중단 제한
PodDisruptionBudget api-pdb 를 만든다. minAvailable: 2, selector 는 app=api.
PDB 는 policy/v1 이고 minAvailable 또는 maxUnavailable 중 하나만 쓴다. selector 는 Deployment 가 아니라 파드 라벨을 가리켜야 한다.
기동 예산과 종료 예산을 함께 (종합)
Deployment api 에 startupProbe 를 추가한다 — httpGet path /startup, port 8080, failureThreshold: 12, periodSeconds: 5. 그리고 파드 스펙의 terminationGracePeriodSeconds 를 60 으로 설정한다. 기존 readiness/liveness 프로브와 레플리카 3은 그대로 유지한다.
앞에서 만든 Deployment 에 startup 프로브를 추가하고 종료 유예 시간을 늘린다. terminationGracePeriodSeconds 는 파드 스펙(spec.template.spec) 수준이고 컨테이너 수준이 아니다. 기존 liveness/readiness 는 그대로 남겨 둔다.