为了实现PHP业务快速对接K8S系统,需要配套相关的构建与发布流程。
背景
公司原有一个发布系统(运维研发),是基于ansible批量分发代码到虚拟机,提供一个django实现的web console点鼠标发布程序。
基于设施现状以及人力情况,我对K8S发布项目的拆解如下:
- 研发负责建设Jenkins的构建流程
- 运维负责改造现有发布系统,对接Jenkins实现镜像打包,支持K8S应用发布
架构
关键在于对构建流程的抽象设计,以便用同一套构建流程适应所有应用。
下图是整体流程,在新窗口打开查看:
人为操作入口收敛在发布系统,Jenkins仅仅作为一个隐藏在背后的backend服务提供镜像打包流程。
为了打通两个系统,我选择以发布系统的一次构建任务ID为线索,通过Jenkins API传参到Jenkins内部的构建任务。Jenkins任务则可以调用发布系统获取对应构建任务的详细信息(发布系统配置的业务描述信息),就可以实现同一套CI流程适配多个项目的目的,即共享pipeline。
实现原理
针对PHP项目来说,整个Jenkins只需要创建一个pipeline项目,它们使用同一套构建流程,通过发布系统获取任务数据,以便实现多项目构建。
发布系统只需要传递本次构建的任务ID到Jenkins即可:
Pipeline定义非常简单,所有与发布系统、代码仓库、镜像仓库的交互逻辑全部实现在shell脚本中,部分逻辑用到了Python实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
pipeline { agent any options { // 禁止并发构建 quietPeriod(0) } // harbor帐号密码 environment { HARBOR_ACCOUNT = credentials('63db0c4a-d102-4936-bd80-81a57409c429') GITLAB_ACCOUNT = credentials('3909526f-17b7-4952-9db3-c4b397b6daa1') } stages { stage("准备数据") { steps { sh "sh php/start.sh" } } stage("构建应用") { steps { sh "sh php/build_app.sh" } } stage("打包镜像") { steps { sh "sh php/build_image.sh" } } stage("推送镜像") { steps { sh "sh php/push_image.sh" } } } post { always { sh "sh php/end.sh ${currentBuild.currentResult}" } } } |
这里需要注意,因为所有PHP项目共享同一个Jenkins pipeline项目,所以需要调整1个重要参数:
- quitePeriod:静默时间,也就是连续触发同一个pipeline可能受到静默处理,这里设置为0秒即可避免静默。
Jenkins对于一个pipeline的多个并发构建来说,会创建不同的workspace作为上下文环境,所以不需要担心并发冲突:
业务编译的deploy.tar.gz会解压到镜像内,在容器启动时会拉起业务脚本完成部署。
通用dockerfile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# PHP项目 - 通用dockerfile # 包含PHP和NGINX环境的基础镜像 FROM registry-team.xxx.com/base/php7:latest # 容器内工作目录 WORKDIR /root # 把build.sh产生的部署包解压到WORKDIR/deploy子目录 ADD ["deploy.tar.gz", "./deploy/"] # 把nginx配置文件解压到WORKDIR/nginx目录 ADD ["nginx.tar.gz", "./"] # 启动前置脚本 ADD ["prepare.sh", "./"] # 容器启动命令 ENTRYPOINT sh prepare.sh && sh start.sh |
prepare.sh完成服务拉起前的准备工作:
1 2 3 4 5 6 7 8 9 10 11 |
#!/bin/bash set -e # 生效nginx配置文件 if [ -n "$(ls -A nginx)" ];then cp -rf nginx/* /usr/local/nginx/conf/sites-enabled.conf/ fi # 调用业务自定义deploy.sh拉起服务 cd ./deploy && sh ./deploy.sh && cd - |
发布系统
发布系统在产生构建任务的时候需要填写本次构建任务是什么项目、什么分支、什么理由等关键信息。
因此,在Jenkins构建的末尾,会把构建任务ID与产生的镜像名回传给发布系统,这样发布系统就可以在mysql中按关系存储该镜像,并且明确记录该镜像属于什么项目、什么分支、什么理由。
其他
在定义镜像tag的时候,我选择了:业务代码commit id+timestamp的形式。
如果仅仅用commit id作为标识的话,当我们升级底层基础image并重新构建项目image的时候,就会覆盖掉之前的同名image,万一升级底层出现问题希望回滚就很麻烦了,所以引入了时间加以区分。
如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~

感谢分享~ 有启发
1
DHorse(https://github.com/tiandizhiguai/dhorse)也是一个基于k8s的自动化开发平台。