要如何在 container 里运行多个 process

延续 Docker 启动 process 的主题,因 container 即 process,因此合理的设计方法会是一个 container 只执行一个 process。而且 Dockerfile 也只能设定一个 ENTRYPOINT 和 CMD,实际上也很难跑多个 process。

但如果真的需要一个 container 同时跑多个 process 的话,该怎麽做呢?

开始前,先来定义简单的目标:

  1. 使用 httpd image,Alpine 版本
  2. 在同一个 container 里,同时启动 httpd 与 top 两个指令

使用 docker exec

山不转,路转。即然 Dockerfile 或 docker run 不行的话,那就先 docker rundocker exec 吧!

# 启动 Apache
docker run --rm -it --name test httpd:2.4-alpine

# 启动 top
docker exec -it test top

这个方法非常单纯易懂,但代价也是庞大的。这个做法的问题点昨天有提到,主要是 docker exec 的 process 在 PID 1 process 结束的时候,没有办法正常地收到 SIGTERM 通知。

再来另一个也非常麻烦的问题是,无法使用「一个」 Docker 指令完成启动两个 process,即使是 Docker Compose 也一样。代表这需要靠脚本或其他方法来组合 Docker 指令,这将会让维运 container 的人吃尽苦头。


docker exec 不适合的话,那接下来也只剩一种方向:在 CMD 或 ENTRYPOINT 执行某个特别的脚本或程序,由它来启动所有需要的 process。

使用 shell script

写一个 shell script,让它去启动每个 process ,然後在结尾跑一个无穷回圈即可:

#!/bin/sh
 
# 启动 Apache
httpd-foreground &

# 启动 top
top -b
 
# 无穷回圈
while [[ true ]]; do
    sleep 1
done

这个方法有一样的问题--process 无法收到 SIGTERM 信号,而且比 docker exec 更加严重。docker exec 的方法,至少还会有一个 process 收到信号,而 shell script 方法则是所有 process 都收不到信号。

笔者有用类似的概念实作 Chromium + PHP for Docker

#!/bin/sh

set -e

# 若有带参数的话,则 chromedriver 会作为背景执行,然後再直接执行需要的 process。
if [ "$1" != "" ]; then
    chromedriver > /var/log/chromedriver.log 2>&1 &
    exec $@
fi

chromedriver

使用 Supervisor

Supervisor 是一个能控制多个 process 执行的管理器。以 Supervisor 改写 Dockerfile 如下:

FROM httpd:2.4-alpine

RUN apk add --no-cache supervisor

COPY ./supervisord.conf /etc/supervisor.d/supervisord.ini
CMD ["supervisord", "-c", "/etc/supervisord.conf"]

这里看到还有个设定是 supervisord.conf,内容如下:

[supervisord]
nodaemon=true

[program:apache2]
command=httpd-foreground
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0

[program:top]
command=top -b
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0

从执行结果的 log 可以看到 Supervisor 是跑在 PID 1,而 Apache 跑在 PID 8、top 跑在 PID 9 ,两个 process 都有正常启动。

2020-10-12 15:24:38,955 INFO supervisord started with pid 1
2020-10-12 15:24:39,961 INFO spawned: 'apache2' with pid 8
2020-10-12 15:24:39,965 INFO spawned: 'top' with pid 9

接着故意使用 Ctrl + C 来中止程序,可以发现 Supervisor 有把 SIGTERM 信号传送给 Apache 与 top,并把中止程序的任务完成:

2020-10-12 15:24:52,055 WARN received SIGINT indicating exit request
2020-10-12 15:24:52,057 INFO waiting for apache2, top to die
2020-10-12 15:24:52,059 INFO stopped: top (terminated by SIGTERM)
2020-10-12 15:24:52,088 INFO stopped: apache2 (exit status 0)

今日自我回顾

从今天的范例可以发现,想要在同一个 container 跑多个 process 是很困难的。因此,最好的方法就是:

一个 container 只执行一个 process!

参考资料


<<:  Day 27:Using the Elasticsearch for IaaS

>>:  关於 position 属性

[Day 08] 从 tensorflow.keras 开始的 VGG Net 生活 (第一季)

-1. 序 OK,资料分析做完了, 现在要进入演算法的部分, 我们未来几天将从经典卷积神经网路架构中...

【C# 群益 API 开发教学】官方范例下载与安装环境 #CH1

群益 API 是利用自己开发的程序,结合群益 API 在群益券商下单的一种方式,通常是做程序交易下单...

Day 10 Git

还记的这篇主题吗?因为 Flask 是用 Python 写的,所以前面讲了那麽多有关 Python ...

【学习笔记】CSS中的HTML Tag Box设定

HTML的每个标签(元素)都是一个Box,因此都由content、padding、border、ma...

Day 9 老照片效果

老照片效果 教学原文参考:老照片效果 这篇文章会介绍使用 GIMP 图层的混合模式,做出老旧照片的图...