# Pod 우아(grace ful)하게 관리하기

bhs9610·2020년 10월 21일
0
post-thumbnail

쿠버네티스에 부하와 장애의 원인이 가장 근접한건 Pod 라고 생각한다. 이러한 Pod 를 관리하기 위해 Pod LifeCycle 을 알아보자.

트래픽 손실 & 무중단 배포


무중단 배포를 위한, kubernetes Pod의 교체되는 flow을 알아보자. Service에 연결된 Pod를 교체한다 했을 때, 이전에 있던 Pod는 사라지고 새로운 Pod에 Healcheck 한 뒤에 트래픽을 보내게된다.

kubernetes는 이러한 배포 절차가 잘되어 있지만, 컨테이너 내부에서 종료될 때 TIME_WAIT를 남기지 않는 세션종료 (Graceful Shutdown) 의 구현이 필요하다. kubernetes에서 컨테이너를 종료할 때 컨테이너를 관리하는 kubelet은 먼저 종료할 Pod 에 SIGTERM 신호를 보내게 된다. 컨테이너는 해당 SIGTERM을 받았을때 기존에 처리중이던 요청에 대한 처리를 완료하고 새로운 요청을 받지 않도록 개발되어야 한다. 그렇지 않으면 트래픽은 이전에 있던 Pod(B) 로가서 요청들은 에러를 내게 된다. kubelet에서 Pod에 SIGTERM을 보낸 후에 일정동안 Graceful Shutdown 이 되지않는다면 강제로 SIGKILL을 보내서 파드를 종료하게 된다.

이러한, 부분들을 관리해주지 않는다면 Zombie Pod 들이 생길 수도 있고 서비스 장애로 이어질 수 있다.

Pod 재시작 고려


컨테이너가 생성되는 과정을 생각해보자, yaml를정의하면 Node에 있는 kubelet이 계속 보고있다가 정의된 설정값을 PodStart를 통해 수행하게 된다. 이때, Pod가 생성될 때 재시작과 관련된 옵션을 생각해볼수 있는데 failureThreshold 와 periodSeconds, terminationGracePeriodSeconds로 세팅 할수 있다.

  • failureThreshold

Pod가 구동에 실패했을 때, 몇번 까지 Pod가 실행될때 까지 시도할 것인지 설정하는 옵션이다.

  • periodSeconds

failureThreshold가 몇초의 주기로 실행될것인지 지정하는 옵션이다. 이 부분들을 먼저 확인하고 성공한다면, Rediness Probe와 Liveness Probe상태로 넘어가게 된다.

  • terminationGracePeriodSeconds

kubelet이 Pod에 SIGTERM을 보낸후에 일정시간동안 graceful shutdown이 되지않는다면 강제로 SIGKILL를 보내서 Pod를 종료하게 된다. 이 대기시간은 terminationGracePeriodSeconds 로 설정해줄수 있고, 설정을 안하면 default은 30초를 가지게 된다.

Pod LifeCycle를 지원하는 Probe 옵션


SIGTERM을 고려해서 배포한다면, kubernetes에서 활용할 옵션들을 생각해보자.

kubernetes에서는 Pod의 Healcheck를 확인하기 위해 2가지 상태체크 옵션을 부여할 수 있다. 무중단배포에 가장 필요한것은, Readiness Probe 이다.

  • Liveness Probe (활성 프로브)

Liveness Probe는 컨테이너가 살아 있는지 확인하는 역할을 하고 Healcheck가 실패하면 kubelet이 컨테이너를 죽이게 된다. 그리고, 컨테이너는 yaml에 정의된 restart policy(Always, OnFailure)에 의해 재시작된다.

  • Readiness Probe (준비성 프로브)

Readiness Probe는 Probe가 성공한 경우에만 파드와 연결된 Service와 Pod의 IP가 추가되 트래픽을 받을 수 있다. 여기서 알아야할 점은, Probe 가 "OK" 상태여도 프로세스별 초기화 과정이 틀리기 때문에 아직 준비되지 않는 Pod로 트래픽을 보낼수도 있다. 그럴때는 "minReadySeconds" 옵션을 이용하면 어느정도 해결할 수 있다. 해당 옵션은 Pod가 Status Ready가 될때 까지 기다리는 최소대기시간이다. "minReadySeconds"에 설정된 시간동안은 트래픽을 받지 않는다.

Pod hook

컨테이너가 실행되거나 종료될 때 이벤트를 잡아서 Hook을 걸수가 있는데, preStop이나 preStart를 사용한다. 이 hook 은 API Request나 Probe의 실패, 자원 경합등 이벤트기반으로 컨테이너가 종료되기 직전에 호출된다. 컨테이너가 이미 terminated 또는 completed 상태인 경우 hook 요청은 실패한다. 여기선, preStop만 알아보도록 하자.

  • preStop

preStop을 설정하면 kubelet이 SIGTERM을 보내기전에 실행되기 때문에 컨테이너에 설정과 별개로 graceful shutdown의 효과를 내게 할수도 있다. preStop이 완료되기 전까지는 컨테이너에 SIGTERM을 보내지 않기 때문에 컨테이너의 구현과는 별개로 종료되기 전에 대기시간을 주는 것도 가능해 지게 된다.

terminationGracePeriodSeconds 시간을 초과하면 프로세스 종료가 시작되니, 이를 염두해 두어야 한다.

Deployment Rolling Update를 위한 옵션


Deployment에서 배포할 때 여러가지 옵션중 "maxSurge"와 "maxUnavailable"라는 옵션을 고려해볼 필요가 있다. 두 개의 옵션을 운영중인 서비스의 특정에 맞게 적절히 조절해 주어야지 항상 일정 개수 이상의 Pod가 이용가능하게 되기 때문에 배포중 트래픽 유실이 없게된다.

  • maxSurge

Deployment에서 배포할 때 maxSurge 라는 옵션을 사용해 설정되어 있는 기본 Pod 개수보다 여분의 Pod가 몇개 더 추가될수 있는지를 설정할수 있다.

  • maxUnavailable

maxUnavailable은 업데이트하는 동안 몇개의 Pod가 이용 불가능하게 되어도 되는지 설정하는데 사용된다.

둘다 한꺼번에 0으로 설정되면, Pod가 존재하지 않는 경우가 발생하기 때문에 한꺼번에 0으로 설정할 수는 없습니다.

정리하자면,

kubelet이 SIGTERM을 보내게되면, Pod종료가 시작하게된다. 하지만, 종료가되고 있는 시점에도 Service에는 연결되어 있다. 이렇게 되면 Request에 대한 에러가 발생하는데 이를 위해서 graceful shutdown 하게 하는 방법들이 존재한다.

참고자료


https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/

https://tech.kakao.com/2018/12/24/kubernetes-deploy/

https://aws-diary.tistory.com/124?category=768983

profile
@changhyuni

0개의 댓글