我們都知道Docker容器的哲學是一個Docker容器只運行一個進程,但是有時候我們就是需要在一個Docker容器中運行多個進程
那么基本思路是在Dockerfile 的CMD 或者 ENTRYPOINT 運行一個”東西”,然后再讓這個”東西”運行多個其他進程
簡單說來是用Bash Shell腳本或者三方進程守護 (Monit,Skaware S6,Supervisor),其他沒講到的三方進程守護工具同理
Bash Shell腳本
入口文件運行一個Bash Shell 腳本, 然后在這個腳本內去拉起多個進程
注意最后要增加一個死循環不要讓這個腳本退出,否則拉起的進程也退出了
run.sh
#!/bin/bash # start 1 start1 > /var/log/start1.log 2>&1 & # start 2 start2 > /var/log/start2.log 2>&1 & # just keep this script running while [[ true ]]; do sleep 1 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=1 \ && 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.0 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 1 # 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