本文翻译自 https://docs.docker.com/config/containers/multi-service_container/
我们都知道,所谓的容器就是一个被隔离到不同环境的进程而已,那我们如果在一个容器内运行多个进程呢?
一个容器的主进程是 ENTRYPOINT
或者在 Dockerfile
最后的 CMD
,
容器的主进程负责管理它启动的全部进程。
在某些条件下,主进程由于出错而退出,容器退出时,主进程并不能优雅地处理停止的子进程。
如果你的进程会出现上述情况,你启动容器时可以使用 --init
标志,在容器内插入一个简易的初始化进程作为主进程,容器退出时INIT
处理这些停止的子进程 ---- 子进程作为孤儿进程会被托管到 INIT 进程
用上述方式管理容器的生命周期比使用笨重的 sysinit
, upstart
, 或者 systemd
更优雅
如果需要在一个容器内运行多个服务,你可以通过下面几种不同方式解决。
-
将全部的命令都封装到脚本中,并将脚本作为 CMD 执行。这是一个非常原生的做法。
比如1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36#!/bin/bash
# Start the first process
./my_first_process -D
status=$?
if [ $status -ne 0 ]; then
echo "Failed to start my_first_process: $status"
exit $status
fi
# Start the second process
./my_second_process -D
status=$?
if [ $status -ne 0 ]; then
echo "Failed to start my_second_process: $status"
exit $status
fi
# 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 seconds
while sleep 60; do
ps aux |grep my_first_process |grep -q -v grep
PROCESS_1_STATUS=$?
ps aux |grep my_second_process |grep -q -v grep
PROCESS_2_STATUS=$?
# If the greps above find anything, they exit with 0 status
# If they are not both 0, then something is wrong
if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; then
echo "One of the processes has already exited."
exit 1
fi
doneDockerfile
1
2
3
4
5FROM 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 的任务控制解决。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 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 %1Dockerfile
1
2
3
4
5FROM 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
的镜像),然后启动supervisor,它会根据配置文件代你管理进程,下面是一个使用 supervisord 的 Dockerfill,我们假定已经预先写好了supervisord.conf
,my_first_process
,my_second_process
,并放到与Dockerfile
同级的目录1
2
3
4
5
6
7FROM 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"]