容器的主要运行进程是 Dockerfile 末尾的 ENTRYPOINT 和/或 CMD。通常建议您通过每个容器使用一项服务来分隔关注区域。该服务可能会fork成多个进程(例如,Apache Web 服务器启动多个工作进程)。拥有多个进程是可以的,但要从 Docker 中获得最大收益,请避免一个容器负责整个应用程序的多个方面。您可以使用用户定义的网络和共享卷连接多个容器。 容器的主进程负责管理它启动的所有进程。在某些情况下,主进程没有经过精心设计,并且在容器退出时无法优雅地处理“收割”(停止)子进程。如果您的进程属于此类别,则可以在运行容器时使用 --init 选项。 --init 标志将一个微小的 init 进程作为主进程插入到容器中,并在容器退出时处理所有进程的收割。以这种方式处理此类进程优于使用成熟的 init 进程(如 sysvinit、upstart 或 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 的作业控制来促进这一点。首先,包装脚本:
#!/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 文件都与 Dockerfile 存在于同一目录中。
# 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"]