php容器化部署实战

1,951 阅读6分钟

为什么要容器化部署

主要是为了实现弹性伸缩,降低基础资源成本。公司之前论坛应用部署在私有云上,申请了固定配置的ECS,基础资源成本较高,也无法实现弹性伸缩。

实施步骤

  1. docker基础知识了解。
  2. 选择合适的基础镜像。
  3. 基于基础镜像进行相关配置和代码拷贝,并进行验证。
  4. 编写Dockerfile,方便后续自动化部署。

docker基础知识了解

docker目前还是最主流,应用也最广泛的容器,所以还是选择docker完成本次容器化部署。docker基础知识相关可以参考:Docker教程Get Started With Docker。可以先花一点时间通读一下,大概了解后再往后继续。

选择合适的镜像

docker镜像仓库提供了很多Linux镜像,比如CentOS、Alpine等。我们在下载的时候可以选择Linux镜像自己在增加各种配置,也可以选择社区里面比较成熟的镜像,如果选择社区镜像,建议选择下载量大和star数较多的。公司的php部署环境是Nginx+php-fpm,综合下载量和star数我选择了社区镜像richarvey/nginx-php-fpm。由于公司的php是5.7,所以选择镜像版本是php5,大家可以选择最新版本。

基于基础镜像进行相关配置和代码拷贝,并进行验证

前面选择好镜像和版本后,我们需要一台Linux机器作为部署机进行镜像制作和验证,并按CentOS Docker安装安装docker客户端。建议配置镜像加速,不然下载镜像有点慢。
首先,我们执行命令先下载镜像:
docker pull richarvey/nginx-php-fpm:php5
等待下载完成,使用命令docker images查看本地镜像:

[root@VM-0-3-centos ~]# docker images
REPOSITORY                TAG       IMAGE ID       CREATED       SIZE
richarvey/nginx-php-fpm   php5      557c302f7402   4 years ago   229MB

通过查看版本php5的镜像分层发现默认启动命令为/start.sh,即容器启动会执行start.sh脚本:
image.png
更多配置详见文档传送门,由于这个镜像里已经默认集成Nginx和php-fpm,所以建议大家详细阅读下文档说明。使用开源代码前先阅读文档是个好习惯,会少走很多弯路。
使用命令docker run -itd richarvey/nginx-php-fpm:php5启动容器,docker ps查看,下面的命令都会用到CONTAINER ID:

[root@VM-0-3-centos ~]# docker ps
CONTAINER ID   IMAGE                          COMMAND       CREATED          STATUS          PORTS             NAMES
d897f6a22b3b   richarvey/nginx-php-fpm:php5   "/start.sh"   35 seconds ago   Up 34 seconds   80/tcp, 443/tcp   priceless_swirles

启动完成后,使用命令docker exec -it d897f6a22b3b bin/bash进入容器,查看start.sh发现默认webroot是“/var/www/html”(镜像的说明文档里也可以看到webroot的说明): image.png 但是由于“/var/www/html”使用VOLUME共享持久化目录,导致commit镜像无法保存,所以我们这里使用自定义webroot:
image.png
下面拷贝代码文件进入webroot,使用docker复制文件命令docker cp /home/app/helloworld d897f6a22b3b:/home/app/helloworld(自行替换代码目录)。我的代码目录只有index.php,内容如下:

<?php
echo "Vincent,hello world!\n";
?>

那是怎么开机启动Nginx和php-fpm的呢?通过查看start.sh发现最后启动了守护进程supervisord:

# Start supervisord and services
/usr/bin/supervisord -n -c /etc/supervisord.conf

然后守护进程supervisord启动了Nginx和php-fpm。可以查看详细配置文件,执行命令cat /etc/supervisord.conf
项目里有一个发邮件的任务脚本,用supervisord守护执行,所以需要修改supervisord的配置文件启动一个线程,执行命令vi /etc/supervisord.conf修改了配置文件(如没有php脚本执行请忽略这步操作)。
项目里有定时任务,需要修改vi /etc/crontabs/root增加自定义定时任务(如没有定时任务请忽略这步操作)。
下面提交我们刚刚修改的镜像,执行命令docker commit -a "Vincent" -m "php demo" d897f6a22b3b demo/php:1.0,再次查看images:

[root@VM-0-3-centos ~]# docker images
REPOSITORY                TAG       IMAGE ID       CREATED          SIZE
demo/php                  1.0       2c278fad2792   24 seconds ago   229MB
richarvey/nginx-php-fpm   php5      557c302f7402   4 years ago      229MB

这次我们使用映射外部端口启动,方便在浏览器测试访问。执行命令docker run -itd -p 80:80 -e 'WEBROOT=/home/app/helloworld' demo/php:1.0

[root@VM-0-3-centos ~]# docker run -itd -p 80:80 demo/php:1.0
fe5b68eb007c858baf25a4f13009d46bca190ad572b39b235d5ecdc66b8b9c76
[root@VM-0-3-centos ~]# docker ps
CONTAINER ID   IMAGE                          COMMAND       CREATED         STATUS          PORTS                         NAMES
fe5b68eb007c   demo/php:1.0                   "/start.sh"   8 seconds ago   Up 7 seconds    0.0.0.0:80->80/tcp, 443/tcp   jolly_hodgkin
d897f6a22b3b   richarvey/nginx-php-fpm:php5   "/start.sh"   2 hours ago     Up 35 minutes   80/tcp, 443/tcp               priceless_swirles

可以进入容器使用内置的curl 127.0.0.1验证是否可以正常访问:

[root@VM-0-3-centos app]# docker exec -it d897f6a22b3b  bin/bash
bash-4.3# curl 127.0.0.1
Vincent,hello world!

浏览器访问: image.png

以上完成的镜像可以直接用于部署,但是因为系统会有迭代,每次都这样用命令打包镜像非常麻烦,不符合最佳实践。下面我们看看Dockerfile怎么完成这些操作。

编写Dockerfile,方便后续自动化部署

在“/home/app”目录下新建Dockerfile,完整的dockerfile内容如下:

FROM    docker.io/richarvey/nginx-php-fpm:php5
MAINTAINER      Fisher "php demo"

# 拷贝当前目录下的php代码。非必须,因为镜像提供了配置git方式自动拉取代码
COPY  helloworld /var/www/html/
# 自定义的队列文件路径添加进supervisord。定时任务添加进crontab。非必须
# RUN       echo -e "[include] \nfiles = /var/www/html/commands/queue.ini" >>  /etc/supervisord.conf \
#          && cat /var/www/html/crontab/crontab-job.ini >> /etc/crontabs/root

执行docker build /home/app -t demo/php:1.1

[root@VM-0-3-centos ~]# docker build /home/app -t demo/php:1.1
Sending build context to Docker daemon  16.38kB
Step 1/3 : FROM    docker.io/richarvey/nginx-php-fpm:php5
 ---> 557c302f7402
Step 2/3 : MAINTAINER      Fisher "php demo"
 ---> Running in 8e646f558832
Removing intermediate container 8e646f558832
 ---> 7a7b268156d3
Step 3/3 : COPY  helloworld /var/www/html/
 ---> e7ac2bafe7a8
Successfully built e7ac2bafe7a8
Successfully tagged demo/php:1.1

启动镜像,执行docker run -itd -p 80:80 demo/php:1.1,然后使用浏览器访问: image.png

总结

这次实践碰到了一些坑,主要以下几点:

  1. 一开始没有查看docker layers,run的时候直接使用command /bin/bash进入容器,导致start.sh没有执行,容器没有完成初始化。
  2. 没有注意volume持久化webroot目录“/var/www/html”,容器复制代码文件和commit代码文件都有问题。 所以其实多看说明文档,里面各种默认配置都有说明,这样实施过程会事半功倍。