在容器中運行多個程序

容器的主要執行程序是 Dockerfile 結尾的 ENTRYPOINT 和/或 CMD。最佳實務是將關注點分離,每個容器使用一個服務。該服務可能會分支成多個程序(例如,Apache 網頁伺服器會啟動多個工作程序)。可以有多個程序,但為了充分利用 Docker,請避免一個容器負責整體應用程式的多個方面。您可以使用使用者定義的網路和共用磁碟區連線多個容器。

容器的主要程序負責管理它啟動的所有程序。在某些情況下,主要程序設計不佳,並且在容器退出時無法正常地「回收」(停止)子程序。如果您的程序屬於此類別,則可以在執行容器時使用 --init 選項。--init 旗標會將一個小型 init 程序作為主要程序插入容器中,並在容器退出時處理所有程序的回收。以這種方式處理此類程序優於使用完整的 init 程序(例如 sysvinitsystemd)來處理容器內的程序生命週期。

如果您需要在容器中執行多個服務,您可以透過幾種不同的方式來實現。

使用包裝器腳本

將所有命令放入包裝器腳本中,並附上測試和除錯資訊。將包裝器腳本作為您的 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"]

如果您想確保兩個程序都將其 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