如何在一个Docker中同时运行多个程序进程?
我们都知道Docker容器的哲学是一个Docker容器只运行一个进程,但是有时候我们就是需要在一个Docker容器中运行多个进程
那么基本思路是在Dockerfile 的CMD 或者 ENTRYPOINT 运行一个”东西”,然后再让这个”东西”运行多个其他进程
简单说来是用Bash Shell脚本或者三方进程守护 (Monit,Skaware S6,Supervisor),其他没讲到的三方进程守护工具同理
Bash Shell脚本
入口文件运行一个Bash Shell 脚本, 然后在这个脚本内去拉起多个进程
注意最后要增加一个死循环不要让这个脚本退出,否则拉起的进程也退出了
run.sh
#!/bin/bash # start
start1 > /var/log/start1.log >& &
# start
start2 > /var/log/start2.log >& & # just keep this script running
while [[ true ]]; do
sleep
done
在Dockerfile的入口中运行run.sh
ENTRYPOINT ["run.sh"]
用Bash Shell 的方式,任意发行版的linux都支持,缺点是不能拉起crash的进程,也就是只能拉起运行不能”守护”
如果不关心进程crash问题那么可以用这种方式
三方容器进程初始化之-dumb-init
dumb-init官方
A minimal init system for Linux containers
一个最小化的Linux容器初始化系统
dumb-init是一个简单的进程监控器和init系统,设计为在最小容器环境(如Docker)中作为PID 1运行。它被部署为一个用C编写的小型静态链接二进制文件。
Dockerfile 参考
# Runs "/usr/bin/dumb-init -- /my/script --with --args"
ENTRYPOINT ["/usr/bin/dumb-init", "--"] # or if you use --rewrite or other cli flags
# ENTRYPOINT ["dumb-init", "--rewrite", "2:3", "--"] CMD ["/my/script", "--with", "--args"]
ServiceMesh的数据平面Envoy Proxy的容器镜像就是使用的dumb-init
三方容器进程初始化之-tini
tini官方
A tiny but valid init for containers
容器的一个小而有效的init
三方进程守护之-Monit
Monit和Supervisor还是有很大区别的,Supervisor管理的都是前台执行的进程,Monit既可以管理前台进程也可以管理后台进程,简单的说,在CentOS中使用service xxx start 启动的程序,使用Monit可以直接管理,这就解决了很多没有前台方式启动的程序不能用Supervisor来管理的问题。
Dockerfile 参考
ENTRYPOINT ["/usr/bin/monit","-I"]
三方进程守护之-Supervisor
大名鼎鼎的 Supervisor
如果有多种版本的linux要用那么可以用Supervisor做统一进程守护管理,网上资料一大堆
注意要以前台程序运行,配置文件中要有,如果是后台的方式docker会退出
[supervisord]
nodaemon=true
Dockerfile 参考
ENTRYPOINT ["supervisord", "-c", "/etc/supervisor/conf.d/youconf.conf"]
三方进程守护之-Skaware S6
Supervisor是常见的进程守护程序,不过程序文件太大,想要容器镜像尽量小,在特别是用Alpine作为基础镜像的时候推荐使用Skaware S6
参考这个微服务基础镜像 https://github.com/nicholasjackson/microservice-basebox 他就是用 Skaware 作为进程守护程序运行多个进程的
如果基础容器镜像是本身就是Alpine,那就再合适不过了
Dockerfile 参考
# skaware s6 daemon runner
RUN mkdir /s6 \
&& wget --no-check-certificate https://github.com/just-containers/skaware/releases/download/v1.21.2/s6-2.6.1.1-linux-amd64-bin.tar.gz \
&& tar -xvzf s6-2.6.1.1-linux-amd64-bin.tar.gz --directory /s6 --strip-components= \
&& mv /s6/bin/* /usr/bin \
&& rm -rf s6-2.6.1.1-linux-amd64-bin.tar.gz \
&& rm -rf /s6 \
&& cd /usr/bin/ \
&& chmod -R 755 s6-accessrules-cdb-from-fs s6-accessrules-fs-from-cdb \
s6-applyuidgid s6-cleanfifodir s6-connlimit s6-envdir s6-envuidgid \
s6-fdholder-daemon s6-fdholder-delete s6-fdholder-deletec s6-fdholder-getdump \
s6-fdholder-getdumpc s6-fdholder-list s6-fdholder-listc s6-fdholder-retrieve \
s6-fdholder-retrievec s6-fdholder-setdump s6-fdholder-setdumpc s6-fdholder-store \
s6-fdholder-storec s6-fdholder-transferdump s6-fdholder-transferdumpc s6-fdholderd \
s6-fghack s6-ftrig-listen s6-ftrig-listen1 s6-ftrig-notify s6-ftrig-wait s6-ftrigrd \
s6-ioconnect s6-ipcclient s6-ipcserver s6-ipcserver-access s6-ipcserver-socketbinder \
s6-ipcserverd s6-log s6-mkfifodir s6-notifyoncheck s6-setlock s6-setsid s6-setuidgid \
s6-softlimit s6-sudo s6-sudoc s6-sudod s6-supervise s6-svc s6-svlisten s6-svlisten1 \
s6-svok s6-svscan s6-svscanctl s6-svstat s6-svwait s6-tai64n s6-tai64nlocal s6lockd ucspilogd \
&& cd - # 预处理s6配置文件
RUN mkdir -p /etc/s6/.s6-svscan \
&& ln -s /bin/true /etc/s6/.s6-svscan/finish \
&& mkdir -p /etc/s6/cron \
&& mkdir -p /etc/s6/app \
&& ln -s /bin/true /etc/s6/cron/finish \
&& ln -s /bin/true /etc/s6/app/finish # corotab 文件内容
ADD cronfile /var/spool/cron/root
# 运行Bash 脚本
ADD cron.run /etc/s6/cron/run
ADD app.run /etc/s6/app/run ENTRYPOINT ["/usr/bin/s6-svscan","/etc/s6"]
cron.run example
| 
 1 
2 
3 
 | 
 #!/usr/bin/env bash 
exec crond -n 
 | 
app.run example
| 
 1 
2 
3 
 | 
 #!/usr/bin/env bash 
exec app 
 | 
三方进程守护之-s6-overlay
s6-overlay 是基于 Skaware S6适用于容器的进程守护工具
s6-overlay 官网 https://github.com/just-containers/s6-overlay
Dockerfile 参考
# Install s6-overlay 进程守护管理.
ENV S6_VERSION v1.21.4.
RUN curl -L "https://github.com/just-containers/s6-overlay/releases/download/$S6_VERSION/s6-overlay-amd64.tar.gz" > /tmp/s6-overlay-amd64.tar.gz
RUN tar xzf /tmp/s6-overlay-amd64.tar.gz -C / --exclude="./bin" && \
tar xzf /tmp/s6-overlay-amd64.tar.gz -C /usr ./bin \
&& rm /tmp/s6-overlay-amd64.tar.gz
ENV S6_BEHAVIOUR_IF_STAGE2_FAILS # Set up a standard volume for logs.
VOLUME ["/var/log/services"] # 设置入口为 s6-based init.
ENTRYPOINT ["/init"]
三方进程守护之-runit
runit官网http://smarden.org/runit/
具体的使用方法见官网
在Docker生态圈, phusion/baseimage-docker, gitlab 在使用runit作为进程管理工具
下面以要运行cron 和 ssh 为例
/etc/service/ 为配置文件目录
/etc/service/sshd 为要运行的程序目录
/etc/service/sshd/run 为需要运行的程序入口脚本文件
cat run
| 
 1 
2 
3 
4 
 | 
 #!/bin/sh 
set -e 
exec /usr/sbin/sshd -D 
 | 
/etc/service/cron 为要运行的程序目录
/etc/service/cron/run 为需要运行的程序入口脚本文件
cat run
| 
 1 
2 
3 
 | 
 #!/bin/sh 
exec /usr/sbin/cron -f 
 | 
Dockerfile 参考
| 
 1 
2 
 | 
 ENTRYPOINT ["/usr/bin/runsvdir","-P","/etc/service"] 
 | 
三方进程守护之-Systemd
在 docker 中使用 Systemd 需要在 docker run 的时候开启特权模式 –privileged ,所以不推荐
这个直接放弃了
Dockerfile 参考
| 
 1 
2 
 | 
 ENTRYPOINT ["/usr/sbin/init"] 
 | 
参考资料
Alpine里的go应用,你猜他能有多小? http://blog.csdn.net/sisiy2015/article/details/50350261
如何运行多进程Docker容器? http://dockone.io/article/951
在Docker Container中启动定时任务 http://dockone.io/article/1070
Docker容器内多进程管理(一)-Supervisor http://www.linuxprobe.com/docker-process-management1.html
Docker容器内多进程管理(二)-Monit http://www.linuxprobe.com/docker-process-management2.html
关于S6和Runit的论坛讨论 S6 or Runit, not systemd https://www.linuxquestions.org/questions/slackware-14/s6-or-runit-not-systemd-4175465428/
[译] runit 快速入门 https://segmentfault.com/a/1190000006644578
如何在一个Docker中同时运行多个程序进程?的更多相关文章
- Docker入门系列之一:在一个Docker容器里运行指定的web应用
		
实现题目描述的这个需求有很多种办法,作为入门,让我们从最简单的办法开始. 首先使用命令docker ps确保当前没有正在运行的Docker实例. 运行命令docker run -it nginx: 然 ...
 - 【docker】查看docker容器或镜像的详细信息命令,查看docker中正在运行的容器的挂载位置
		
命令: docker inspect f257d69e0035 格式: docker inspect 容积或镜像ID 首先,docker ps获取简要信息 然后输入命令docker inspect ...
 - 在 Docker 中已运行的 container 如何修改 run 时的 env
		
https://www.cnblogs.com/xiaouisme/p/9837221.html 首先不推荐这样做,如需修改配置,应删掉重新部署. 其次,可以进行如下操作(未测试,不知道仅重启 con ...
 - 在Windows命令行中编译运行C/C++程序
		
此处运行环境是在Windos下,运行cmd命令进入DOS界面 现在有一段简单C++代码(文件名为 demo.cpp),用于计算a*b的值 #include<iostream> using ...
 - VS2008中编译运行MFC应用程序时,出现无法启动程序,因为计算机中丢失mfc90ud.dll的解决方案
		
 解决方法:"工具"->"选项"->"项目和解决方案"->"VC++目录",在可执行文件栏中加上如 ...
 - 修改docker中mysql登入密码(包括容器内和本地远程登入的密码)
		
查看docker中正在运行的容器 docker ps 进入MySQL 容器中 sudo docker exec -it cd800a1cd503 /bin/bash 在容器中: /etc/mysql/ ...
 - iOS堆栈-内存-代码在据算机中的运行
		
其实作程序不管是那行,学什么语言最终的目的是和就算机打交道的,我们写的程序计算机是怎么处理的呢??? 计算机运行我们的程序无非就是吧磁盘-内存-cpu三者结合起来 我们写一个程序代码肯定是在此盘中存着 ...
 - call_usermodehelper内核中运行用户应用程序
		
init是用户空间第一个程序,在调用init前程序都运行在内核态,之后运行init时程序运行到用户态. 操作系统上,一些内核线程在内核态运行,它们永远不会进入用户态.它们也根本没有用户态的内存空间.它 ...
 - (转)在Docker中运行Java:为了防止失败,你需要知道这些
		
转自:https://mp.weixin.qq.com/s?__biz=MzA5OTAyNzQ2OA==&mid=2649693848&idx=1&sn=4e9ef7e2a9d ...
 
随机推荐
- 初识RSA
			
基础知识:http://www.guideep.com/read?guide=5676830073815040# python实现:https://blog.csdn.net/bian_h_f6127 ...
 - git 执行 git reset HEAD 报 Unstaged changes after reset
			
Unstaged changes after reset 解决的办法如下2中办法: 1. git add . git reset --hard 2. git stash git stash dro ...
 - Vue打包发布到Tomcat后,刷新报错404解决方法
			
在应用下面加 WEB-INF 建 web.xml 内容如下 <?xml version="1.0" encoding="ISO-8859-1"?> ...
 - matlab学习笔记12_4rmfield,arrayfun,structfun,struct2cell,cell2struct
			
一起来学matlab-matlab学习笔记12 12_4 结构体 rmfield,arrayfun,structfun,struct2cell,cell2struct 觉得有用的话,欢迎一起讨论相互学 ...
 - ireport5.6.0分组显示
			
一,ireport中分组 二,java调用实现分组 一,ireport中分组: 1,新建模板文件,纸张随意,名称随意,路径随意 2,连接要分组的数据源 3,添加测试表和数据 CREATE TABLE ...
 - spark org.apache.spark.ml.linalg.DenseVector cannot be cast to org.apache.spark.ml.linalg.SparseVector
			
在使用 import org.apache.spark.ml.feature.VectorAssembler 转换特征后,想要放入 import org.apache.spark.mllib.clas ...
 - sqlserver 创建分区表
			
我们知道很多事情都存在一个分治的思想,同样的道理我们也可以用到数据表上,当一个表很大很大的时候,我们就会想到将表拆 分成很多小表,查询的时候就到各个小表去查,最后进行汇总返回给调用方来加速我们的查询速 ...
 - Linux下配置Golang开发环境
			
前几天无意间看到了微信推送的golang开发的消息,看到golang那么牛逼,突然心血来潮想学习一下go.工欲善其事必先利其器,想做go开发,必须先配置好go的开发环境(就像开发Java先安装配置jd ...
 - initramfs文件系统制作
			
源码下载:https://busybox.net/downloads/ 源码版本:busybox-1.30.0.tar.bz2 [ 源码编译步骤 ] make menuconfig ARCH= COM ...
 - 页码0~N ,其中0,1....9都出现了几次
			
/* 这道题目可以暴力解答:对1~n的每个数进行从低位到高位分析 一旦这个数字num出现,a[num]++即可 第二种方法: 由0,1,...9组成的所有n位数,从n个0到n个9共10^n个数,0,1 ...