잡동사니

Doccker stop시 process kill하기 본문

IT

Doccker stop시 process kill하기

yeTi 2021. 2. 22. 13:08

안녕하세요. yeTi입니다.
오늘은 graceful shutdown을 위한 docker container를 종료시 시그널을 받아 처리하는 방안에 대해서 알아보겠습니다.

docker stop

docker stop명령어는 컨테이너내의 메인 프로세스에 SIGTERMSIGKILL을 순차적으로 호출합니다.

신호의 전달은 graceful shutdown을 위해 중요합니다.
하지만, 만일 서비스 프로세스가 메인 프로세스에서 구동할 수 없는 상황이라면 해당 프로세스는 종료 신호를 전달받지 못하여 서비스 종료를 위한 후처리가 불가능합니다.

이에 shell script를 메인 프로세스로 두고 python 서비스에 종료 신호를 전달하는 방안을 알아보고자 합니다.

CMD의 3가지 형식

docker에서 컨테이너를 실행하기 위한 명령어로 CMDENTRYPOINT가 있습니다. 두개의 명령어 중에서 CMD를 기반으로 형식에 따라 내부 프로세스구조가 어떻게 달라지는지 확인해보겠습니다.

전체적인 샘플코드는 다음과 같습니다.

# Dockerfile

FROM ubuntu

Add start-ho.sh /usr/src/app/start-ho.sh
RUN ["chmod", "+x", "/usr/src/app/start-ho.sh"]

CMD ["sh", "-c", "/usr/src/app/start-ho.sh"]
# CMD ["/usr/src/app/start-ho.sh"]
# CMD /usr/src/app/start-ho.sh
# start-ho.sh

#!/bin/bash

while [[ 1=1 ]]; do
    echo "run"
    sleep 1
done

위와 같이 작성한 코드를 컨테이너로 구동하면 내부 프로세서는 다음과 같이 생성됩니다.

$ docker exec -it ho-docker ps -x
  PID TTY      STAT   TIME COMMAND
    1 pts/0    Ss+    0:00 sh -c /usr/src/app/start-ho.sh
    6 pts/0    S+     0:00 /bin/bash /usr/src/app/start-ho.sh
    8 pts/0    S+     0:00 sleep 1
    9 pts/1    Rs+    0:00 ps -x

메인 프로세스가 shell이 되고 /usr/src/app/start-ho.sh을 실행하으로 docker stop에 대한 시그널을 start-ho script에서 받을 수 없습니다.

Dockerfile에서 CMD를 다음과 같이 변경해 보겠습니다.

CMD ["/usr/src/app/start-ho.sh"]

컨테이너의 메인 프로세서로 샘플로 작성한 start-ho script가 구동된것을 확인할 수 있습니다.

$ docker exec -it ho-docker ps -x
  PID TTY      STAT   TIME COMMAND
    1 pts/0    Ss+    0:00 /bin/bash /usr/src/app/start-ho.sh
   12 pts/0    S+     0:00 sleep 1
   13 pts/1    Rs+    0:00 ps -x

마지막으로 다음을 수행해보면

CMD /usr/src/app/start-ho.sh

CMD ["sh", "-c", "/usr/src/app/start-ho.sh"]과 마찬가지로 메인 프로세스가 shell이 되고 /usr/src/app/start-ho.sh를 실행하는것을 확인할 수 있습니다.

$ docker exec -it ho-docker ps -x
  PID TTY      STAT   TIME COMMAND
    1 pts/0    Ss+    0:00 /bin/sh -c /usr/src/app/start-ho.sh
    6 pts/0    S+     0:00 /bin/bash /usr/src/app/start-ho.sh
    8 pts/0    S+     0:00 sleep 1
    9 pts/1    Rs+    0:00 ps -x

따라서 도커실행시 CMD ["/usr/src/app/start-ho.sh"] 형식으로 작성해야 shell script에서 시그널을 받을 수 있습니다.

shell script에서 signal 잡기

shell script에서 서비스를 백그라운드로 구동한 이후에 pid를 가지고 있는 파일을 계속 관찰한 후 시그널이 들어오면 해당 pidkill하는 방식으로 샘플을 작성했습니다.

# kill_child.sh

python3 child.py &

trap  "sigterm; exit" SIGTERM

function  sigterm() {
  echo  "Catch SIGTERM"
  echo  "Try kill pid $value"
  kill  "$value"
}

while [[ 1=1 ]]; do
  value=`cat deamon.pid`
  sleep 1
done

python으로 작성한 샘플 서비스는 pid를 특정 파일에 저장합니다.

import time
import os
import sys

pid = str(os.getpid())

with open("deamon.pid", "w") as f:
    f.write(pid)

while True:
    print('running')
    time.sleep(1)
Comments