-
[Kubernetes] Pod - 라이프사이클과 컨테이너 프로브공부/쿠버네티스&헬름 2025. 2. 9. 20:08
파드는 정의된 생명주기를 따르며 Pending 단계에서 시작하여 하나 이상의 기본 컨테이너가 정상적으로 시작되면 Running 단계를 거쳐 파드 내의 컨테이너 중 하나라도 실패로 종료되면 Succeeded 또는 Failed 단계 중 하나를 거칩니다.
개별 애플리케이션 컨테이너와 마찬가지로 파드는 비교적 일시적인(내구성이 없는) 엔터티로 간주됩니다. 파드는 생성되고 고유 ID(UID)가 할당되며 종료(재시작 정책에 따름) 또는 삭제될 때까지 노드에서 실행되도록 예약됩니다. 만약 노드가 죽으면 해당 노드에서 실행 중이거나 실행 예정인 파드는 삭제 대상으로 표시됩니다. 컨트롤 플레인은 시간 초과 후 파드를 제거 대상으로 표시합니다.
파드 수명
파드는 수명 주기 동안 단 한 번만 스케줄링됩니다. 특정 노드에 파드를 할당하는 것을 바인딩(binding)이라고 하며 사용할 노드를 선택하는 과정을 스케줄링(scheduling)이라고 합니다. 파드가 스케줄링되고 노드에 바인딩되면 Kubernetes는 해당 파드를 노드에서 실행하려고 시도합니다. 파드는 중지되거나 종료될 때까지 해당 노드에서 실행됩니다. Kubernetes가 선택한 노드에서 파드를 시작할 수 없는 경우(예: 파드가 시작되기 전에 노드가 충돌하는 경우), 해당 특정 파드는 절대 시작되지 않습니다.
파드 스케줄링 준비성(Pod Scheduling Readiness)을 사용하여 모든 스케줄링 게이트(scheduling gates)가 제거될 때까지 파드의 스케줄링을 지연시킬 수 있습니다. 예를 들어, 파드 집합을 정의하지만 모든 파드가 생성된 후에만 스케줄링을 트리거할 수 있습니다.
파드 오류 복구
파드는 클러스터가 복구할 수 없는 방식으로 실패할 수 있으며 이 경우 Kubernetes는 파드를 추가적으로 복구하려고 시도하지 않습니다. 대신 Kubernetes는 파드를 삭제하고 자동 복구를 제공하는 다른 구성 요소에 의존합니다.
파드가 노드에 스케줄링되었는데 해당 노드가 실패하면 파드는 비정상으로 간주되고 Kubernetes는 결국 파드를 삭제합니다. 파드는 리소스 부족이나 노드 유지 관리로 인한 퇴거(eviction)에서 살아남지 못합니다.
Kubernetes는 상대적으로 일회용 파드 인스턴스를 관리하는 작업을 처리하는 컨트롤러(controller)라는 상위 수준 추상화를 사용합니다.
UID로 정의된 특정 파드는 다른 노드로 "재스케줄링"되지 않습니다. 대신 해당 파드는 새롭고 거의 동일한 파드로 대체될 수 있습니다. 대체 파드를 만들면 이전 파드와 동일한 이름(즉,
metadata.name
)을 가질 수 있지만 대체 파드는 이전 파드와 다른metadata.uid
를 갖습니다.Kubernetes는 대체된 파드가 이전 파드와 동일한 노드에 스케줄링된다는 것을 보장하지 않습니다.
파드 phase
파드의
status
필드는PodStatus
객체이며 이 객체는phase
필드를 가지고 있습니다.파드의
phase
는 파드가 생명 주기 중 어느 단계에 있는지에 대한 간단하고 높은 수준의 요약입니다.phase
는 컨테이너 또는 파드 상태에 대한 모든 관찰 결과를 종합한 것도 아니고 포괄적인 상태 머신도 아닙니다.값 설명 Pending
파드가 Kubernetes 클러스터에 의해 수락되었지만 하나 이상의 컨테이너가 설정되지 않았거나 실행 준비가 되지 않은 상태입니다. 여기에는 파드가 스케줄링되기를 기다리는 시간과 네트워크를 통해 컨테이너 이미지를 다운로드하는 데 걸리는 시간이 포함됩니다. Running
파드가 노드에 바인딩되었고 모든 컨테이너가 생성되었습니다. 적어도 하나의 컨테이너가 여전히 실행 중이거나 시작 또는 재시작 과정에 있습니다. 다시 말해, 일부 컨테이너는 아직 시작 중이거나 재시작 중이여도 파드의 단계는 Running이 될 수 있습니다. Succeeded
파드 내의 모든 컨테이너가 성공적으로 종료되었으며 다시 시작되지 않습니다. Failed
파드 내의 모든 컨테이너가 종료되었으며 적어도 하나의 컨테이너가 실패로 종료되었습니다. 즉, 컨테이너가 0이 아닌 상태 코드로 종료되었거나 시스템에 의해 종료되었으며 자동 재시작하도록 설정되지 않았습니다. Unknown
어떤 이유로 인해 파드의 상태를 가져올 수 없습니다. 이 단계는 일반적으로 파드가 실행 중이어야 하는 노드와의 통신 오류로 인해 발생합니다. 파드가 반복적으로 시작에 실패하면 일부
kubectl
명령어의Status
필드에CrashLoopBackOff
가 나타날 수 있습니다. 마찬가지로 파드가 삭제될 때 일부kubectl
명령어의Status
필드에Terminating
이 나타날 수 있습니다.Status
는 사용자 직관을 위한kubectl
표시 필드이며 파드의phase
와 혼동하지 않도록 주의해야 합니다. 파드phase
는 Kubernetes 데이터 모델과 파드 API의 명시적인 부분입니다.NAMESPACE NAME READY STATUS RESTARTS AGE alessandras-namespace alessandras-pod 0/1 CrashLoopBackOff 200 2d9h
파드는 정상적으로 종료될 수 있도록 유예 기간(기본값 30초)이 주어집니다.
--force
플래그를 사용하면 파드를 강제로 종료할 수 있습니다.컨테이너 states
파드의 전체적인
phase
외에도 Kubernetes는 파드 내부의 각 컨테이너 상태를 추적합니다. 컨테이너 생명 주기 후크(container lifecycle hooks)를 사용하여 컨테이너 생명 주기의 특정 시점에 이벤트를 실행하도록 트리거할 수 있습니다.스케줄러가 파드를 노드에 할당하면 kubelet은 컨테이너 런타임(container runtime)을 사용하여 해당 파드의 컨테이너 생성을 시작합니다. 컨테이너에는 세 가지 가능한 상태, 즉
Waiting
,Running
,Terminated
가 있습니다.파드의 컨테이너 상태를 확인하려면
kubectl describe pod <name-of-pod>
명령어를 사용하면 됩니다. 출력에는 해당 파드 내의 각 컨테이너 상태가 표시됩니다.값 설명 waiting
컨테이너가 Running
또는Terminated
상태가 아니면Waiting
상태입니다.Waiting
상태의 컨테이너는 시작을 완료하기 위해 필요한 작업을 여전히 수행 중입니다. 예를 들어, 컨테이너 이미지 레지스트리에서 컨테이너 이미지를 가져오거나 Secret 데이터를 적용하는 등의 작업을 수행합니다.kubectl
을 사용하여Waiting
상태의 컨테이너가 있는 파드를 조회하면 해당 컨테이너가 왜 해당 상태에 있는지 요약하는Reason
필드도 함께 표시됩니다.Running
Running
상태는 컨테이너가 문제 없이 실행 중임을 나타냅니다. 구성된postStart
후크가 있다면 이미 실행되고 완료되었습니다.kubectl
을 사용하여Running
상태의 컨테이너가 있는 파드를 조회하면 컨테이너가Running
상태에 들어간 시간에 대한 정보도 함께 표시됩니다.Terminated
Terminated
상태의 컨테이너는 실행을 시작했다가 어떤 이유로든 완료되었거나 실패했습니다.kubectl
을 사용하여Terminated
상태의 컨테이너가 있는 파드를 조회하면 해당 컨테이너의 실행 기간에 대한 이유, 종료 코드, 시작 및 종료 시간이 표시됩니다.
컨테이너에 preStop 후크가 구성되어 있는 경우, 이 후크는 컨테이너가 Terminated 상태로 들어가기 전에 실행됩니다.파드가 컨테이너의 문제를 처리하는 방법
Kubernetes는 파드 스펙에 정의된
restartPolicy
를 사용하여 파드 내 컨테이너 실패를 관리합니다. 이 정책은 Kubernetes가 오류 또는 기타 이유로 컨테이너가 종료될 때 어떻게 반응하는지 결정하며 다음 순서로 진행됩니다.- 초기 충돌(Initial crash): Kubernetes는 파드
restartPolicy
에 따라 즉시 재시작을 시도합니다. - 반복되는 충돌(Repeated crashes): 초기 충돌 후 Kubernetes는
restartPolicy
에 설명된 대로 후속 재시작에 대해 지수 백오프 지연을 적용합니다. 이는 시스템에 과부하를 일으키는 급격하고 반복적인 재시도 시도를 방지합니다. CrashLoopBackOff
상태: 이는 백오프 지연 메커니즘이 현재 충돌 루프에 있는 특정 컨테이너에 대해 적용 중임을 나타냅니다. 해당 컨테이너는 지속적으로 실패하고 재시작됩니다.- 백오프 재설정(Backoff reset): 컨테이너가 특정 기간(예: 10분) 동안 성공적으로 실행되면 Kubernetes는 백오프 지연을 재설정하고 새로운 충돌을 첫 번째 충돌로 간주합니다.
실제로
CrashLoopBackOff
는 파드 내의 컨테이너가 제대로 시작되지 않고 지속적으로 시도하고 실패하는 루프에 있을 때kubectl
명령의 출력에서 파드를 설명하거나 나열할 때 볼 수 있는 조건 또는 이벤트입니다.다시 말해, 컨테이너가 충돌 루프에 들어가면 Kubernetes는 "컨테이너 재시작 정책"에 언급된 지수 백오프 지연을 적용합니다. 이 메커니즘은 결함이 있는 컨테이너가 지속적인 실패 시작 시도로 시스템에 과부하를 주는 것을 방지합니다.
CrashLoopBackOff
는 다음과 같은 문제로 인해 발생할 수 있습니다.- 컨테이너를 종료시키는 애플리케이션 오류
- 잘못된 환경 변수 또는 누락된 구성 파일과 같은 구성 오류
- 컨테이너가 제대로 시작하는 데 충분한 메모리 또는 CPU가 없을 수 있는 리소스 제약
- 애플리케이션이 예상 시간 내에 서비스를 시작하지 않으면 상태 검사 실패
- "프로브" 섹션에서 언급한 컨테이너 활성 프로브 또는 시작 프로브가
Failure
결과를 반환
CrashLoopBackOff
문제의 근본 원인을 조사하기 위해 사용자는 다음을 수행할 수 있습니다.- 로그 확인:
kubectl logs <name-of-pod>
를 사용하여 컨테이너의 로그를 확인합니다. 이는 충돌을 일으키는 문제를 진단하는 가장 직접적인 방법인 경우가 많습니다. - 이벤트 검사:
kubectl describe pod <name-of-pod>
를 사용하여 파드의 이벤트를 확인합니다. 이를 통해 구성 또는 리소스 문제에 대한 힌트를 얻을 수 있습니다. - 구성 검토: 환경 변수 및 마운트된 볼륨을 포함하여 파드 구성이 올바른지 확인하고 필요한 모든 외부 리소스를 사용할 수 있는지 확인합니다.
- 리소스 제한 확인: 컨테이너에 할당된 CPU와 메모리가 충분한지 확인합니다. 경우에 따라 파드 정의에서 리소스를 늘리면 문제가 해결될 수 있습니다.
- 애플리케이션 디버깅: 애플리케이션 코드에 버그나 잘못된 구성이 있을 수 있습니다. 로컬 또는 개발 환경에서 이 컨테이너 이미지를 실행하면 애플리케이션 관련 문제를 진단하는 데 도움이 될 수 있습니다.
컨테이너 재시작 정책
파드의
spec
에는restartPolicy
필드가 있으며 가능한 값은Always
,OnFailure
,Never
입니다. 기본값은Always
입니다.파드의
restartPolicy
는 파드 내의 애플리케이션 컨테이너와 일반적인 초기화 컨테이너에 적용됩니다. 사이드카 컨테이너는 파드 수준의restartPolicy
필드를 무시합니다. Kubernetes에서 사이드카는 컨테이너 수준의restartPolicy
가Always
로 설정된initContainers
내의 항목으로 정의됩니다. 오류와 함께 종료된 초기화 컨테이너의 경우, 파드 수준의restartPolicy
가OnFailure
또는Always
이면 kubelet이 초기화 컨테이너를 다시 시작합니다.Always
: 모두 종료 후 컨테이너를 자동으로 다시 시작합니다.OnFailure
: 컨테이너가 오류(0이 아닌 종료 상태)로 종료되는 경우에만 다시 시작합니다.Never
: 종료된 컨테이너를 자동으로 다시 시작하지 않습니다.
kubelet이 구성된 재시작 정책에 따라 컨테이너 재시작을 처리할 때, 이는 동일한 파드 내에서 동일한 노드에서 실행되는 대체 컨테이너에 대한 재시작에만 적용됩니다. 파드의 컨테이너가 종료된 후 kubelet은 지수 백오프 지연(10초, 20초, 40초, …)으로 다시 시작하며, 최대 300초(5분)로 제한됩니다. 컨테이너가 문제 없이 10분 동안 실행되면 kubelet은 해당 컨테이너의 재시작 백오프 타이머를 재설정합니다. "사이드카 컨테이너 및 파드 생명 주기"는
restartpolicy
필드를 지정할 때 초기화 컨테이너의 동작을 설명합니다.apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: my-image restartPolicy: Always # 또는 OnFailure, Never
컨테이너 프로브
프로브(probe)는 kubelet이 컨테이너에 대해 주기적으로 수행하는 진단입니다. 진단을 수행하기 위해 kubelet은 컨테이너 내에서 코드를 실행하거나 네트워크 요청을 보냅니다.
메커니즘 확인
프로브를 사용하여 컨테이너를 확인하는 네 가지 방법이 있습니다. 각 프로브는 다음 네 가지 메커니즘 중 정확히 하나를 정의해야 합니다.
exec
: 컨테이너 내부에서 지정된 명령을 실행합니다. 명령이 상태 코드 0으로 종료되면 진단이 성공한 것으로 간주됩니다.grpc
: gRPC를 사용하여 원격 프로시저 호출을 수행합니다. 대상은 gRPC 상태 확인을 구현해야 합니다. 응답 상태가SERVING
이면 진단이 성공한 것으로 간주됩니다.httpGet
: 지정된 포트와 경로에서 Pod의 IP 주소에 대해 HTTP GET 요청을 수행합니다. 응답 상태 코드가 200 이상 400 미만이면 진단이 성공한 것으로 간주됩니다.tcpSocket
: 지정된 포트에서 Pod의 IP 주소에 대해 TCP 검사를 수행합니다. 포트가 열려 있으면 진단이 성공한 것으로 간주됩니다. 원격 시스템(컨테이너)이 연결을 연 직후 닫으면 정상으로 간주됩니다.
프로브 종류
kubelet은 실행 중인 컨테이너에 대해 세 가지 종류의 프로브를 선택적으로 수행하고 이에 반응할 수 있습니다.
livenessProbe
(활성 프로브): 컨테이너가 실행 중인지 여부를 나타냅니다. 활성 프로브가 실패하면 kubelet은 컨테이너를 종료하고 컨테이너는 해당 컨테이너의 재시작 정책을 따릅니다. 컨테이너가 활성 프로브를 제공하지 않으면 기본 상태는Success
입니다.readinessProbe
(준비성 프로브): 컨테이너가 요청에 응답할 준비가 되었는지 여부를 나타냅니다. 준비성 프로브가 실패하면 엔드포인트 컨트롤러는 해당 파드와 일치하는 모든 서비스의 엔드포인트에서 파드의 IP 주소를 제거합니다. 초기 지연 전의 준비 상태 기본값은Failure
입니다. 컨테이너가 준비성 프로브를 제공하지 않으면 기본 상태는Success
입니다. 만약 해당 프로브가 실패가 되면 서비스의 엔드포인트를 제거해 트래픽을 받지 못하게 되지만 컨테이너는 계속 살아있습니다. kubelet은 설정한 주기대로 체크를 진행하며 다시 정상 상태가 되면 kubelet은 쿠버네티스 컨트롤 플레인에 이를 알리고 컨트롤 플레인은 해당 파드를 다시 서비스 엔드포인트에 연결합니다.startupProbe
(시작 프로브): 컨테이너 내의 애플리케이션이 시작되었는지 여부를 나타냅니다. 시작 프로브가 제공되면 다른 모든 프로브는 성공할 때까지 비활성화됩니다. 시작 프로브가 실패하면 kubelet은 컨테이너를 종료하고 컨테이너는 해당 컨테이너의 재시작 정책을 따릅니다. 컨테이너가 시작 프로브를 제공하지 않으면 기본 상태는Success
입니다.
보통 startupProbe를 사용하면 livenessProbe, readinessProbe도 함께 쓰며 startupProbe가 OK돼야 livenessProbe, readinessProbe가 동작합니다.
언제 liveness probe를 사용할까?
컨테이너 내의 프로세스가 문제에 직면하거나 비정상 상태가 될 때마다 스스로 충돌할 수 있다면 반드시 활성 프로브가 필요한 것은 아닙니다. kubelet은 파드의
restartPolicy
에 따라 자동으로 올바른 조치를 수행합니다.프로브가 실패할 경우 컨테이너를 종료하고 다시 시작하려면 활성 프로브를 지정하고
restartPolicy
를Always
또는OnFailure
로 지정해야 합니다.언제 readiness probe를 사용할까?
프로브가 성공했을 때만 파드로 트래픽을 보내기 시작하려면 준비성 프로브를 지정해야 합니다. 이 경우 준비성 프로브는 활성 프로브와 동일할 수 있지만 스펙에 준비성 프로브가 있다는 것은 파드가 트래픽을 받지 않고 시작하며 프로브가 성공하기 시작한 후에만 트래픽을 받기 시작한다는 것을 의미합니다.
컨테이너가 유지 관리를 위해 스스로 종료할 수 있도록 하려면 활성 프로브와 다른 준비 상태에 특정한 엔드포인트를 확인하는 준비성 프로브를 지정할 수 있습니다.
앱이 백엔드 서비스에 엄격하게 의존하는 경우 활성 프로브와 준비성 프로브를 모두 구현할 수 있습니다. 활성 프로브는 앱 자체가 정상일 때 통과하지만 준비성 프로브는 각 필수 백엔드 서비스가 사용 가능한지 추가로 확인합니다. 이렇게 하면 오류 메시지만 응답할 수 있는 파드로 트래픽을 보내는 것을 방지할 수 있습니다.
컨테이너가 시작하는 동안 대용량 데이터, 구성 파일 또는 마이그레이션을 로드해야 하는 경우 시작 프로브를 사용할 수 있습니다. 그러나 실패한 앱과 시작 데이터를 여전히 처리 중인 앱의 차이점을 감지하려면 준비성 프로브를 사용하는 것이 좋습니다.
언제 startup probe를 사용할까?
시작 프로브는 서비스 제공에 오랜 시간이 걸리는 컨테이너가 있는 파드에 유용합니다. 긴 활성 간격을 설정하는 대신 활성 간격보다 더 긴 시간을 허용하는 컨테이너 시작 시 프로브를 위한 별도의 구성을 설정할 수 있습니다.
컨테이너가 일반적으로
initialDelaySeconds + failureThreshold × periodSeconds
보다 오래 걸려 시작되는 경우, 활성 프로브와 동일한 엔드포인트를 확인하는 시작 프로브를 지정해야 합니다.periodSeconds
의 기본값은 10초입니다. 그런 다음 활성 프로브의 기본값을 변경하지 않고 컨테이너가 시작될 수 있을 만큼failureThreshold
를 충분히 높게 설정해야 합니다. 이는 데드락으로부터 보호하는 데 도움이 됩니다.예시
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: my-image restartPolicy: OnFailure livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 15 periodSeconds: 10 readinessProbe: tcpSocket: port: 3306 initialDelaySeconds: 5 periodSeconds: 5 startupProbe: exec: command: ["cat", "/app/startup_probe.txt"] failureThreshold: 30 periodSeconds: 10
restartPolicy
: 실패한 컨테이너만 재시작을 합니다.livenessProbe
: HTTP GET 요청을/healthz
경로 8080 포트로 보내 컨테이너의 활성 상태를 확인합니다. 15초 후 첫 번째 프로브를 시작하고 이후 10초마다 프로브를 실행합니다.readinessProbe
: 3306 포트에서 TCP 소켓 연결을 시도하여 컨테이너의 준비 상태를 확인합니다. 5초 후 첫 번째 프로브를 시작하고 이후 5초마다 프로브를 실행합니다.startupProbe
: 컨테이너 내에서cat /app/startup_probe.txt
명령어를 실행하여 애플리케이션 시작 여부를 확인합니다.failureThreshold
설정을 통해 30번 실패할 때까지 10초마다 프로브를 실행합니다.
즉,
livenessProbe
를 통해 컨테이너가 살아있는지 확인하고 정상이 아닌 컨테이너는restartPolicy
에 따라 비정상인 컨테이너만 재시작합니다.readinessProbe
는 컨테이너가 트래픽을 처리할 준비가 되었는지 확인하고 실패 시 서비스 엔드포인트에서 제외합니다.startupProbe
는 애플리케이션 시작 여부를 확인하고 실패 시restartPolicy
에 따라 비정상인 컨테이너만 재시작합니다.Liveness Probe와 Readiness Probe를 동일한 기준으로 설정했을 때 발생할 수 있는 문제점
Liveness Probe는 컨테이너가 살아있는지 (즉, 실행 중인지) 확인하며 Liveness Probe가 실패하면 Kubernetes는 컨테이너를 재시작합니다. Readiness Probe는 컨테이너가 요청을 처리할 준비가 되었는지 확인합니다. Readiness Probe가 실패하면 Kubernetes는 해당 컨테이너가 속한 파드를 서비스의 엔드포인트에서 제외하여 트래픽을 받지 않도록 합니다.
만약 Liveness Probe와 Readiness Probe를 동일한 기준으로 설정하면 다음과 같은 문제가 발생할 수 있습니다.
불필요한 컨테이너 재시작
만약 컨테이너가 일시적인 문제 (예: 외부 서비스 연결 실패)로 인해 Readiness Probe에 실패했다고 가정해 봅시다. Liveness Probe와 Readiness Probe가 동일하게 설정되어 있다면 Liveness Probe도 실패하게 되고 컨테이너는 재시작됩니다. 하지만 실제로는 컨테이너가 다시 시작될 필요 없이 문제가 해결되면 정상적으로 동작할 수 있는 상황일 수 있습니다. 이러한 경우 불필요한 컨테이너 재시작이 발생하여 서비스 가용성을 저하시킬 수 있습니다.
트래픽 손실
컨테이너가 Readiness Probe에 실패하면 서비스 엔드포인트에서 제외되어 트래픽을 받지 못합니다. 만약 Liveness Probe와 Readiness Probe가 동일하게 설정되어 있다면 컨테이너는 재시작되므로 트래픽 손실이 발생합니다. 하지만 Readiness Probe만 실패한 상황이라면 컨테이너가 재시작되지 않고 문제를 해결한 후 다시 트래픽을 받을 수 있도록 하는 것이 더 효율적일 수 있습니다.
예시
apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-container image: my-image # Liveness Probe와 Readiness Probe를 동일하게 설정 (문제 발생 가능성 있음) livenessProbe: httpGet: path: /healthz # 데이터베이스 연결 상태를 확인하는 엔드포인트 port: 8080 initialDelaySeconds: 5 periodSeconds: 5 readinessProbe: httpGet: path: /healthz # Liveness Probe와 동일한 엔드포인트 사용 port: 8080 initialDelaySeconds: 5 periodSeconds: 5 restartPolicy: Always # 컨테이너가 실패하면 항상 재시작
웹 애플리케이션 컨테이너가 데이터베이스에 연결되어 있습니다. 데이터베이스에 일시적인 장애가 발생하여 컨테이너가 데이터베이스와 통신할 수 없게 되었습니다. Liveness Probe와 Readiness Probe가 데이터베이스 연결 상태를 확인하도록 동일하게 설정되어 있습니다. 컨테이너는 Readiness Probe에 실패하여 서비스 엔드포인트에서 제외되고, Liveness Probe에도 실패하여 재시작됩니다. 데이터베이스 장애가 해결되었지만, 컨테이너는 재시작되었으므로 다시 시작하는 데 시간이 걸립니다. 이로 인해 서비스 가용성이 저하되고 트래픽 손실이 발생합니다.
해결 방법
Liveness Probe와 Readiness Probe를 서로 다른 기준으로 설정하여 컨테이너의 상태를 더 세밀하게 관리하는 것이 좋습니다. 예를 들어, Liveness Probe는 컨테이너의 핵심 기능이 정상적으로 동작하는지 확인하고 Readiness Probe는 컨테이너가 트래픽을 처리할 준비가 되었는지 확인하는 데 사용할 수 있습니다. 이렇게 하면 일시적인 문제로 인해 컨테이너가 불필요하게 재시작되는 것을 방지하고 서비스 가용성을 향상시킬 수 있습니다.
파드 종료
갑작스러운 종료(KILL 신호) 대신 정상적인 종료를 통해 리소스를 정리하고 데이터를 보존하는 것이 중요하므로 Kubernetes는 이를 위해 다음과 같은 정상 종료 절차를 제공합니다.
- 삭제 요청 및 유예 기간 설정
- 사용자가
kubectl delete pod <pod-name>
명령을 통해 파드 삭제를 요청하면 Kubernetes API 서버는 해당 파드에 유예 기간(grace period)을 설정하고 "Terminating" 상태로 변경합니다. - 유예 기간은 파드가 정상적으로 종료될 때까지 기다리는 시간으로 기본값은 30초입니다. 이 시간 동안 파드는 실행 중인 작업을 마무리하고 리소스를 정리할 수 있습니다.
- 서비스 엔드포인트 관리
- 파드가 종료되는 동안 컨트롤 플레인은 해당 파드를 서비스의 엔드포인트에서 제거하여 더 이상 트래픽이 해당 파드로 전달되지 않도록 합니다.
- 이를 통해 서비스의 안정성을 유지하고 종료 중인 파드로 인해 발생하는 오류를 방지할 수 있습니다.
- kubelet의 정상 종료 시도
- 파드가 실행 중인 노드의 kubelet은 파드가 "Terminating" 상태로 변경된 것을 감지하고 해당 파드의 정상 종료 절차를 시작합니다.
- kubelet은 먼저 컨테이너 런타임에 각 컨테이너의 주 프로세스에
TERM
신호(SIGTERM)를 보내도록 요청합니다. - 컨테이너 런타임은 이 신호를 받아 컨테이너 내부의 애플리케이션에게 종료 신호를 전달하고 애플리케이션은 정상적으로 종료 작업을 수행합니다.
preStop
후크 실행 (선택적)
- 파드 스펙에
preStop
후크가 정의되어 있다면 kubelet은 컨테이너가 종료되기 전에 이 후크를 실행합니다. preStop
후크는 애플리케이션이 종료되기 전에 필요한 추가 작업을 수행하는 데 사용됩니다 (예: 열린 연결 처리, 세션 정리 등).preStop
후크가 실행되는 동안에도 유예 기간은 계속 진행됩니다.
- 유예 기간 만료 및 강제 종료
- 유예 기간이 만료되면 kubelet은 컨테이너 런타임에
KILL
신호(SIGKILL)를 보내 컨테이너를 강제로 종료합니다. - 이는 애플리케이션이 정상적으로 종료되지 않거나
preStop
후크가 너무 오래 걸리는 경우에 발생합니다.
- 파드 삭제
- 컨테이너가 완전히 종료되면 kubelet은 파드를 "Failed" 또는 "Succeeded" 상태로 변경하고 API 서버에서 해당 파드 정보를 삭제합니다.
강제 종료
기본적으로 모든 삭제는 30초 내에 정상적으로 처리됩니다.
kubectl delete
명령어는--grace-period=<seconds>
옵션을 지원하므로 기본값을 재정의하고 사용자 지정 값을 지정할 수 있습니다.유예 기간을
0
으로 설정하면 파드가 API 서버에서 즉시 강제로 삭제됩니다. 파드가 노드에서 여전히 실행 중인 경우, 이러한 강제 삭제는 kubelet이 즉시 정리를 시작하도록 트리거합니다.kubectl
을 사용하여 강제 삭제를 수행하려면--grace-period=0
과 함께 추가 플래그--force
를 지정해야 합니다.강제 삭제가 수행되면 API 서버는 파드가 실행 중이던 노드에서 종료되었는지에 대한 kubelet의 확인을 기다리지 않습니다. 즉시 API에서 파드를 제거하므로 동일한 이름으로 새 파드를 만들 수 있습니다. 노드에서 즉시 종료되도록 설정된 파드는 강제 종료되기 전에 짧은 유예 기간이 부여됩니다.
레퍼런스
https://kubernetes.io/ko/docs/concepts/workloads/pods/pod-lifecycle/
https://kubernetes.io/docs/tasks/run-application/force-delete-stateful-set-pod/
https://coffeewhale.com/kubernetes/mistake/2020/11/29/mistake-10/
- 초기 충돌(Initial crash): Kubernetes는 파드