Kubernetes

[Kubernetes] k8s 환경에서 springboot graceful shutdown 방법

흥부가귀막혀 2024. 1. 29. 15:57

문제 상황

  • (1) request 처리 도중 Pod 이 종료되면 Request 가 비정상적으로 처리될 수 있음
  • (2) Pod 이 종료될 때 종료 중인 Pod 에 request 가 들어오면 클라이언트는 connection refused 에러를 만나게 됨

문제 해결을 위한 과정

  • (1)번 이슈는 Spring 에서 제공해주는 Graceful Shutdown 설정을 통해 해결 가능하다.
server:
    shutdown: graceful
  • (2)번 상황을 막기 위해 Readiness Probe 를 /actuator/health endpoint 로 잡아주고 Custom Health Indicator 를 구현하여 API 로 유입된 값에 따라 Application 상태를 Active/Inactive 하게 변경할 수 있게 하였다.
  • 이렇게 하면 prestop 훅에 Application 상태를 Inactive 로 변경하여 Readiness Probe 를 통해 Service 에서 제외하고 Graceful Shutdown 을 하여 (2) 번 상황을 해결할 수 있을거라 판단하였다.
  • 내가 진행한 방법이 Best Practice 일거라 생각했지만, 스프링 공식 가이드 문서를 보니 이게 왠걸.. 단순히 sleep 만 걸어주면 된다고 정리되어 있었다.
  • 그래서 이게 왜 그런지 확인해보았다.

Pod 종료 절차

  • Pod 를 종료하면 위와 같은 절차가 진행되게 된다.
    • A : Pod 종료 sequence
    • B : 종료되는 Pod 으로 Request 가 가지 않도록 IP 를 변경하는 sequence
      • B2 : 삭제되는 Pod 이 속한 Service 의 엔드포인트에서 삭제될 Pod 제거 (엔드포인트 API 오브젝트 수정)
      • B3 : 각 노드에서 iptables 를 업데이트해서 연결이 종료되는 Pod 으로 새로운 커넥션이 전달되지 않도록 함
      • 보다 완전한 이해를 위해서는 kube-proxy, iptables 등 개념에 대한 학습이 필요할 듯 하다.

  • 별도 작업을 해주지 않으면 B 의 sequence 가 더 오래 걸린다. 따라서 위와 같이 connection refused 되는 request 가 생겨날 수 있다.

Sleep 을 하면 어떻게 될까?

  • prestop 훅에 sleep 추가
  • sleep 을 통해 iptables 가 변경되기 위해 필요한 시간을 확보한다.
  • iptables 가 변경될때까지 Sleep 을 통해 Application 이 종료되지 않기 때문에 자연스럽게 Graceful Shutdown 을 수행할 수 있게 된다.

결론

  • 내가 진행했던 Custom Headlth Indicator 와 Readness Probe 를 사용하는 전략도 이슈는 없지만 굳이 그렇게 할 필요는 없다.
  • k8s 환경에서 spring boot 의 graceful shutdown 을 위해서는 아래 두 가지 설정이 필요하다.
    • Spring Application Properties 에 graceful shutdown 설정 추가
    • prestop hook 에 sleep 커맨드 추가
  • 어설픈 지식보단 공식문서와 전체적인 개념을 잘 파악하자

References