본문 바로가기
컨테이너/쿠버네티스

Pod의 생명주기

by sangyeon 2022. 11. 18.
728x90

★ Pod Lifecycle (생명주기)
: Pod는 기동 시에 기본 컨테이너 중 하나 이상이 정상으로 시작하면 Pending -> Running 단계로 넘어가며
Pod 안의 컨테이너 중 하나라도 실패로 종료되었는지 여부에 따라 Succeeded 또는 Failed가 된다.

Pod가 실행되는 동안 kubelet은 오류를 핸들링하기 위해 컨테이너를 재시작시킬 수 있다. 
쿠버네티스는 Pod 내의 컨테이너 상태를 추적하고 Pod를 다시 정상 Status로 만들기 위해 수행할 조치를 취한다.

Kubernetes API안에 Pod는 사양과 실제 상태를 갖고 있다. 
Pod가 노드에 한번 스케쥴되면, Stop되거나 Termintaed되지 않는 한 수명주기 동안 오직 한번만 스케쥴된다.

 

 

★ Pod Phase (단계)
Pod Phase는 Pod가 수명주기 중 어떤 상태인지를 보여주는 Status입니다.

- Pending : Pod가 Kube 클러스터에서 수락되었지만 하나 이상의 컨테이너가 셋업되지 않았으며 아직 실행할 준비가 되지 않음
(여기에는 네트워크를 통해 이미지를 다운로드 하는데 소요되는 시간뿐 아니라 Pod가 스케쥴링을 기다리는데 소요되는 시간도 포함됨)
- Running : Pod가 노드에 연결되었고 모든 컨테이너가 생성된 상태. 하나 이상의 컨테이너가 실행중이거나 시작 또는 재시작하는 중
- Succeeded : Pod의 모든 컨테이너가 성공적으로 종료되었으며 재시작되지 않음
- Failed : Pod의 모든 컨테이너가 종료되었으며 하나 이상의 컨테이너가 오류로 종료되었음. 즉, 컨테이너가 0이 아닌 상태로 종료되었거나 시스템에 의해 종료됨
- Unknown : Pod의 상태를 알 수 없음. API Server에서 쿼리를 사용하여 Kubelete과 통신하여 Pod의 상태를 가져올 수 없음. (이 단계는 일반적으로 Pod가 실행되어야 하는 노드의 kubelet과 통신 오류로 인해 발생)

※ Pod가 삭제될 때, Terminating으로 보여진다. 이때 Terminating은 Pod Phase는 아니다. 
Pod는 graceful shutdown을 위해 term을 갖는데, default로 30초이다. 하지만 --force flag를 사용하여 강제로 종료시킬 수 있다.


★ 컨테이너 상태
Pod의 전체 상태 뿐 아니라, Pod안의 각 컨테이너의 상태를 K8S가 추적한다.
kubectl get describe pod <name-of-pod>를 통해 Pod Container의 상태를 출력한다.

- Waiting : Running/ Terminated 상태가 아닌 상태를 뜻한다. 컨테이너를 Running 하기 위한 모든 작업(이미지 가져오기, secret 데이터 적용하기 등)을 하는 상태이다.
- Running : 컨테이너가 문제없이 실행되고 있는 상태를 뜻한다. hook(postStart) 설정이 있다면 이미 실행되고 끝난것이다.
- Terminated : 컨테이너 종료가 완료되었거나 어떤 이유로든 컨테이너가 Running에 실패할 경우의 상태를 뜻한다. hook(preStop) 설정이 있다면, 이 hook는 컨테이너가 Terminated 상태가 되기 전에 실행된다.

 

★ 컨테이너 재시작 정책
Pod는 restartPolicy 스펙 필드를 가지고 있다. value는 Always, OnFailure, Never가 있고 디폴트 값은 Always이다.
컨테이너 재시작 정책은 Pod의 모든 컨테이너에 적용되며, 동일한 노드의 kubelet에 의한 컨테이너 재시작을 의미한다.
kubelet은 5분을 limit으로 점진적 back-off 딜레이(10s, 20s, 40s)를 갖고 컨테이너를 재시작한다.
만약 컨테이너가 아무런 문제없이 10분 동안 실행된 상태라면, kubelet은 backoff 타이머를 리셋한다.

★ Pod Conditions
Pod는 PodStatus를 갖고 있는데, kubelet은 다음 Pod Condition을 관리한다.
- PodScheduled : Pod가 노드에 스케쥴됨
- PodHasNetwork : Pod sandbox가 성공적으로 생성되었고 네트워크가 구성됨
- CotnainersReady : Pod의 모든 컨테이너가 Ready 상태임
- Initailized : 모든 Init 컨테이너가 성공적으로 완료된 상태
- Ready : Pod가 요청을 받을 준비가 된 상태

 

★ 컨테이너 프로브(참고하기 좋은 블로그 : https://nearhome.tistory.com/89)

Probe는 컨테이너에 kubelet이 주기적으로 health check 하는 것이다. 
체크하는 메커니즘은 4가지가 있다. 

- exec : 컨테이너 내에서 지정된 명령어를 실행한다. 명령에 대한 상태코드가 0으로 종료되면 진단이 성공한 것으로 간주됨
- grpc : gRPC를 사용해 원격 프로시저 호출을 수행한다. 진단에 대한 상태가 SERVING으로 응답 받으면 정상적으로 성공한 것이다.
- httpGet : 지정된 IP:PORT에 대해 HTTP GET 요청을 보내 응답 코드가 200이상 400미만인 경우 진단이 성공한 것으로 간주됨
- tcpSocket : 지정된 IP:PORT에 대해 TCP 검사를 수행한다. 포트가 열려있으면 진단이 성공한 것으로 간주됨

 

 

★ 프로브 유형
kubelet은 3가지 유형의 프로브를 수행할 수 있다.
간단하게 이야기하면 readiness는 언제 트래픽을 보낼지에 대한 설정이고, liveness는 app(프로세스)이 잘 살아 있는지에 대한 설정이고 마지막으로 startup은 app이 기동됐는지를 판단하기 위함이다.
만약 app 기동이 오래 걸리는 상황일 때, liveness 체크가 되면 무한정 Pod Restart를 하게 되고 
readiness 역시 app이 기동되기 전에 활성화가 되면 트래픽이 실패나게 된다. 그렇기 때문에 startup을 설정하면 
app이 기동되고 나서 liveness, readiness를 체크하기 때문에 더 안정적인 Probe 세팅을 할 수 있다.

 

- livenessProbe : 컨테이너가 실행중인지 여부를 나타냄. livenessProbe가 실패하면 kubelet은 컨테이너를 종료하고 컨테이너 restartPolicy를 따른다.
만약 livenessProbe가 따로 설정되어 있지 않다면 기본적인 상태는 Success이다.
- readinessProbe : 컨테이너가 요청에 응답할 준비가 되어있는지 여부를 나타냄. readinessProbe가 실패하면 엔드포인트 컨트롤러는 Pod와 일치하는 모든 서비스의
엔드포인트에서 해당 Pod로 서비스가 가지 않도록 Pod의 주소를 제거한다.
  -> 롤링 업데이트 시, readinessProbe를 설정하여 정상적으로 서비스 준비가 된 Pod에 트래픽이 가도록 한다. 만약 readinessProbe 없이 롤링 업데이트를 한다면 사용자는 500에러를 볼수 있다.
- startupProbe : 컨테이너 내의 애플리케이션이 시작되었는지 여부를 나타냄. 만약 startupProbe가 구성되면 성공될때까지 다른 프로브들은 비활성화된다.
startupProbe가 실패하면 kubelet은 컨테이너를 종료하고 restartPolicy를 따른다. (livenessProbe보다 선행되는 프로브이다)
  -> 서비스를 시작하는데 오랜 시간 걸리는 컨테이너에 설정하는 것이 좋습니다. liveness 간격(주기)를 길게 잡는 것보다, 긴 시간을 허용하도록 하여 시작 시 컨테이너를 진단하도록 한다. 
컨테이너가 보통 initialDelaySeconds + failureThreshold x periodSeconds 이후에 기동이 된다면, startupProbe가 livenessProbe와 같은 엔드포인트를 체크하도록 명시해야 한다. 컨테이너가 livenessProbe의 기본 값 변경없이 기동되도록 하려면 failureThreshold를 충분히 높게 설정해주어야 데드락(deadlock)을 방지할 수 있다.

 

★ Pod 종료
클러스터 노드에서 실행 중인 Pod는 더이상 사용중이지 않을 때 graceful terminated되는 것이 중요하다.
(프로세스를 정리할 기회없이 KILL Signal하는 것보다)
일반적으로 컨테이너 런타임은 각 컨테이너의 "메인" 프로세스에 TERM Signal을 보낸다. 
(만약 컨테이너 이미지에 STOPSIGNAL이 다른 것으로 정의되어 있다면 TERM이 아닌 해당 Signal을 보낸다.)
유예 기간(graceful period : default 30초)이 끝나면 KILL SIG가 남아있는 프로세스로 전송된 다음 API 서버로부터 Pod가 삭제된다.

참고 : https://kimjingo.tistory.com/73 
SIGHUP
SIGINT
SIGQUIT
SIGABRT
SIGKILL
SIGTERM
SIGUSR1
SIGUSR2

컨테이너 종료 라이프사이클
1) Starting terminating
: Pod의 상태를 Terminating으로 바꾸고, 엔드포인트 리스트에서 Pod를 제거하여 새로운 Traffic을 차단 (컨테이너는 여전히 Pod내에서 실행중인 상태)

2) Grace Period(유예기간)
: Gracefully 종료를 위해 default로 30초를 기다림. preStop Hook, SIGTERM과 병렬적으로 수행되어 끝나지 않아도 이 시간이 지나면 SIGKILL 발생
(Pod yaml에서 TerminationGracePeriodSeconds 옵션 설정하여 변경 가능)

3) preStop Hook
: Pod에 구현되어 있는 preStop Hook을 실행. 컨테이너가 SIGTERM을 수신하기 전에 완료되어야 함.

4) SIGTERM 
: 쿠버네티스가 컨테이너를 멈추기 위해 보내는 신호. DB 혹은 WebSocket 연결 중지, 현재 상태 저장 등을 수행하여 깨끗하게 종료될 수 있도록 함

5) SIGKILL 
: 컨테이너 프로세스를 강제로 종료하는 시그널. Grace Period 후에도 컨테이너 프로세스가 종료되지 않는다면 해당 시그널을 통해 강제로 종료처리함.

728x90