背景
由于项目需要,今天制作了一下基于CentOS6的PHP5.6+Nginx的Docker镜像,同时也复习了一下Dockfile,解决一两个坑,实现了在一个Docker中启动多个进程的目标。
Docker简介
什么是 Docker
Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目。它基于 Google 公司推出的 Go 语言实现。 项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在 GitHub 上进行维护。
Docker 自开源后受到广泛的关注和讨论,以至于 dotCloud 公司后来都改名为 Docker Inc。Redhat 已经在其 RHEL6.5 中集中支持 Docker;Google 也在其 PaaS 产品中广泛应用。
Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。 Docker 的基础是 Linux 容器(LXC)等技术。
在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单。
下面的图片比较了 Docker 和传统虚拟化方式的不同之处,可见容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统方式则是在硬件层面实现。
为什么要使用 Docker?
作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。
首先,Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多。 其次,Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。
容器除了运行其中应用外,基本不消耗额外的系统资源,使得应用的性能很高,同时系统的开销尽量小。传统虚拟机方式运行 10 个不同的应用就要起 10 个虚拟机,而Docker 只需要启动 10 个隔离的应用即可。
具体说来,Docker 在如下几个方面具有较大的优势。
更快速的交付和部署
对开发和运维(devop)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。
开发者可以使用一个标准的镜像来构建一套开发容器,开发完成之后,运维人员可以直接使用这个容器来部署代码。 Docker 可以快速创建容器,快速迭代应用程序,并让整个过程全程可见,使团队中的其他成员更容易理解应用程序是如何创建和工作的。 Docker 容器很轻很快!容器的启动时间是秒级的,大量地节约开发、测试、部署的时间。
更高效的虚拟化
Docker 容器的运行不需要额外的 hypervisor 支持,它是内核级的虚拟化,因此可以实现更高的性能和效率。
更轻松的迁移和扩展
Docker 容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等。 这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另外一个。
更简单的管理
使用 Docker,只需要小小的修改,就可以替代以往大量的更新工作。所有的修改都以增量的方式被分发和更新,从而实现自动化并且高效的管理。
对比传统虚拟机总结
| 特性 | 容器 | 虚拟机
| 启动 | 秒级 | 分钟级
| 硬盘使用 | 一般为 MB | 一般为 GB
| 性能 | 接近原生 | 弱于
| 系统支持量 | 单机支持上千个容器 | 一般几十个
Dockerfile
Docker创建镜像的方式有两种:
通过commit的方式:把做了一系列操作的容器关闭,然后利用docker的commit指令:dockercommit 容器ID 镜像名:tag。然后dockerpush到镜像仓库。别人pull下来的再次启动的时候,就是你当前的操作的形态。
通过Dockerfile构建的方式:把操作的步骤通过脚本的形式写下来,然后构建的时候,Docker会按照你写的步骤,一步一步构建。这是目前主流的构建方式。
Dockerfile指令
FROM
基于哪个镜像
RUN
安装软件用
MAINTAINER
镜像创建者
CMD
container启动时执行的命令,但是一个Dockerfile中只能有一条CMD命令,多条则只执行最后一条CMD.
CMD主要用于container时启动指定的服务,当docker run command的命令匹配到CMD command时,会替换CMD执行的命令。ENTRYPOINT
Container启动时执行的命令,但是一个Dockerfile中只能有一条ENTRYPOINT命令,如果多条,则只执行最后一条
CMD与ENTRYPOINT作用比较类似,都是在启动容器时执行相应命令
其区别在于:CMD会被docker run后面直接跟的命令覆盖,而ENTRYPOINT不会
但ENTRYPOINT会被 –entrypoint 后面的指令覆盖USER
使用哪个用户运行container
EXPOSE
container内部服务开启的端口。 可选,不写也可以。
ENV
用来设置环境变量
ADD
将文件拷贝到container的文件系统对应的路径
VOLUME
可以将本地文件夹或者其他container的文件夹挂载到container中。
WORKDIR
切换目录用,可以多次切换(相当于cd命令),对RUN,CMD,ENTRYPOINT生效
ONBUILD
ONBUILD 指定的命令在构建镜像时并不执行,而是在它的子镜像中执行,用得不多
使用Dockerfile的一些优化的技巧
尽量减少Dockerfile指令
Docker镜像是分层叠加进行构建的,使用Dockerfile进行镜像构建时会一条命令打包一层只读镜像,后续指令在前一指令生成的只读镜像基础上进行进一步叠加构建,指令多,层数就多,相应的镜像就会比较大,而且构建时也慢
尽量将yum安装写成一条,安装后执行yum clean all,如:
RUN yum -y install openssh-server tengine php-fpm php-xmlrpc php-bcmath php-oci8 php-curl php-gd php-mcrypt php-opcache php-inotify php-swoole php-pcntl php-zookeeper php-zip php-yaf libmemcached10 php-memcached php-memcache php-igbinary php-phalcon vim wget curl lrzsz tar telnet python-pip && yum clean all
尽量将RUN命令写成一条,并且与上述yum命令写成一条,如:
RUN yum -y install openssh-server tengine php-fpm php-xmlrpc php-bcmath php-oci8 php-curl php-gd php-mcrypt php-opcache php-inotify php-swoole php-pcntl php-zookeeper php-zip php-yaf libmemcached10 php-memcached php-memcache php-igbinary php-phalcon vim wget curl lrzsz tar telnet python-pip && yum clean all && pip install supervisor && rm -rf /etc/nginx/nginx.conf && mkdir /etc/nginx/sites.d/ && mkdir -p /var/cache/nginx/client_temp && mkdir -p /var/wd/wrs/webroot/ && mkdir -p /var/wd/wrs/release/ && mkdir -p /var/wd/log/nginx && mkdir -p /var/wd/log/php && mkdir -p /var/lib/php/session
使用ADD命令上传压缩的配置文件
ADD命令是具有解压常见tar/tgz包能力的,经常需要给镜像传配置文件时,可以先进行压缩,然后上传,这样比单个上传配置文件更能节省空间,而且build速度快。
Docker中启动多进程运行php-fpm nginx sshd
在Docker中如果没有前台进程(相对守护进程)存在,就会自动停止运行,但对于php-fpm nginx sshd这三个服务来说,通常都是运行于守护进程中。
虽然都有方法可以放在前台,但在Dockerfile中无法执行多条执行,让三个服务全运行在前台,使用CMD或者ENTRYPOINT时,只能启动放在最前面的那个服务,后面的服务都无法启动
借助Supervisor实现多进程
Linux的后台进程运行有好几种方法,例如nohup,screen等,但是,如果是一个服务程序,要可靠地在后台运行,我们就需要把它做成daemon,最好还能监控进程状态,在意外结束时能自动重启。
supervisor就是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启。
安装Supervisor
//以下两行已经在上面RUN命令中体现
# yum install python-pip
# pip install supervisor
这里有个坑,使用pip安装supervisor,没问题,但运行时会报
pkg_resources.DistributionNotFound: meld3>=0.6.5
在安装supervisor时其实已经安装了meld3,且版本也满足要求,而且使用pip单独安装meld3也不行,只能手动下载meld3-1.0.2.tar.gz,然后解压并使用python setup.py install安装
配置supervisor
第一步,使用supervisor自带的命令生成默认配置文件
echo_supervisord_conf > /etc/supervisord.conf
第二步,配置三个服务,在 /etc/supervisord.conf 的最后加如下配置:
[program:php-fpm]
command = /usr/sbin/php-fpm --nodaemonize //php-fpm前台运行
[program:sshd]
command = /usr/sbin/sshd -D //sshd前台运行
[program:nginx]
command = nginx -g "daemon off;" //nginx前台运行
默认监控时间为1s,即1s进程无反应就自动重启,并且尝试试三次重启都失败才停止
第三步,把supervisor配置为前台进程
由于上述三个服务都需要supervisor来启动,这三个进程就是supervisor的子进程,这就需要supervisor作为前台进行运行,以防止docker停止,为了使supervisor作为前台进行运行,需要修改 /etc/supervisord.conf 如下项:
nodaemon=true ; (start in foreground if true;default false)
实验测试
Dockerfile:
FROM centos:6.6
MAINTAINER lizhihua11
ENV REFRESHED 2016-08-29
RUN rm -rf /etc/yum.repos.d/* && yum clean all
ADD ./yum/all.repo /etc/yum.repos.d/
RUN yum -y install openssh-server tengine php-fpm php-xmlrpc php-bcmath php-oci8 php-curl php-gd php-mcrypt php-opcache php-inotify php-swoole php-pcntl php-zookeeper php-zip php-yaf libmemcached10 php-memcached php-memcache php-igbinary php-phalcon vim wget curl lrzsz tar telnet python-pip && yum clean all && pip install supervisor && rm -rf /etc/nginx/nginx.conf && mkdir /etc/nginx/sites.d/ && mkdir -p /var/cache/nginx/client_temp && mkdir -p /var/wd/wrs/webroot/ && mkdir -p /var/wd/wrs/release/ && mkdir -p /var/wd/log/nginx && mkdir -p /var/wd/log/php && mkdir -p /var/lib/php/session
ADD ./patch/meld3-1.0.2.tar.gz /root/
RUN cd /root/meld3-1.0.2 && python setup.py install
ADD ./config.tar.gz /etc/
#ADD ./nginx/nginx.conf.erb /etc/nginx/nginx.conf
#ADD ./php/php.ini.erb /etc/php.ini
#ADD ./php/php-fpm.conf.erb /etc/php-fpm.conf
#ADD ./supervisor/supervisor.conf /etc/supervisord.conf
RUN useradd sre && chmod -R 775 /var/lib/php && chown -R root:sre /var/lib/php
ADD ./unitmon/unitmon.ffan.com.conf /etc/nginx/sites.d/unitmon.ffan.com.conf
ADD ./unitmon/html.tgz /var/wd/wrs/webroot/unitmon/
RUN chown -R sre:sre /var/wd
ENTRYPOINT /usr/bin/supervisord
EXPOSE 10080
构建镜像:
$ sudo docker build -t test:6.6v4 .
........省略N行
Removing intermediate container b202374c398a
Step 9 : ADD ./config.tar.gz /etc/
---> a33c658c1ddd
Removing intermediate container 3dface0374c7
Step 10 : RUN useradd sre && chmod -R 775 /var/lib/php && chown -R root:sre /var/lib/php
---> Running in 98c35cfcf70d
---> 75ed442606eb
Removing intermediate container 98c35cfcf70d
Step 11 : ADD ./unitmon/unitmon.ffan.com.conf /etc/nginx/sites.d/unitmon.ffan.com.conf
---> a5d21a655b1a
Removing intermediate container 65870c1ef011
Step 12 : ADD ./unitmon/html /var/wd/wrs/release/unitmon/20160826-163630
---> 4ef1057520d7
Removing intermediate container c0042002dfd3
Step 13 : RUN ln -s /var/wd/wrs/release/unitmon/20160826-163630/ /var/wd/wrs/webroot/unitmon && chown -R sre:sre /var/wd
---> Running in 3ae56e760c93
---> bc30d55adf17
Removing intermediate container 3ae56e760c93
Step 14 : ENTRYPOINT /usr/bin/supervisord
---> Running in e52efe994625
---> beeb1ca64453
Removing intermediate container e52efe994625
Step 15 : EXPOSE 10080
---> Running in d99310e8d1b0
---> 68823fe07d65
Removing intermediate container d99310e8d1b0
Successfully built 68823fe07d65
运行容器测试:
$ sudo docker run -d --name test_v4 -p 10080:10080 test:6.6v4 /bin/bash
fbb118781b19f15f1684af9730ab1d197cd02ba630f5a1553fb5f10fabd6b26d
$ sudo docker logs fbb118781b19f15f1684af9730ab1d197cd02ba630f5a1553fb5f10fabd6b26d
/usr/lib/python2.6/site-packages/supervisor/options.py:298: UserWarning: Supervisord is running as root and it is searching for its configuration file in default locations (including its current working directory); you probably want to specify a "-c" argument specifying an absolute path to a configuration file for improved security.
'Supervisord is running as root and it is searching '
2016-08-29 10:01:29,822 CRIT Supervisor running as root (no user in config file)
2016-08-29 10:01:29,843 INFO RPC interface 'supervisor' initialized
2016-08-29 10:01:29,843 CRIT Server 'unix_http_server' running without any HTTP authentication checking
2016-08-29 10:01:29,843 INFO supervisord started with pid 1
2016-08-29 10:01:30,845 INFO spawned: 'nginx' with pid 9
2016-08-29 10:01:30,847 INFO spawned: 'sshd' with pid 10
2016-08-29 10:01:30,849 INFO spawned: 'php-fpm' with pid 11
2016-08-29 10:01:31,961 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2016-08-29 10:01:31,961 INFO success: sshd entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2016-08-29 10:01:31,961 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
总结
本文主要介绍了基于CentOS6制作PHP5.6+Nginx的Docker镜像,并解决了多进程同时存在的问题。
并用实验测试并验证相应的解决方法。
初涉Docker,如有问题还请多多指教。