[node.js] k8s 환경에서 graceful shutdown을 해도 pod 재시작시 502, 504 에러가 발생하는 경우 (502 and 504 Errors Occur Even with Graceful Shutdown in Kubernetes Pod Restarts)
node.js 2025. 3. 10. 18:31
node.js 버전 19 이상인 경우 http 서버에서 server.close()를 호출하면 아래 사항들을 전부 처리해줘서 graceful shutdown이 가능함.
1. accept를 더이상 받지 않아 신규 연결 생성 중지
2. 처리하던 요청은 다 처리
3. keep alive를 위해 연결되어 있던 idle socket도 다 종료시킴
만약 그 이전 버전이면 버전에 따라 2, 3번 사항을 수동으로 처리해줘야 할 필요도 있음.
하지만 node.js v22인 상황에서 k8에서 pod를 재시작할 때마다 502, 504 에러가 소수 발생하는 상황이 지속되어 원인분석 시작.
일단 probe에서 intial delay seconds를 30초까지 늘여봤으나 효과가 없었음.
그리고 조사를 하던 중,
k8s에서 pod를 종료시킬 때 pod에 SIGTERM을 보내 pod 내부의 서버 프로세스가 종료되어도,
기존 nginx ingress 등이 아직 그 상황이 적용되지 못한 찰나의 순간에 이미 죽은 pod로 요청이 들어갈 수 잇어서,
기본적으로 server.close() 호출 전 아래처럼 임의의 대기시간을 주는 방식이 필요하다고 함.
참고: https://github.com/godaddy/terminus?tab=readme-ov-file#how-to-set-terminus-up-with-kubernetes
process.on('SIGTERM', async()=>{
// pod가 종료되는 중 nginx ingress에서 요청이 들어올 경우 처리를 위한 대기시간
await new Promise(res => setTimeout(res, 5000));
server.close(...);
});
하지만 이 대기시간을 30초까지 줘봐도 효과가 없었음. (probe 30초 + 30초 = 1분)
조금 더 알아보다가 테스트를 위해 로컬 도커 컨테이너를 중지시키려고 docker stop <컨테이너ID> 를 실행시키니 대기시간 없이 곧바로 종료되는 현상을 발견.
그래서 컨테이너에 들어가 ps 로 알아보니 node.js 서버 프로세스가 PID 1 이 아닌 상황.
왜 그럴까 궁금해서 알아보니 Dockerfile 에서 node.js 서버 프로세스 실행시 명령어가 아래와 같았음.
CMD ["npm", "start", "--silent"]
이렇게 되면 실제 node.js 프로세스는 npm 부터 이어지는 자식 프로세스로 생성되기 때문에,
SIGTERM을 직접 받지 못하고,
그로 인해 컨테이너는 즉시 종료되어 버리는 상황이었음.
node.js 서버 프로세스 실행 명령어를 아래처럼 직접 실행하는 방식으로 해결.
CMD ["node", "index.js"]
tini 같이 PID 1 로 실행하기 위한 이런저런 방법들도 있는데 딱히 다르게 실행해야할 이유가 없다면 직접 실행하는 방식이 제일 좋은 듯.