CKAD — 쿠버네티스 애플리케이션 개발자 · 파드 퇴근 실험실 — 기존 요청과 종료 유예 · 이론
퇴근 유예도 예산이다 — preStop과 TERM 사이
한 줄 요약
preStop은 종료 유예 밖의 보너스 시간이 아닙니다. 종료 대상 Pod의 훅과 애플리케이션의 신호 처리, 남은 작업 시간을 함께 설계해야 합니다.
왜 이게 필요했나
readiness를 달고 preStop에서 잠깐 기다렸으니 무조건 안전하다고 생각하기 쉽습니다. 하지만 훅 뒤에 프로세스가 곧바로 종료하면 이미 받은 요청은 잘릴 수 있고, 프로세스가 요청을 기다려도 종료 유예가 먼저 소진되면 끝낼 수 없습니다. '설정을 넣었다'와 '원하는 결과가 났다' 사이를 메우는 것이 이번 실습의 목적입니다.
설정이 어느 Pod에 들어 있는지도 중요합니다. Deployment 템플릿에 새로 추가한 preStop은 그 템플릿으로 생성하는 Pod의 설정입니다. 지금 교체되어 내려가는 옛 Pod에 소급해서 들어간 것으로 해석하면 실험 비교가 틀립니다. 삭제 직전 대상 Pod의 UID와 spec.containers의 lifecycle을 읽어 보존해야 합니다. 새 템플릿만 캡처해 둔 보고서는 무엇이 실제로 실행됐는지 말해 주지 못합니다.
어떻게 동작하나
일반적인 TERM 종료 흐름에서 kubelet은 preStop 훅을 실행하고, 훅이 끝난 뒤 컨테이너 프로세스에 종료 신호를 보냅니다. 종료 유예 계산은 훅이 실행되기 전에 시작되므로 훅과 그 이후 정리를 같은 예산 안에 넣어야 합니다. 훅이 3초를 썼다면 그 3초가 애플리케이션에 별도로 적립되는 것이 아닙니다. 무작정 긴 sleep을 넣는 방법은 새 요청 제외에 시간을 줄 수 있지만 종료 예산도 소비합니다.
여기서 시간 합산을 잘못하기도 합니다. 이미 시작한 HTTP 작업은 훅이 실행되는 동안에도 진행될 수 있습니다. 따라서 전체 작업 시간이 10초이고 훅이 3초라고 해서 언제나 13초의 잔여 작업이 있는 것은 아닙니다. 설계할 때는 훅 실행 시간과 TERM 뒤 실제로 남는 처리·정리 시간의 상한을 따지고, 관측할 때는 수락·삭제·훅·TERM·완료의 시각을 따로 남깁니다. 작업 상한이 없다면 유예만 크게 늘려서는 안전한 종료를 보장할 수 없습니다.
이번 서버의 graceful 모드는 TERM을 받으면 새 work 요청을 거절하고, active가 0이 될 때까지 기다린 뒤 종료합니다. immediate 모드는 비교를 위해 종료 코드 17로 즉시 끝납니다. 코드 17 자체가 Kubernetes의 표준 종료 의미인 것은 아닙니다. 실습 서버가 일부러 고른 관측 표식입니다. 정상 완료에서는 응답 본문을 끝까지 보내고 종료 코드 0을 관측합니다.
graceful이어도 유예가 부족하면 컨테이너가 강제로 종료될 수 있습니다. 이번에 앞서 수행한 실제 VM 탐침에서는 유예 부족 시 137을 관측했습니다. 그러나 현장에서 137만 보고 종료 유예 때문이라고 단정하지 마세요. OOM 같은 다른 원인도 조사해야 합니다. Pod watch의 종료 사유, 실제 유예 설정, 신호 전후 시각, 요청 결과를 함께 연결하는 것이 핵심입니다.
현장에서 만나는 모습
kubectl delete를 실행한 벽시계 시각과 kubelet이 종료를 처리하기 시작한 시각은 정확히 같지 않습니다. API 처리, 관측 전달, 런타임 작업에도 지연이 있습니다. 그래서 '유예 5초니까 삭제 명령 후 정확히 5초에 연결이 끊겨야 한다'는 채점은 정상 환경에서도 틀릴 수 있습니다. 이번 실습은 소수점 몇 초를 맞히게 하지 않고, 수락된 동일 요청의 결과와 종료 상태를 검사합니다.
채점 시점에 Pod를 다시 조회하는 것만으로도 부족합니다. 이미 삭제된 Pod는 없고, 종료된 컨테이너도 런타임에서 회수됐을 수 있습니다. 탐침의 첫 구현에서는 종료 뒤에 확인하려다 근거를 잃었습니다. 그래서 요청을 보내기 전 Pod watch를 시작하고, 최종 컨테이너 상태와 DELETED 이벤트를 보존합니다. 관측 파일을 읽는 재채점은 Pod를 재생성하지 않습니다. 같은 실험을 몰래 한 번 더 실행하면 이전 결과를 검사한 것이 아니기 때문입니다.
다음 실습에서 할 것
정상 종료 설정에서 유예를 줄여 요청을 끊어 보고, 다시 유예를 보완해 같은 길이의 작업이 완료되는지 확인합니다. 이론을 읽고 예상한 결과와 실제 관측을 비교하되, 특정 한 번의 응답을 모든 운영 트래픽의 무중단 보증으로 확대하지 마세요. 요청 실패 뒤 자동 재시도를 붙일 때는 앞 단원의 Job 멱등성처럼 업무 부작용도 고려해야 합니다.
공식 문서: [컨테이너 생명주기 훅](https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/), [Pod 종료 흐름](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination-flow).