erp项目自动发布流程容器化设计

前言

  由于公司ERP后端API项目基于Laravel框架编写,开发语言为PHP,此次记录是把现有的自动化发布流程容器化,原先自动发布流程基于 Gtilab+Jenkins+Nginx  直接发布至开发与测试环境。运行了一个月,发现还是存在一些缺点的,比如代码在开发环境运行得好好的,测试人员使用Jenkins把代码部署到测试环境时就出现了错误。测试完后,发布至生产环境又出现一些如权限、配置文件、变量等一系列问题。每换一个环境,总是有这样那样的问题,所以为了彻底解决这一问题,解放传统运维人员的双手,决定容器化整个发布流程。

一、发布流程设计

  • 1.获取代码

  • 2.编译(可选)

  • 3.配置文件

  • 4.构建镜像

  • 5.上传镜像

  • 6.启动容器

画张图,让大家容易理解些。

666.png

  首先是,开发人员完成开发任务后,push提交代码------代码同步到Gitlab仓库后,触发Webhook通知Jenkins----Jenkins负责构建Docker镜像并推送到远程Docker仓库,推送完成后,通过SSH连接到节点服务器(Node)----在节点服务器拉取远程docker仓库的镜像,然后指定启动哪个配置文件来启动容器。整个发布流程大概就这样子,实战过程如下。

图中自己搭建的为Harbor私有仓库,不想搭建,大家可以使用阿里云提供docker仓库,功能也很强大,目前免费使用

二、环境规划

首先整个环境确保已经部署完成Gitlab、Jenkins、Docker Registry、Docker、Nginx。部署方法不在叙述,请看百度或翻看我Blog。

角色                    IP                            域名
Gitlab                 192.168.1.22            git.leiyan.com
Jenkins/Docker         192.168.1.23            jenkins.leiyan.com
Docker Registry        192.168.1.27            docker.leiiyan.com
Docker/Nginx           192.168.1.31            dev.leiyan.com

.

[root@jenkins-server]# cat /etc/redhat-release && uname -a
CentOS Linux release 7.5.1804 (Core) 
Linux jenkins-server 3.10.0-862.14.4.el7.x86_64 #1 SMP Wed Sep 26 15:12:11 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

[root@jenkins-server]# docker -v
Docker version 18.09.0, build 4d60db4

三、Docker客户端配置

Docker仓库我使用的是Vmware开源的Harbor,官网,使用域名:docker.leiyan.com 部署与当前内网,因为docker 默认以https方式登陆,不支持http方式登录,所以所有Docker客户端要以http方式登陆,则需修改下配置文件。(阿里云仓库默认是https模式,不需要做此步骤)

方法一:

vim /usr/lib/systemd/system/docker.service

ExecStart=/usr/bin/dockerd \
          --insecure-registry docker.leiyan.com \   #增加镜像地址

方法二:
创建/etc/docker/daemon.json文件,在文件中指定仓库地址

cat > /etc/docker/daemon.json << EOF
{ "insecure-registries":["docker.leiyan.com"] }
EOF

完成后从载配置,重启docker

systemctl daemon-reload 
systemctl restart docker

登录仓库

docker login docker.leiyan.com
Username: admin
Password:     
Login Succeeded

四、构建基础镜像

构建一个PHP代码须要环境,我直接在gitbug上找了一个: 项目地址
这个PHP+NGINX的环境镜像还不错,适合大多数PHP环境,它使用supervisord启动守护NGINXPHP进程,具体使用指南可以看: https://www.qinzc.me/post-204.html

Dockerfile 内容

FROM centos:7
MAINTAINER Skiychan <dev@skiy.net>

ENV NGINX_VERSION 1.15.7
ENV PHP_VERSION 7.2.13

RUN set -x && \
    yum install -y gcc \
    gcc-c++ \
    autoconf \
    automake \
    libtool \
    make \
    cmake && \
#Install PHP library
## libmcrypt-devel DIY
   rpm -ivh http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm && \
    yum install -y zlib \
    zlib-devel \
    openssl \
    openssl-devel \
    pcre-devel \
    libxml2 \
    libxml2-devel \
    libcurl \
    libcurl-devel \
    libpng-devel \
    libjpeg-devel \
    freetype-devel \
    libmcrypt-devel \
    openssh-server \
    python-setuptools && \
#Add user
    mkdir -p /data/{www,phpextini,phpextfile} && \
    useradd -r -s /sbin/nologin -d /data/www -m -k no www && \
#Download nginx & php
    mkdir -p /home/nginx-php && cd $_ && \
    curl -Lk http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz | gunzip | tar x -C /home/nginx-php && \
    curl -Lk http://php.net/distributions/php-$PHP_VERSION.tar.gz | gunzip | tar x -C /home/nginx-php && \
#Make install nginx
    cd /home/nginx-php/nginx-$NGINX_VERSION && \
    ./configure --prefix=/usr/local/nginx \
    --user=www --group=www \
    --error-log-path=/var/log/nginx_error.log \
    --http-log-path=/var/log/nginx_access.log \
    --pid-path=/var/run/nginx.pid \
    --with-pcre \
    --with-http_ssl_module \
    --without-mail_pop3_module \
    --without-mail_imap_module \
    --with-http_gzip_static_module && \
    make && make install && \
#Make install php
    cd /home/nginx-php/php-$PHP_VERSION && \      
    ./configure --prefix=/usr/local/php \
    --with-config-file-path=/usr/local/php/etc \
    --with-config-file-scan-dir=/data/phpextini \
    --with-fpm-user=www \
    --with-fpm-group=www \
    --with-mysqli \
    --with-pdo-mysql \
    --with-openssl \
    --with-gd \
    --with-iconv \
    --with-zlib \
    --with-gettext \
    --with-curl \
    --with-png-dir \
    --with-jpeg-dir \
    --with-freetype-dir \
    --with-xmlrpc \
    --with-mhash \
    --enable-fpm \
    --enable-xml \
    --enable-shmop \
    --enable-sysvsem \
    --enable-inline-optimization \
    --enable-mbregex \
    --enable-mbstring \
    --enable-ftp \
    --enable-mysqlnd \
    --enable-pcntl \
    --enable-sockets \
    --enable-zip \
    --enable-soap \
    --enable-session \
    --enable-opcache \
    --enable-bcmath \
    --enable-exif \
    --enable-fileinfo \
    --disable-rpath \
    --enable-ipv6 \
    --disable-debug \
    --without-pear && \
    make && make install && \
#Install php-fpm
    cd /home/nginx-php/php-$PHP_VERSION && \
    cp php.ini-production /usr/local/php/etc/php.ini && \
    cp /usr/local/php/etc/php-fpm.conf.default /usr/local/php/etc/php-fpm.conf && \
    cp /usr/local/php/etc/php-fpm.d/www.conf.default /usr/local/php/etc/php-fpm.d/www.conf && \
#Install supervisor
    easy_install supervisor && \
    mkdir -p /var/{log/supervisor,run/{sshd,supervisord}} && \
#Clean OS
    yum remove -y gcc \
    gcc-c++ \
    autoconf \
    automake \
    libtool \
    make \
    cmake && \
    yum clean all && \
    rm -rf /tmp/* /var/cache/{yum,ldconfig} /etc/my.cnf{,.d} && \
    mkdir -p --mode=0755 /var/cache/{yum,ldconfig} && \
    find /var/log -type f -delete && \
    rm -rf /home/nginx-php && \
#Change Mod from webdir
    chown -R www:www /data/www

#Add supervisord conf
ADD supervisord.conf /etc/

#Create web folder
# WEB Folder: /data/www
# SSL Folder: /usr/local/nginx/conf/ssl
# Vhost Folder: /usr/local/nginx/conf/vhost
# php extfile ini Folder: /usr/local/php/etc/conf.d
# php extfile Folder: /data/phpextfile
VOLUME ["/data/www", "/usr/local/nginx/conf/ssl", "/usr/local/nginx/conf/vhost", "/data/phpextini", "/data/phpextfile"]

ADD index.php /data/www/

#Add ext setting to image
#ADD extini/ /data/phpextini/
#ADD extfile/ /data/phpextfile/

#Update nginx config
ADD nginx.conf /usr/local/nginx/conf/

#Start
ADD start.sh /
RUN chmod +x /start.sh

#Set port
EXPOSE 80 443

#Start it
ENTRYPOINT ["/start.sh"]

#Start web server
#CMD ["/bin/bash", "/start.sh"]

开始构建

docker build -t docker.leiyan.com/erp-api/nginx .

注意:后边的点. 是Dockerfile 所在路径,Dockerfile所在路径为文件ADD进容器的根路径。

镜像构建完成后上传至Docker 仓库。

docker push docker.leiyan.com/erp-api/nginx

五、Jenkins 环境准备

1.Jenkins上,/code/data/文件夹目录结构

2.拉取第四步构建好好的基础镜像

[root@jenkins-server ~]# docker pull docker.leiyan.com/erp-api/nginx:latest
latest: Pulling from erp-api/nginx
a02a4930cb5d: Pull complete 
af7170ef0b85: Extracting [==================================================>]  96.14MB/96.14MB
72dff1e1a3e5: Download complete 
473619a99d5b: Download complete 
31a15d353075: Download complete 
7ded69bed07f: Download complete 
2bdee6428e36: Download complete

3.jenkins执行的脚本:功能很简单,就是把,php代码,配置文件,容器运行脚本,做成镜像,并上传至Docker仓库

#!/bin/bash                                                                                                                                                                                               
#Author:覃子城
#Blog:http://www.qinzc.me
#Time:2019-01-09 09:30:55
#Name:devops.sh
#Version:V1.0
#Description: jenkins CI shell

CODEDIR=/data/code

if [ -d /data/code ];then
    echo "-----目录存在------"
else
    mkdir /data/code -p
    echo "创建目录成功"
fi

#拉取gitlab上的代码至当前Jenkins(请根据自身业务去做)
echo "############git pull  new code....#############"

cd $CODEDIR
rm -fr ${CODEDIR}/erp-backend
git clone  git@git.leiyan.com:erp/erp-backend.git

#pull新代码下来后进入代码目录,,并编译更新代码(请根据自身业务去做)

cd $CODEDIR/erp-backend/src
/usr/local/bin/composer update

#生成Dockerfile文件

echo "----------编写Dockerfile-------------"

cat > $CODEDIR/Dockerfile <<EOF                                                                                                                                                                       
#基础镜像来源 
FROM docker.leiyan.com/erp-api/nginx

#镜像信息
MAINTAINER Qinzicheng  "542129333@qq.com"

#1.添加nginx.conf配置文件
#2.添加start.sh启动的脚本
#3.复制所有环境配置文件至站点目录
#4.复制PHP代码到站点目录

ADD nginx.conf /usr/local/nginx/conf/nginx.conf
ADD start.sh /start.sh
COPY deploy /data/
COPY "erp-backend/src" /data/www

#暴露 80、443端口
EXPOSE 80 443

#运行
ENTRYPOINT "/start.sh"

EOF

# 开始构建镜像
docker build -t docker.leiyan.com/erp-api/nginx:$Tag $CODEDIR/.

# 打印当前镜像,查看是否构建成功
echo "--------------print docker images  当前镜像 --------------"
docker images

# 上传到Docker 仓库
echo "-----------start push Harbor--------------"
docker push docker.leiyan.com/erp-api/nginx:$Tag

# 把容器删除,释放空间
echo "-------------删除镜像--------------"
docker rm -f docker.leiyan.com/erp-api/nginx:$Tag 
docker rmi -f docker.leiyan.com/erp-api/nginx:$Tag

start.sh脚本内容如下:

https://github.com/skiy/nginx-php7/blob/master/start.sh

此脚本为原项目里的脚本,按照发布流程设计思路,我会在此脚本后面添加上,以下几行内容:
功能:就是运行容器时指定的环境变量-e CONF=xxx,把相应的配置文件拷贝至站点目录。

代码:

if [ $CONF == "dev" ];then
    mv /data/dev.conf /data/www/.env
elif [ $CONF == "test" ];then
    mv /data/test.conf /data/www/.env
elif [ $CONF == "pro" ];then
    mv /data/pro.conf /data/www/.env
fi

六、Jenkins创建项目并构建测试

1.构建一个自由风格的软件项目,创建Git Parameter 参数化构建

2.源码管理  

3.构建:执行shell

4.构建测试
这里我选个我们项目最新的版本

控制台日志,显示我们构建成功啦。

镜像也传到了Docker仓库。

七、 发布

上边步骤都调通后,剩下的事情就简单了。Jenkins SSH连接进入节点,下载远程镜像仓库上对应版本的容器。启动。Game Over!

1.JenKins上增加构建步骤

上边代码:

#删除上一版本的容器
docker rm -f  erp-api

#下载新构建的容器
docker pull docker.leiyan.com/erp-api/nginx:$Tag

#启动新容器
docker run   --name erp-api  -d -e CONF=dev -p 83:80 -v docker.leiyan.com/erp-api/nginx:$Tag

#CONF=dev  为使用dev.conf配置文件,在步骤五中目录结构中的3个配置文件之一。
#如果写城CONF=test  就是使用test.conf配置文件

2.打开验证

知识扩展

  容器启动正常后,作为后端服务使用,所以生产环境上,我是用nginx反向代理的功能,把请求都转发到对应的Docker容器上。Nginx配置我就不贴上来了,能看懂,看到这的兄嘚,Nginx反向配置不用我多说,都会的。

  还有就是没有做版本回滚优化,所以按现在的情景下使用,回滚版本耗时较长需要1-3分钟,有时间大家可写个脚本优化下,大概思路就是,Jenkins上选择回滚的版本,写个判断脚本,如果本地镜像仓库存在这个版本,就启动,不存在就去远程镜像仓库上拉取后再启动。