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
- 스프링부트 공식 문서
- 스프링 공식 가이드
- 블로그 글
- Spring Boot Health Indicators
- 쿠버네티스 인 액션 17.3 절