하나의 Docker 컨테이너에서 여러 서비스를 실행하는 방법
게시 됨: 2022-06-30Docker는 스택의 구성 요소를 격리된 컨테이너로 패키징하는 기술입니다. 각 프로세스를 자체 컨테이너에서 실행하여 구성 요소 간에 명확한 구분을 만드는 것이 일반적입니다. 이를 통해 모듈화가 향상되고 컨테이너화의 확장성 이점에 액세스할 수 있습니다.
단일 컨테이너 내에서 여러 서비스를 실행하려는 상황이 여전히 있을 수 있습니다. 이것은 Docker 에코시스템에서 자연스럽게 이루어지지는 않지만 하나 이상의 수명이 긴 프로세스로 컨테이너를 생성하는 데 사용할 수 있는 몇 가지 다른 접근 방식을 보여줍니다.
문제 식별
Docker 컨테이너는 단일 포그라운드 프로세스를 실행합니다. 이것은 이미지의 ENTRYPOINT
및 CMD
명령에 의해 정의됩니다. ENTRYPOINT
는 이미지의 Dockerfile
내에서 설정되는 반면 CMD
는 컨테이너를 생성할 때 재정의될 수 있습니다. 컨테이너는 포그라운드 프로세스가 종료되면 자동으로 중지됩니다.
CMD
에서 다른 프로세스를 시작할 수 있지만 컨테이너는 원래 포그라운드 프로세스가 살아있는 동안에만 계속 실행됩니다. ENTRYPOINT/CMD
메커니즘을 사용하여 두 개의 독립적인 서비스의 결합된 수명을 통해 컨테이너를 작동 상태로 유지하는 것은 직접 가능하지 않습니다.
하나의 진입점에서 여러 프로세스 래핑
래퍼 스크립트는 문제에 대한 가장 간단한 솔루션입니다. 모든 프로세스를 시작하고 완료될 때까지 기다리는 스크립트를 작성할 수 있습니다. 스크립트를 Docker ENTRYPOINT
로 설정하면 컨테이너의 포그라운드 프로세스로 실행되어 래핑된 스크립트 중 하나가 종료될 때까지 컨테이너가 계속 실행됩니다.
#!/bin/bash /opt/첫 번째 프로세스 & /opt/두 번째 프로세스 & 기다려 -n 종료 $?
이 스크립트는 컨테이너 내부에서 /opt/first-process
및 /opt/second-process
바이너리를 시작합니다. &
를 사용하면 각 프로세스가 종료될 때까지 기다리지 않고 스크립트를 계속할 수 있습니다. wait
는 프로세스 중 하나가 종료될 때까지 스크립트를 일시 중단하는 데 사용됩니다. 그런 다음 스크립트는 완료된 스크립트에서 발행한 상태 코드와 함께 종료됩니다.
이 모델은 컨테이너가 first-process
와 second-process
중 하나가 종료될 때까지 모두 실행되도록 합니다. 이 시점에서 다른 프로세스가 아직 실행 중일지라도 컨테이너가 중지됩니다.
이 스크립트를 사용하려면 Docker 이미지의 ENTRYPOINT
및 CMD
를 수정하여 컨테이너의 포그라운드 프로세스로 만듭니다.
진입점 ["/bin/sh"] CMD ["./경로/to/script.sh"]
--init
컨테이너 옵션
컨테이너 프로세스 관리의 한 가지 문제는 프로세스가 종료될 때 효과적으로 정리하는 것입니다. Docker는 CMD
를 프로세스 ID 1로 실행하여 신호 처리 및 좀비 제거를 담당합니다. 스크립트에 이러한 기능이 없으면 컨테이너 내부에서 고아 자식 프로세스가 지속되게 될 수 있습니다.
docker run
명령에는 tini
를 PID 1로 사용하도록 진입점을 수정하는 --init
플래그가 있습니다. 이것은 CMD
를 실행하고, 신호 전달을 처리하고, 계속해서 좀비를 수확하는 최소 초기화 프로세스 구현입니다.
많은 프로세스를 생성할 것으로 예상되고 수동으로 정리를 처리하지 않으려는 경우 --init
를 사용하는 것이 좋습니다. Tini는 컨테이너용으로 설계된 가벼운 초기화 맛입니다. systemd
및 upstart
와 같은 완전한 대안보다 훨씬 작습니다.
전용 프로세스 관리자 사용
수동 스크립팅은 관리해야 할 프로세스가 많을 때 신속하게 차선책이 됩니다. 프로세스 관리자를 채택하는 것은 Docker 컨테이너 내에서 여러 서비스를 실행하는 또 다른 방법입니다. 프로세스 관리자는 ENTRYPOINT
가 되며 작업자 프로세스를 시작, 유지 관리 및 정리할 책임이 있습니다.
이 접근 방식을 구현할 때 사용할 수 있는 몇 가지 옵션이 있습니다. supervisord
는 /etc/supervisor/conf.d/supervisord.conf
파일을 통해 쉽게 구성할 수 있는 인기 있는 선택입니다.
[프로그램:apache2] 명령=/usr/sbin/apache2 -DFOREGROUND [프로그램:mysqld] 명령=/usr/sbin/mysqld_safe
이 구성 파일은 Apache 및 MySQL을 시작하도록 supervisord
를 구성합니다. Docker 컨테이너에서 사용하려면 필요한 모든 패키지를 이미지에 추가한 다음 supervisord
구성 파일을 올바른 위치에 복사하십시오. 컨테이너가 시작될 때 자동으로 실행되도록 supervisord
를 이미지의 CMD
로 설정합니다.
우분투에서:최신 apt-get install -y apache2 mysql-server 감독자 실행 복사 supervisord.conf /etc/supervisor/conf.d/supervisord.conf 진입점 ["/bin/sh"] CMD ["/usr/bin/supervisord"]
supervisord
는 계속 실행되기 때문에 모니터링되는 프로세스 중 하나가 종료될 때 컨테이너를 중지할 수 없습니다. 대체 옵션은 이 기능이 있는 s6-overlay
입니다. 서비스 스크립트를 /etc/services.d
에 직접 배치하는 선언적 서비스 모델을 사용합니다.
# 이미지에 s6 오버레이 추가 추가 https://github.com/just-containers/s6-overlay/releases/download/v3.1.0.0/s6-overlay-noarch.tar.xz /tmp 실행 tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz RUN printf "#!/bin/shn/usr/sbin/apache2 -DFOREGROUND"> /etc/services.d/first-service/run 실행 chmod +x /etc/services.d/first-service/run # s6-overlay를 이미지의 진입점으로 사용 진입점 ["/초기화"]
서비스 디렉토리 내에 실행 가능한 finish
스크립트를 추가하여 docker stop
으로 컨테이너 중지를 처리할 수 있습니다. s6-overlay
는 해당 프로세스가 stop
명령으로 인해 TERM
신호를 수신할 때 이러한 스크립트를 자동으로 실행합니다.
Finish 스크립트는 서비스의 종료 코드를 첫 번째 인수로 받습니다. 잡히지 않은 신호로 인해 서비스가 종료되면 코드는 256으로 설정됩니다. 스크립트는 최종 종료 코드를 /run/s6-linux-init-container-results/exitcode
. s6-overlay는 이 파일을 읽고 그 안에 있는 값으로 종료하여 해당 코드를 컨테이너의 중지 코드로 사용합니다.
#!/bin/sh echo "$1" > /run/s6-linux-init-container-results/exitcode
컨테이너에서 여러 프로세스를 실행해야 하는 경우는 언제입니까?
이 기술은 독립적인 컨테이너로 실행하기 위해 분리할 수 없는 밀접하게 연결된 프로세스와 함께 사용하는 것이 가장 좋습니다. 백그라운드 도우미 유틸리티 또는 개별 프로세스의 자체 관리를 수행하는 모놀리식 애플리케이션에 의존하는 프로그램이 있을 수 있습니다. 위에 표시된 기술은 이러한 유형의 소프트웨어를 컨테이너화하는 데 도움이 될 수 있습니다.
컨테이너에서 여러 프로세스를 실행하는 것은 가능한 한 여전히 피해야 합니다. 단일 포그라운드 프로세스를 고수하면 격리가 최대화되고 구성 요소가 서로 간섭하지 않으며 특정 부분을 디버그 및 테스트하는 능력이 향상됩니다. 컨테이너 오케스트레이터를 사용하여 구성 요소를 개별적으로 확장할 수 있으므로 가장 리소스 집약적인 프로세스의 더 많은 인스턴스를 유연하게 실행할 수 있습니다.
결론
컨테이너에는 일반적으로 하나의 포그라운드 프로세스가 있으며 살아 있는 동안 실행됩니다. 이 모델은 컨테이너화 모범 사례와 일치하며 기술의 이점을 최대한 활용할 수 있습니다.
어떤 상황에서는 컨테이너에서 실행하기 위해 여러 프로세스가 필요할 수 있습니다. 모든 이미지에는 궁극적으로 단일 진입점이 있으므로 래퍼 스크립트를 작성하거나 대상 바이너리 시작을 담당하는 프로세스 관리자를 추가해야 합니다.
프로세스 관리자는 필요한 모든 것을 제공하지만 추가 패키지 및 구성으로 이미지를 부풀립니다. 래퍼 스크립트는 더 간단하지만 좀비 프로세스 확산을 방지하기 위해 Docker의 --init
플래그와 쌍을 이루어야 할 수도 있습니다.