PID 1 + Docker&K8s Q.A.
- Docker/K8s에서 PID 1이 왜 중요한가요?
- 배포할 때 간헐적으로 502가 난다면 어떻게 할건가요?(시그널을 못받은 경우)
- 어떻게 해결하나요?
- exec form이면 tini 없이도 되지 않나요?
발생 가능한 문제들
1. 좀비 프로세스(Zombile Process) 누적
PID 1 (java app)
|-- fork된 child process -> 종료됨
-> 부모가 wait() 안 하면 좀비로 남음
-----
- 일반 앱(java 포함)은 "wait()" syscall로 자식을 reap하는 로직이 없음
- 좀비가 쌓이면 PID 테이블 고갈 -> 새 프로세스 생성 불가
- 특히 문제가 되는 경우
1. shell script로 여러 프로세스를 fork 하는 경우
2. JVM 내부에서 native process를 실행할 때(Runtime.exec(), ProcessBuilder)
2. SIGTERM 무시 → 강제 종료(SIGKILL)
쉘을 통해 실행할 경우
--------------------
CMD ["sh", "-c", "java -jar app.jar"]
이 경우
-------
- 'sh'가 PID 1이 되고, 'java'는 PID 2가 됨
- 'docker stop' / k8s pod 종료 시 SIGTERM을 sh에 전달
- sh는 자식에게 "시그널을 전달하지 않음"
- "terminationGracePeriodSeconds" 초과 후 SIGKILL로 강제 종료
위 결과
-------
docker stop -> SIGTERM -> [sh(PID1)] -> java(PID2) 전달 안됨 -> 30초 후 SIGKILL
3. K8s Gradceful Shutdown 미동작
k8s.yaml
--------
spec:
terminationGracePeriodSeconds: 60
containers:
- lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 10"]
- Spring Boot의
server.shutdown=gracefule 설정이 있어도
- SIGTERM이 JVM에 도달하지 않으면 graceful shutdown hook 자체가 실행 안 됨
- In-flight request 처리 중 연결 강제 종료
4. exec form vs shell form 혼동
sh form
-------
CMD java -jar app.jar
CMD ["sh", "-c", 'java -jar app.jar"]
Exec form
---------
CMD ["java", "-jar", "app.jar"]
해결법