在容器中運行多個程序
容器的主要執行程序是 Dockerfile
結尾的 ENTRYPOINT
和/或 CMD
。最佳實務是將關注點分離,每個容器使用一個服務。該服務可能會分支成多個程序(例如,Apache 網頁伺服器會啟動多個工作程序)。可以有多個程序,但為了充分利用 Docker,請避免一個容器負責整體應用程式的多個方面。您可以使用使用者定義的網路和共用磁碟區連線多個容器。
容器的主要程序負責管理它啟動的所有程序。在某些情況下,主要程序設計不佳,並且在容器退出時無法正常地「回收」(停止)子程序。如果您的程序屬於此類別,則可以在執行容器時使用 --init
選項。--init
旗標會將一個小型 init 程序作為主要程序插入容器中,並在容器退出時處理所有程序的回收。以這種方式處理此類程序優於使用完整的 init 程序(例如 sysvinit
或 systemd
)來處理容器內的程序生命週期。
如果您需要在容器中執行多個服務,您可以透過幾種不同的方式來實現。
使用包裝器腳本
將所有命令放入包裝器腳本中,並附上測試和除錯資訊。將包裝器腳本作為您的 CMD
執行。以下是一個簡單的範例。首先,包裝器腳本
#!/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 作業控制
如果您有一個需要先啟動並保持執行的主要程序,但您暫時需要執行其他一些程序(可能與主要程序互動),則可以使用 bash 的作業控制。首先,包裝器腳本
#!/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
使用程序管理器
使用像 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"]
如果您想確保兩個程序都將其 stdout
和 stderr
輸出到容器日誌,您可以將以下內容新增到 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