在容器中运行多个进程

容器的主要运行进程是Dockerfile末尾的ENTRYPOINT和/或CMD。最佳实践是每个容器使用一项服务来分离关注点。该服务可能会派生出多个进程(例如,Apache Web服务器启动多个工作进程)。拥有多个进程是可以的,但是为了最大限度地利用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