点击上方“中兴开发者社区”,关注我们
每天读一篇一线开发者原创好文
DevOps微课系列旨在帮助用户学习DevOps实践。
1.方案框架
OpenStack CI典型的基于ZUUL框架的通信机制图如下:
开发者提交变更到Gerrit代码库后会产生Gerrit事件流,ZUUL会侦测相关事件并进行相关处理(比如准备变更测试的临时代码库),然后通过GearmanServer分发任务到Jenkins Master,Jenkins Master再分配节点进行任务执行,任务执行完成后执行结果再原路返回给Gerrit,形成闭环。
2.基于云CI的ZUUL方案框架
考虑到与现有云CI的兼容,基于云CI的ZUUL方案与OpenStack基于ZUUL的CI框架基本一致:
ZUUL-SERVER、ZUUL-MERGER、HTTPD(APACHE)和Jenkins Master封装在docker
里,作为一个实体存在,而Gearman Server则内置在ZUUL-SERVER中;项目配置(包括ZUUL配置)均挂载到容器内,实现业务逻辑与配置分离。
数据流如下:
① 用户提交代码到Gerrit
② Zuul侦听到项目gerrit代码库变更事件
③ Zuul Merger/HTTPD准备临时的变更代码库供后续测试
④ Zuul通过Gearman Server给Jenkins Master分发测试任务
⑤ Jenkins Master分发任务到Slave执行
⑥ Jenkins Slave下载临时变更代码库执行测试
测试结果再逆向返回给Gerrit形成闭环:Jenkins Slave >Jenkins Master>Zuul->Gerrit。
3.关键问题及解决
1) ZUUL与Gerrit保活
Zuul运行一段时间不时出现无法接收Gerrit事件问题,确认系Zuul与Gerrit保活导致,需要增加保活配置,修改zuul/connection/gerrit.py文件。
详情请参考:https://review.openstack.org/#/c/238988/
1) SSH保活
目前的云CI集群都是基于TECS2.0的,前期碰到SSH保活相关问题,排查确认需要应用层自己配置SSH保活参数,因此Jenkins Master的docker镜像中需要配置SSH保活参数。
修改server端的etc/ssh/sshd_config
① 修改client端的etc/ssh/ssh_config
Slave镜像如若用到SSH,也需要按上所述进行配置。
1) 先有鸡还是先有蛋
由于Mesos的资源调度是先有资源需求后Mesos才会根据需求动态分配资源,而Gearman的调度是先有资源了才会进行任务分发,因此这里存在"先有鸡还是先有蛋"的问题。
考虑以下几个方案:
① Jenkins上死循环执行一个空JOB
② Jenkins周期性(50s)执行一个空JOB
③ ZUUL设置触发JOB,该触发JOB限定在master上执行,通过该触发JOB的子JOB来执行实际的任务
经测试,结果如下:
方案a: 不会触发,Gearman调度框架只会识别空闲资源才会进行任务分发
方案b: 任务只会在该JOB所在的节点上固定执行,再多的任务需求Mesos也不会额外分配资源,无法满足并发需求
方案c: 满足需求
通过方案c可解决"先有鸡还是先有蛋"的问题,将master从节点个数设置为多个可满足并发需求,master上的触发JOB什么都不干,只是起触发器作用,后续如若有性能瓶颈,再考虑其它解决方案。
2) 只能触发一次
Jenkins Master上电初始化后会通过Jenkins Gearman Plugin创建Worker,并向Gearman Server注册相关Jobs信息。在Jenkins页面任何配置变更时,Gearman plugin都会重新注册Jobs信息。
经测试发现,在Jenkins Master启动后,Gerrit首次触发正常,后续均不能触发,且Jenkins收不到构建任务。经分析,在首次触发新分配的mesos节点在完成任务释放后,Gearman Server的worker注册Jobs信息全部清零,因此后续触发时Gearman认为无Job可以执行。
分析Gearman Plugin插件代码,发现有一处代码可优化解决该问题,该处代码的逻辑会导致在mesos节点完成任务执行释放后将Gearman Server上的Jobs注册信息全部清零。优化修改后问题解决。
src/main/java/hudson/plugins/gearman/ExecutorWorkerThread.java
4.ZUUL配置
ZUUL配置问题主要集中在zuul.conf和layout.yaml,zuul.conf主要针对zuul的一些账户信息的配置,layout.yaml主要针对gerrit工程与jenkins job关联触发关系的注册,需要将这两个文件的配置修改可视化出来。
经过分析zuul.conf中的配置只需要配置Gerrit User信息即可,其它信息都可以根据相关信息动态生成;layout.yaml可全部呈现出来,方便用户修改。由于这两个文件是ZUUL的核心配置信息,且ZUUL未提供配置reload渠道,这两个文件修改后需要重启ZUUL相关组件以重新加载载配置信息,因此这两个文件的修改不应过于频繁。
考虑到Jenkins上已有Gearman Plugin插件的配置,可以将ZUUL配置和Gearman Plugin配置放到一起,通过修改Gearman Plugin代码,增加相关配置满足需求。
配置情况如下图所示:
ZUUL配置请参考: http://docs.openstack.org/infra/zuul/zuul.html
5.Master从节点个数变更
采取如上5.3方案时,在需要增加项目并发度时可修改master从节点数目,但是修改maser从节点数目后Gearman Plugin/Server并不会感知,需要有个途径通知Gearman Server进行数据更新,因此考虑通过修改Gearman Plugin代码探测master从节点数目变更,然后由Gearman Plugin发起数据更新。
6.项目账号隔离
通过在Mesos Sand Box里识别该项目账号所在虚机的GID/UID信息,基于源ZUUL镜像创建项目账号生成该项目账号的镜像,然后在执行docker时以该项目账号执行,完成项目账号的隔离。
7.方案应用
基于ZUUL框架的云CI通过制度化的流程保证提交正式分支的代码质量,其核心是支持异地协作、多人并发修改代码及提交评审,并进行事前的逐单验证,确保主干分支绝对安全。主要流程:
① 开发者发起git review
② 触发Verify CI
③ 代码评审
④ 触发Merge CI,如果通过则Merge到正式分支
其中步骤①)和③是人工完成的,其它步骤依托ZUUL+云CI自动化完成。 目前该方案在CMS、Netnumen、5Gran、AIP项目落地实施,项目反馈较好,再也无需担心并发多单依赖问题了。 项目上线该方案也较简单,只需四步走:
① 项目发起申请,并准备好业务镜像(在原有业务镜像上安装Zuul Cloner组件)
② 起项目云CI实例
③ 项目配置Zuul参数:Gerrit User和Zuul Layout.yaml
④ 项目增加job配置,提交代码变更到Gerrit代码库,全流程测试通过