在容器中运行多个进程
容器的主要运行进程是 `Dockerfile` 末尾的 `ENTRYPOINT` 和/或 `CMD`。最佳实践是通过为每个容器使用一个服务来分离关注点。该服务可能会分叉成多个进程(例如,Apache Web 服务器会启动多个工作进程)。拥有多个进程是可以的,但为了从 Docker 中获得最大收益,请避免让一个容器负责整个应用程序的多个方面。您可以使用用户定义的网络和共享卷来连接多个容器。
容器的主进程负责管理其启动的所有进程。在某些情况下,主进程设计不佳,在容器退出时无法优雅地处理“回收”(停止)子进程。如果您的进程属于此类别,您可以在运行容器时使用 `--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.confmy_first_processmy_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