Run multiple services in a container
Estimated reading time: 4 minutes
A container’s main running process is the ENTRYPOINT and/or CMD at the end of the Dockerfile. It is generally recommended that you separate areas of concern by using one service per container. That service may fork into multiple processes (for example, Apache web server starts multiple worker processes). It’s ok to have multiple processes, but to get the most benefit out of Docker, avoid one container being responsible for multiple aspects of your overall application. You can connect multiple containers using user-defined networks and shared volumes.
容器的主要运行过程是 Dockerfile 末尾的 ENTRYPOINT 和/或 CMD。通常建议您通过每个容器使用一个服务来分离关注的领域。该服务可以分叉为多个进程 (例如,Apache web 服务器启动多个工作进程)。有多个流程是可以的,但是为了从 Docker 中获得最大的好处,避免一个容器负责整个应用程序的多个方面。您可以使用用户定义的网络和共享卷连接多个容器。
The container’s main process is responsible for managing all processes that it starts. In some cases, the main process isn’t well-designed, and doesn’t handle “reaping” (stopping) child processes gracefully when the container exits. If your process falls into this category, you can use the --init option when you run the container. The --init flag inserts a tiny init-process into the container as the main process, and handles reaping of all processes when the container exits. Handling such processes this way is superior to using a full-fledged init process such as sysvinit, upstart, or systemd to handle process lifecycle within your container.
容器的主进程负责管理它启动的所有进程。在某些情况下,主进程设计得不好,当容器退出时,不会优雅地处理 “收获” (停止) 子进程。如果您的进程属于此类别,则可以在运行容器时使用-init 选项。—Init 标志将一个微小的 init 进程作为主进程插入到容器中,并在容器退出时处理所有进程的收获。这种方式处理此类进程优于使用成熟的 init 进程 (如 sysvinit 、 upstart 或 systemd) 来处理容器内的进程生命周期。
If you need to run more than one service within a container, you can accomplish this in a few different ways.
如果您需要在一个容器内运行多个服务,您可以通过几种不同的方式来完成。
- Put all of your commands in a wrapper script, complete with testing and debugging information. Run the wrapper script as your
CMD. This is a very naive example. First, the wrapper script:
将所有命令放入包装脚本中,完成测试和调试信息。运行包装脚本作为你的 CMD。这是一个非常天真的例子。首先,包装脚本:
#!/bin/bash# Start the first process./my_first_process -Dstatus=$?if [ $status -ne 0 ]; thenecho "Failed to start my_first_process: $status"exit $statusfi# Start the second process./my_second_process -Dstatus=$?if [ $status -ne 0 ]; thenecho "Failed to start my_second_process: $status"exit $statusfi# Naive check runs checks once a minute to see if either of the processes exited.# This illustrates part of the heavy lifting you need to do if you want to run# more than one service in a container. The container exits with an error# if it detects that either of the processes has exited.# Otherwise it loops forever, waking up every 60 secondswhile sleep 60; dops aux |grep my_first_process |grep -q -v grepPROCESS_1_STATUS=$?ps aux |grep my_second_process |grep -q -v grepPROCESS_2_STATUS=$?# If the greps above find anything, they exit with 0 status# If they are not both 0, then something is wrongif [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; thenecho "One of the processes has already exited."exit 1fidone
Next, the Dockerfile:
FROM ubuntu:latestCOPY my_first_process my_first_processCOPY my_second_process my_second_processCOPY my_wrapper_script.sh my_wrapper_script.shCMD ./my_wrapper_script.sh
If you have one main process that needs to start first and stay running but you temporarily need to run some other processes (perhaps to interact with the main process) then you can use bash’s job control to facilitate that. First, the wrapper script:
如果你有一个主进程需要先开始并保持运行,但是你暂时需要运行一些其他进程 (也许是为了与主进程交互) 然后,您可以使用 bash 的作业控制来实现这一点。首先,包装脚本:
#!/bin/bash# turn on bash's job controlset -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 therefg %1
FROM ubuntu:latestCOPY my_main_process my_main_processCOPY my_helper_process my_helper_processCOPY my_wrapper_script.sh my_wrapper_script.shCMD ./my_wrapper_script.sh
- Use a process manager like
supervisord. This is a moderately heavy-weight approach that requires you to packagesupervisordand its configuration in your image (or base your image on one that includessupervisord), along with the different applications it manages. Then you startsupervisord, which manages your processes for you. Here is an example Dockerfile using this approach, that assumes the pre-writtensupervisord.conf,my_first_process, andmy_second_processfiles all exist in the same directory as your Dockerfile.
FROM ubuntu:latestRUN apt-get update && apt-get install -y supervisorRUN mkdir -p /var/log/supervisorCOPY supervisord.conf /etc/supervisor/conf.d/supervisord.confCOPY my_first_process my_first_processCOPY my_second_process my_second_processCMD ["/usr/bin/supervisord"]
