이슈사항
- 유레카 서버 client가 주기적으로 heartbeat를 보내게 되는데, 서버 자체가 느려서 heartbeat를 제한시간 내에 보내지 못하는 이슈가 존재해서 확인(근데 애초에 heartbeat 시간 설정도 이상하게 돼있긴 했지만...)
- 그런데 확인해보니 chrome 이 한 서버당 다수 떠있는 것을 확인
ps -ef | grep chrome | wc -l
37403
명령어를 쳐서 프로세스들이 어떻게 구성돼있나 확인해보면 아래와 같다
ps -o pid, ppid, cmd -C chrome
ps -eo pid, ppid, comm | grep -v "chrome"
- 부모 process 번호가 1번(현재는 springboot 서버이므로 java)인 chrome창이 다수 떠있는 것을 확인할 수 있음
- 실제로 chromedriver을 이용해 chrome을 띄울 경우에는 아래와 같은 pstree 구조를 가져야 정상임

- docker 내부의 PID 1번 process 는 java
그리고 docker stop시 아래와 같은 경고가 뜨는 것 또한 확인할 수 있음
docker stop inquiry-collector.2.ycq1wdm9i4gvf8cjtqbnb43ip
Error response from daemon: cannot stop container:
inquiry-collector.2.ycq1wdm9i4gvf8cjtqbnb43ip:
container 5acf80b07cd3 PID 16264 is zombie and can not be killed.
Use the --init option when creating containers to run an init inside the container
that forwards signals and reaps processes
- docker stop은 graceful shutdown이기 때문에 좀비 프로세스가 존재할 경우 위와 같은 경고가 생김
알아야 할 배경 지식
문제 해결을 위해서는 아래 두개를 확인해야함
1. 왜 defunct 프로세스가 생겼는가
2. docker 내부에서 init이 왜 제대로 실행되지 않았는가
그에 앞서서 필요한 배경지식은 아래와 같다
1. defunct process(좀비 프로세스)란 무엇인가
- 부모 프로세스에게 종료 상태를 전달하지 못한 자식 프로세스
- 부모 프로세스는 자식 프로세스가 종료되면 종료 코드를 얻기 위해 대기(wait)
- 종료 코드는 프로세스 테이블에 저장되고 부모 테이블은 종료 코드를 읽게 됨(reaping)
- 좀비 상태 : exit을 마치고 부모 프로세스가 자신의 exit status를 읽어가기 기다리는 상태
- cf) 부모 프로세스가 자식 프로세스보다 먼저 죽으면 고아 프로세스가 됨(Orpahn process)
종료가 됐기 때문에 CPU를 사용하지는 않지만, 프로세스 테이블의 공간을 차지하고
프로세스 테이블은 RAM에 저장됨
때문에 defunct가 많아질 경우 다른 프로세스에 영향을 줄 수 있음
2. docker 의 multiple process 관리(cf. 컨테이너가 아닌 환경)

- 컨테이너의 main running process는 ENTRYPOINT나 CMD로 실행시킨 프로세스
- 실제로 우리 수집기 도커는 pid 1번이 java였음
- 도커는 하나의 컨테이너에서는 하나의 서비스만 실행하는 것을 이상적이라고 생각함
- main processs는 모든 프로세스 관리에 책임이 있음
- 만일 그러한 init 기능이 잘 이뤄지지 않는다 판단되면 —init option으로 tiny init process를 main프로세스로 넣을 수 있음

- 컨테이너가 아닌 리눅스 환경 pid 1번은 systemd
- zombie 프로세스를 init(또는 systemd) 프로세스의 자식으로 입양시킴
- init이나 systemd는 주기적으로 waitpid()를 통해 zombie 프로세스를 종료시켜줌
해결 방법 모색
- 왜 defunct 프로세스가 생겼는가..

실제로 디버깅을 해보면 new chromeDriver() 동작 과정에서 defunct chrome 프로세스가 생기기도 하는 것 같기도 함(컨테이너 환경이 아니라 일반 로컬 개발환경에서 진행, 정상인 동작 상태 )
하지만 도커와 관련해서 탐구해보면
도커 내부에서는 기본적으로 프로세스가 끝나도 처리를 하지 않는 구조여서 그렇다 (명시적으로 kill을 하지 않는 이상..)
간단한 테스트를 해보자면

- defunct가 된 프로세스가 수거되지 않고 있는 것을 확인할 수 있다
때문에 --init option을 추가하면
- 1번 프로세스가 /sbin/docker-init인 것을 확인(tiny init 프로세스)
- 자식의 자식 프로세스가 좀비 프로세스가 됐을 경우에 수거를 해가는 것을 확인


그래서 결론적으로는 --init 옵션을 추가하여 해결했다