在容器中執行多個程序
容器的主要執行程序是 `Dockerfile` 末尾的 `ENTRYPOINT` 和/或 `CMD`。最佳實踐是使用一個容器一個服務來分離關注點。該服務可能會派生出多個程序(例如,Apache Web 伺服器啟動多個工作程序)。在一個容器中擁有多個程序是可以的,但為了充分利用 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