본문 바로가기
WIKI 기술 지식 베이스

우아한 Pod 종료

원문 보기 위키 갱신

우아한 Pod 종료 (Graceful Pod Shutdown)

Kubernetes가 pod를 종료할 때 Linkerd 프록시가 요청을 우아하게 마무리하는 동작과, config.linkerd.io/shutdown-grace-period 주석이나 linkerd-await 같은 설정 옵션을 소개해요.

출처: Linkerd Graceful Pod Shutdown

본문

Kubernetes가 pod를 종료하기 시작하면, 그 pod의 모든 컨테이너에 TERM 신호를 보내는 것으로 시작합니다. Linkerd 프록시 사이드카가 이 신호를 받으면 즉시 우아한 종료를 시작합니다. 즉 새 요청을 거부하고, 종료 전에 기존 요청이 완료되도록 허용하죠.

이는 pod의 메인 컨테이너가 프록시가 TERM 신호를 받은 뒤 새로운 네트워크 호출을 시도하면, 그 네트워크 호출이 실패한다는 뜻입니다. 이것은 종료 중인 pod의 클라이언트와 job 리소스에도 영향을 줍니다.

Kubernetes에서의 우아한 종료

Pod는 본질적으로 일시적이며, 여러 이유로 죽을 수 있습니다. 예를 들어:

  • 실패한 노드에 스케줄링되어 있음(이 경우 pod는 삭제됩니다).
  • pod가 스케줄링된 노드의 리소스 부족(이 경우 pod는 축출됩니다).
  • 예를 들어 kubectl delete를 통한 수동 삭제.

pod는 기본적으로 클러스터의 노드에서 실행되는 프로세스를 나타내므로, 죽을 때 정리하고 우아하게 종료할 충분한 시간이 있도록 보장하는 것이 중요합니다. pod가 삭제되면 컨테이너 런타임이 pod에서 실행 중인 각 컨테이너에 TERM 신호를 보냅니다.

기본적으로 Kubernetes는 프로세스가 TERM 신호를 처리하도록 30초를 기다립니다. 이것을 grace period라고 하며, 그 안에서 프로세스가 스스로 우아하게 종료할 수 있습니다. grace period 시간이 다 지났는데도 프로세스가 우아하게 종료되지 않으면, 컨테이너 런타임은 KILL 신호를 보내 프로세스를 갑자기 멈춥니다. Grace period는 워크로드 레벨에서 덮어쓸 수 있습니다. 이것은 프로세스가 정리(예: 네트워크 호출, 디스크 쓰기 등)에 추가 시간이 필요할 때 유용해요.

Kubernetes는 또한 서비스 운영자가 컨테이너에 라이프사이클 훅을 정의할 수 있게 해줍니다. 우아한 종료의 맥락에서 중요한 것은 preStop 훅으로, 컨테이너가 다음 이유로 종료될 때 호출됩니다:

  • API 요청.
  • Liveness/Readiness 프로브 실패.
  • 리소스 경쟁.

pod의 컨테이너에 preStop 훅이 있고 pod가 컨테이너 런타임으로부터 TERM 신호를 받으면, preStop 훅이 먼저 실행되고 컨테이너 자체에 TERM 신호가 전파되기 전에 끝나야 합니다. 이 경우 grace period가 컨테이너가 TERM 신호 처리를 시작할 때가 아니라 preStop 훅이 실행될 때 시작된다는 점을 알아두는 것이 좋아요.

우아한 종료를 위한 구성 옵션

Linkerd는 pod와 컨테이너가 우아하게 종료되도록 구성하는 몇 가지 옵션을 제공합니다.

  • config.linkerd.io/shutdown-grace-period: 워크로드에 사용해 프록시의 우아한 종료 시간을 구성할 수 있는 주석입니다. 프록시가 스스로 우아하게 종료할 기회를 갖기 전에 이 기간이 경과하면, 프록시는 강제로 종료되며 열려 있는 모든 연결을 닫습니다. 기본적으로 종료 grace period는 120초입니다. 이 grace period는 TERM 신호가 어디서 오든 존중됩니다. 프록시는 컨테이너 런타임, 다른 프로세스(예: TERM을 보내는 스크립트), 또는 종료 엔드포인트에 대한 네트워크 요청(루프백 인터페이스에서만 가능)으로부터 종료 신호를 받을 수 있어요. 프록시는 열린 모든 연결이 끝날 때까지 TERM 신호 처리를 지연합니다. 이 옵션은 프록시가 우아하게 종료되는 것을 막을 수 있는 장기 실행 연결을 닫는 데 특히 유용해요.
  • linkerd-await: 다른 프로세스를 감싸고(그리고 생성) 실행하는 바이너리로, 보통 프록시 준비 상태를 기다리는 데 사용됩니다. await 바이너리는 --shutdown 옵션과 함께 사용할 수 있는데, 이 경우 감싼 프로세스가 끝난 뒤 프록시에 종료 요청을 보냅니다. 우아한 종료에 사용할 때는 보통 컨테이너의 엔트리포인트를 linkerd-await로 바꿔야 합니다.

Job·Cronjob 리소스의 우아한 종료

Job 또는 Cronjob 리소스의 일부인 pod는 pod의 모든 컨테이너가 완료될 때까지 실행됩니다. Linkerd 2.20부터 프록시는 기본적으로 네이티브 사이드카 컨테이너로 실행되며, pod의 메인 컨테이너가 종료되면 자동으로 종료되므로 메시화된 Job과 Cronjob은 추가 구성 없이 완료됩니다.

이것은 네이티브 사이드카를 비활성화한 경우에만 문제가 되며, 그건 더 이상 기본값이 아닙니다. 그 경우 프록시는 TERM 신호를 받을 때까지 계속 실행되는 일반 컨테이너로 실행되고, Kubernetes가 프록시에게 Job이 완료된 때를 알려줄 방법이 없으므로 메시화된 Job·Cronjob pod는 메인 컨테이너가 완료된 뒤에도 계속 실행됩니다. 애플리케이션 컨테이너가 완료된 뒤 프록시를 수동으로 종료하면 이 문제를 해결할 수 있습니다. 그러면 우아한 종료가 트리거되어 메시화된 Job·Cronjob pod가 완료될 수 있어요.

수동 종료

네이티브 사이드카가 비활성화되어 있다면, 애플리케이션이 완료된 뒤 프록시의 /shutdown 엔드포인트에 POST를 보낼 수 있습니다(예: curl -X POST http://localhost:4191/shutdown). 그러면 프록시가 우아하게 종료되고 Job 또는 Cronjob이 완료될 수 있습니다. 이 종료 요청은 루프백 인터페이스, 즉 같은 Kubernetes pod 내부에서 와야 합니다.

이 엔드포인트를 호출하는 편리한 방법 중 하나는 애플리케이션을 linkerd-await 유틸리티로 감싸는 것입니다. 이렇게 호출되는 애플리케이션(예: linkerd-await -S $MYAPP)은 완료될 때 프록시의 /shutdown 엔드포인트를 자동으로 호출합니다.

보안상의 이유로 프록시의 /shutdown 엔드포인트는 기본적으로 비활성화되어 있습니다. 프록시를 수동으로 종료할 수 있으려면 --set proxy.enableShutdownEndpoint=true 플래그로 Linkerd를 설치해 이 엔드포인트를 활성화해야 합니다.

더 알아보기 (Learn more)

  • linkerd-await
  • 네이티브 사이드카 (Native sidecars)