컨테이너에서 여러 프로세스 실행하기

컨테이너에서 여러 프로세스 실행하기 (Run multiple processes in a container)

컨테이너의 주요 실행 프로세스는 Dockerfile 끝의 ENTRYPOINT 및/또는 CMD예요. 한 컨테이너에 하나의 서비스를 사용해 관심사를 분리하는 것이 모범 사례예요. 그 서비스가 여러 프로세스로 분기할 수는 있어요(예를 들어 Apache 웹 서버는 여러 워커 프로세스를 시작해요). 여러 프로세스를 갖는 것은 괜찮지만, Docker의 이점을 최대한 얻으려면 하나의 컨테이너가 전체 애플리케이션의 여러 측면을 담당하지 않도록 피해야 해요. 사용자 정의 네트워크와 공유 볼륨을 사용해 여러 컨테이너를 연결할 수 있어요.

출처: 문서

본문

컨테이너의 주요 프로세스는 자기가 시작한 모든 프로세스를 관리할 책임이 있어요. 어떤 경우에는 주요 프로세스가 잘 설계되지 않아 컨테이너가 종료될 때 자식 프로세스를 "수확"(reaping, 중지)하지 못할 수도 있어요. 프로세스가 이 범주에 해당한다면 컨테이너를 실행할 때 --init 옵션을 사용할 수 있어요. --init 플래그는 주요 프로세스로 아주 작은 init 프로세스를 컨테이너에 삽입하고, 컨테이너가 종료될 때 모든 프로세스의 수확을 처리해요. 이렇게 프로세스를 처리하는 것은 sysvinit이나 systemd 같은 완전한 init 프로세스를 사용해 컨테이너 안의 프로세스 수명주기를 처리하는 것보다 우수해요.

컨테이너 안에서 하나 이상의 서비스를 실행해야 한다면 몇 가지 다른 방법으로 달성할 수 있어요.

래퍼 스크립트 사용 (Use a wrapper script)

모든 명령을 테스트·디버깅 정보를 포함한 래퍼 스크립트에 넣어요. 래퍼 스크립트를 CMD로 실행해요. 다음은 단순한(naive) 예시예요. 먼저 래퍼 스크립트:

#!/bin/bash

# Start the first process
./my_first_process &

# Start the second process
./my_second_process &

# Wait for any process to exit
wait -n

# Exit with status of process that exited first
exit $?

다음으로 Dockerfile:

# syntax=docker/dockerfile:1
FROM ubuntu:latest
COPY my_first_process my_first_process
COPY my_second_process my_second_process
COPY my_wrapper_script.sh my_wrapper_script.sh
CMD ./my_wrapper_script.sh

Bash 작업 제어 사용 (Use Bash job controls)

먼저 시작해 계속 실행해야 하는 주요 프로세스가 하나 있고, (아마도 주요 프로세스와 상호작용하기 위해) 일시적으로 다른 프로세스를 실행해야 한다면 bash의 작업 제어(job control)를 사용할 수 있어요. 먼저 래퍼 스크립트:

#!/bin/bash

# turn on bash's job control
set -m

# Start the primary process and put it in the background
./my_main_process &

# Start the helper process
./my_helper_process

# the my_helper_process might need to know how to wait on the
# primary process to start before it does its work and returns

# now we bring the primary process back into the foreground
# and leave it there
fg %1
# syntax=docker/dockerfile:1
FROM ubuntu:latest
COPY my_main_process my_main_process
COPY my_helper_process my_helper_process
COPY my_wrapper_script.sh my_wrapper_script.sh
CMD ./my_wrapper_script.sh

프로세스 매니저 사용 (Use a process manager)

supervisord 같은 프로세스 매니저를 사용해요. 이 방법은 다른 옵션보다 더 복잡한데, 이미지에 supervisord와 그 구성(또는 supervisord를 포함하는 이미지를 베이스로)을 관리하는 다양한 애플리케이션과 함께 번들로 포함해야 하기 때문이에요. 그런 다음 supervisord를 시작하면 프로세스를 대신 관리해줘요.

다음 Dockerfile 예시는 이 접근 방식을 보여줘요. 이 예시는 다음 파일들이 빌드 컨텍스트의 루트에 존재한다고 가정해요:

  • supervisord.conf
  • my_first_process
  • my_second_process
# syntax=docker/dockerfile:1
FROM ubuntu:latest
RUN apt-get update && apt-get install -y supervisor
RUN mkdir -p /var/log/supervisor
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY my_first_process my_first_process
COPY my_second_process my_second_process
CMD ["/usr/bin/supervisord"]

두 프로세스가 모두 stdoutstderr를 컨테이너 로그로 출력하게 하려면 supervisord.conf 파일에 다음을 추가할 수 있어요:

[supervisord]
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0

[program:app]
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true

더 알아보기 (Learn more)