如何運(yùn)行多進(jìn)程Docker容器?
一般來說,Docker容器比較適合運(yùn)行單個(gè)進(jìn)程。例如,項(xiàng)目"使用多個(gè)Docker容器運(yùn)行Kubernetes",Kubernetes的各個(gè)組件分別運(yùn)行在各個(gè)容器之中,每個(gè)容器只運(yùn)行單個(gè)進(jìn)程。
然而,很多時(shí)候我們需要在Docker容器中運(yùn)行多個(gè)進(jìn)程。例如,項(xiàng)目"使用單個(gè)Docker容器運(yùn)行Kubernetes",kubernetes的各個(gè)組件均運(yùn)行在同一個(gè)容器中,該容器中運(yùn)行了多個(gè)進(jìn)程。那么,如何運(yùn)行多進(jìn)程Docker容器?
一種方法是使用Shell腳本,另一種方法是使用進(jìn)程管理工具Supervisor。kiwenlau/kubernetes-shell和kiwenlau/kubernetes-supervisor分別采用了這兩種方法,用于啟動(dòng)多個(gè)進(jìn)程來運(yùn)行Kubernetes的各個(gè)組件,從而實(shí)現(xiàn)"使用單個(gè)Docker容器運(yùn)行Kubernetes"。下面我將分別介紹兩種不同方法。
使用Shell腳本運(yùn)行多進(jìn)程Docker容器
這個(gè)方法大家應(yīng)該會(huì)比較熟悉,使用Shell腳本依次啟動(dòng)Kubernetes的各個(gè)組件即可。以下為start-kubernetes.sh
- !/bin/bashstart docker daemondocker daemon > /var/log/docker.log 2>&1 &
- start etcdetcd --data-dir=/var/etcd/data > /var/log/etcd.log 2>&1 &
- wait for ectd to setupsleep 5
- start apiserverkube-apiserver --service-cluster-ip-range=10.0.0.1/24 --insecure-bind-address=0.0.0.0 --etcd_servers=http://127.0.0.1:4001 > /var/log/kube-apiserver.log 2>&1 &
- wait for apiserver to setupsleep 5
- start controller manager, sheduler, kubelet and proxykube-controller-manager --master=http://0.0.0.0:8080 > /var/log/kube-controller-manager.log 2>&1 &
- kube-scheduler --master=http://0.0.0.0:8080 > /var/log/kube-scheduler.log 2>&1 &
- kubelet --api_servers=http://0.0.0.0:8080 --address=0.0.0.0 --cluster_dns=10.0.0.10 --cluster_domain="kubernetes.local" --pod-infra-container-image="kiwenlau/pause:0.8.0" > /var/log/kubelet.log 2>&1 &
- kube-proxy --master=http://0.0.0.0:8080 > /var/log/kube-proxy.log 2>&1 &
- just keep this script runningwhile [[ true ]]; do
- sleep 1
- done
然后在Dockerfile中,將start-kubernetes.sh指定為Docker容器默認(rèn)執(zhí)行的命令即可:
- CMD ["start-kubernetes.sh"]
需要注意的一點(diǎn)在于,start-kubernetes.sh腳本將作為Docker容器的1號(hào)進(jìn)程運(yùn)行,必須始終保持運(yùn)行。因?yàn)镈ocker容器僅在1號(hào)進(jìn)程運(yùn)行時(shí)保持運(yùn)行,換言之,Docker容器將在1號(hào)進(jìn)程退出后Exited。由于Kubernetes的各個(gè)組件都以后臺(tái)進(jìn)程方式執(zhí)行,我在腳本末尾添加了死循環(huán),以保持start-kubernetes.sh腳本始終處于運(yùn)行狀態(tài)。
- just keep this script runningwhile [[ true ]]; do
- sleep 1
- done
使用supervisor運(yùn)行多進(jìn)程Docker容器
Supervisor是進(jìn)程管理工具。這時(shí),需要編寫supervisor的配置文件kubernetes.conf:
- [supervisord]
- nodaemon=true
- [program:etcd]
- command=etcd --data-dir=/var/etcd/data
- autorestart=true
- stdout_logfile=/var/log/etcd.stdout.log
- stderr_logfile=/var/log/etcd.stderr.log
- [program:kube-apiserver]
- command=kube-apiserver --service-cluster-ip-range=10.0.0.1/24 --insecure-bind-address=0.0.0.0 --etcd_servers=http://127.0.0.1:4001
- autorestart=true
- stdout_logfile=/var/log/kube-apiserver.stdout.log
- stderr_logfile=/var/log/kube-apiserver.stderr.log
- [program:kube-controller-manager]
- command=kube-controller-manager --master=http://0.0.0.0:8080
- autorestart=true
- stdout_logfile=/var/log/controller-manager.stdout.log
- stderr_logfile=/var/log/controller-manager.stderr.log
- [program:kube-scheduler]
- command=kube-scheduler --master=http://0.0.0.0:8080
- autorestart=true
- stdout_logfile=/var/log/kube-scheduler.stdout.log
- stderr_logfile=/var/log/kube-scheduler.stderr.log
- [program:kubelet]
- command=kubelet --api_servers=http://0.0.0.0:8080 --address=0.0.0.0 --cluster_dns=10.0.0.10 --cluster_domain="kubernetes.local" --pod-infra-container-image="kiwenlau/pause:0.8.0"
- autorestart=true
- stdout_logfile=/var/log/kubelet.stdout.log
- stderr_logfile=/var/log/kubelet.stderr.log
- [program:kube-proxy]
- command=kube-proxy --master=http://0.0.0.0:8080
- autorestart=true
- stdout_logfile=/var/log/kube-proxy.stdout.log
- stderr_logfile=/var/log/kube-proxy.stderr.log
- [program:docker]
- command=docker daemon
- autorestart=true
- stdout_logfile=/var/log/docker.stdout.log
- stderr_logfile=/var/log/docker.stderr.log
可知,將Kubernetes的各個(gè)組件的啟動(dòng)命令設(shè)為command即可。autorestart參數(shù)設(shè)為true,意味著supervisor將負(fù)責(zé)重啟意外退出的組件。stdout_logfile和stderr_logfile參數(shù)則可以用于設(shè)置命令的標(biāo)準(zhǔn)輸出文件和標(biāo)準(zhǔn)錯(cuò)誤輸出文件。
然后在Dockerfile中,將supervisord指定為Docker容器默認(rèn)執(zhí)行的命令即可:
- CMD ["supervisord", "-c", "/etc/supervisor/conf.d/kubernetes.conf"]
此時(shí), supervisord是Docker容器中的1號(hào)進(jìn)程,也需要始終保持運(yùn)行狀態(tài)。nodaemon設(shè)為true時(shí),表示supervisor保持前臺(tái)運(yùn)行而非在后臺(tái)運(yùn)行。若supervisor在后臺(tái)運(yùn)行,則Docker容器也會(huì)在執(zhí)行supervisord命令后立即Exited.
- [supervisord]
- nodaemon=true
總結(jié)
使用Shell腳本運(yùn)行多進(jìn)程Docker容器,優(yōu)勢(shì)是大家比較熟悉。由于需要保持Docker容器的1號(hào)進(jìn)程始終運(yùn)行,這一點(diǎn)比較容易出錯(cuò)。若要實(shí)現(xiàn)進(jìn)程意外退出后自動(dòng)重啟的話,使用shell腳本比較麻煩。
使用supervisor運(yùn)行多進(jìn)程Docker容器,非常方便。另外,保持1號(hào)進(jìn)程保持運(yùn)行,以及進(jìn)程意外退出后自動(dòng)重啟,實(shí)現(xiàn)起來都很簡(jiǎn)單。
使用多個(gè)Docker容器運(yùn)行Kubernetes
GitHub地址
- kiwenlau/single-kubernetes-docker
下圖顯示了我在Ubuntu主機(jī)上運(yùn)行單機(jī)版Kubernetes的架構(gòu)??芍乙还策\(yùn)行了7個(gè)容器,分別運(yùn)行Kubernetes的各個(gè)組件。

使用單個(gè)Docker容器運(yùn)行Kubernetes
GitHub地址:
- kiwenlau/kubernetes-shell
- kiwenlau/kubernetes-supervisor
該項(xiàng)目中,我將kubernetes的所有組件:etcd, controller manager, apiserver, scheduler, kubelet, proxy以及docker daemon均運(yùn)行在同一個(gè)Docker容器之中。
容器啟動(dòng)時(shí),各個(gè)組件由shell腳本或者supervisor啟動(dòng)。

參考
1. Using Supervisor with Docker
2. How To Install and Manage Supervisor on Ubuntu and Debian VPS
3. 基于Docker搭建單機(jī)版Kuberntes
4. kiwenlau/single-kubernetes-docker