共计 4746 个字符,预计需要花费 12 分钟才能阅读完成。
作者:vivo 互联网服务器团队 - Wu Qinghua
本文从目前业界实现 Jenkins 的高可用的实现计划,剖析各计划的优缺点,引入 vivo 目前应用的 Jenkins 高可用计划,以及目前 Jenkins 资源的调度计划的设计实际和目前的落地运行成果。
一、前言
当初的企业很多都在用 Jenkins 做继续集成,各个业务端都依附 Jenkins,vivo Devops 也是应用 Jenkins 来进行继续构建,部署 Jenkins 服务时如何保障服务的高可用变得尤为重要。
上面是目前 Jenkins 存在的 一些问题。
- Jenkins 自身是单体的,即只能有一个 Jenkins Master。尽管你也能够在多台机器上部署多个 Jenkins Master,但这些 Master 之间没有分割,都是各自把工作交给手下的 slave 去执行,没有任何交加。兴许某个 master 下的 slave 很忙,而另一个 master 下的 slave 却很闲,资源得不到充分利用。
- 当其中一个 slave 宕机之后,该 slave 上的运行的 job 工作没有版本从新进行调配,须要用户从新执行。并且 slave 节点离线之后没有告诉管理员。
- 当零碎业务量比拟大的时候业务申请集中在 Jenkins Master 上,会对 Jenkins 造成压力,甚至的造成 Jenkins 服务不可用。
- 当有 job 工作在 jenkins Master 上队列排队的时候,Jenkins Master 宕机后,队列工作不可长久化。
- Jenkins Workspace 没有主动清理性能,会导致磁盘空间有余,工作执行不了的状况。
基于以上状况,vivo Devops 对 Jenkins 的部署架构进行优化搭建,并且配套了一套 Jenkins 资源调度零碎用于治理 Jenkins 资源。
二、业界实现
目前业界也蕴含一些 Jenkins 高可用的设计形式,然而并不能齐全的满足解决上述问题,比方:
2.1 计划一 Gearman + Jenkins
这是 OpenStack 团队应用的计划。这个计划应用了 gearman,gearman 是个工作散发框架。
须要在每个 Master 上装置好 gearman 的插件,并配置好能连贯到 gearman server,同时在每个 Master 必须建设雷同的 job。
之后运行工作的流程如下:
- gearman worker 运行在各个 Jenkins Master 中期待 gearman server 散发工作;
- gearman client 向 gearman server 收回运行 job 的申请;
- gearman server 告诉各个 gearman worker 有工作拉,第一个闲着的 worker 会接受任务,如果所有的 worker 都忙,则放入 gearman 的工作队列,得 worker 闲暇时再调配;
- gearman worker 闲下来后会从工作队列里取 job 来执行,执行完之后,将后果发回给 gearman server;
- gearman server 将后果返回给 gearman client。
长处:
这样各个 salver 资源能够失去充分利用,某个 master 挂掉另外的 master 能够持续服务。
弊病:
每个 master 的 slave 必须配置统一,否则会造成 job 调度谬误,同时会造成一些资源的节约。当一个 master 呈现问题,该 master 的工作不会进行主动重新分配。
2.2 计划二 革新 Jenkins 的文件存储形式
目前 Jenkins 的配置文件都是间接在硬盘上以文件模式存储的,你在 JENKINS_HOME 的个文件夹下能看到各种.xml 文件。有些公司在 Jenkins 上进行二次开发,将 Jenkins 的数据存储形式改为数据库存储,这样前端能够起多个 Jenkins 服务,后端连雷同的数据库即可。数据库也有比拟成熟的高可用计划。
长处: 能够达到 Jenkins 的高可用也就是某个 master 挂掉另外的 master 能够持续服务。
弊病:须要对 Jenkins 进行二次开发,应用数据库会升高读取资源效率降落。
2.3 计划三 最简略的 Jenkins 一主一备模式
平时让 Jenkins A 机器提供服务,并应用 SCM Sync configuration plugin 保留数据,JenkinsA 机器批改配置后触发 Jenkins B 更新配置,一旦 Jenkins A 呈现问题挂掉后,切换到备机 Jenkins B 上。
长处: 能够达到 Jenkins 的高可用,当 master 宕机后会进行切换到备机上。
弊病: 会有一批 Jenkins 备机存在资源节约,切换 master 工夫过长,会导致有段时间 Jenkins 服务不可用。
三、vivo Jenkins Scheduler 零碎指标
因为目前业界的一些实现还不能齐全的满足咱们目前的需要,所以咱们进行了 vivo jenkins scheduler 零碎的设计与实现。该零碎须要达到如下的目标:
晋升整个构建服务可靠性时长。
保障 jenkins 集群的高可用,解决目前 master-slave 的单点问题,保障整个构建服务的可靠性时长。
升高劫难时服务复原时长。
①提供精准流控形式,在 jenkins 构建呈现申请量过高的时候能够进行流控和长久化操作,缩小对目前零碎的冲击。
②当零碎压力缩小后,放开流控能够疾速的对沉积的申请进行调配执行。
- 无效分配任务至各个子节点,保障资源的无效利用。
- 能保障劫难时的及时切换工作至可用节点上,同时能疾速的告诉管理员进行解决。
- 能进行数据的可视化剖析,能提供一系列帮忙改善开发效率的视图,比方构建时长报表、构建量报表等。
四、vivo Jenkins Scheduler 设计
该零碎咱们从两大部分进行了设计,首先,咱们不采纳原生的 Jenkins 部署计划,而是采纳全 master 的形式。第二,设计并开发了一套用于治理 Jenkins 集群的调度零碎。
五、底层 Jenkins 工具部署计划
不采纳目前单 master 的搭建计划,采纳多 master 的搭建计划,master 下不进行挂载 slave 机器,工作间接有 master 进行解决,master 之间的关系、任务分配、离线、插件装置等由调度零碎进行治理。这样因为 vivo Jenkins Scheduler 零碎为高可用的,解决了目前 Jenkins 的单点问题。
六、零碎架构图
七、零碎阐明
7.1 API-Gateway
次要提供零碎的内部申请,网关零碎,性能蕴含:
- 权限校验:校验用户发送集群管理系统的申请的权限。
- 智能路由:接管内部所有申请,并转发到后端的外服下来。
- 限流:与监控线程配合(当构建申请达到某个阈值时),进行限流操作。
- API 日志对立收集:相似于一个 aspect 切面,记录接口的进入和进来时的相干日志。
- 数据处理:对申请的参数进行数据的转换解决。
7.2 事件核心
是整个零碎通信调用的次要模块,采纳的是 Spring 的 Event 机制实现,次要外围事件如下:
Jenkins 注册事件
(EVENT\_REGIST\_JENKINS):
Jenkins 启动后,通过自定的插件会向零碎发送注册申请时,零碎接管到后会触发 Jenkins 治理模块将 Jenkins 的信息注册至调度零碎中。
Jenkins 宕机事件
(EVENT\_DOWN\_JENKINS) :
监控治理轮询查看 Jenkins 状态,当发现有 Jenkins 宕机的状况会触发该事件,Jenkins 治理模块解决将 Jenkins 的信息状态设置为不可用状态,从而是工作不能调配至该台 jenkins。
工作从调配事件 (EVENT\_JOB\_REDO) :
当 Jenkins 宕机后,如果该台 jenkins 上存在未执行完的工作时候,由 job 监控模块触发,job 治理莫管解决,会对该 Jenkins 上未执行的 job 进行重新分配。
工作承受事件 (EVENT\_JOB\_RECIVE) :
当 job 治理模块承受到创立申请,会触发该事件,由 job 治理模块放入 Redis 执行队列。
工作执行事件 (EVENT\_JOB\_EXECUTE) :
job 治理模块中的执行线程(10s 执行一次,会从 Redis 队列中弹出工作),弹出工作后触发该事件,由调度核心选取适合的 jenkins 进行执行。
7.3 调度核心
是整个零碎的外围模块,次要的性能是进行执行 job 时候能选取适合的 jenkins 进行解决工作,蕴含两个外围算法:
7.3.1 Jenkins 分组算法
每台 Jenkins 都能够应用标签的形式,打上多个标签,比方 Jenkins 能够构建 Java 程序,应用的构建工具能够是 maven 和 gradle,这个时候咱们就能够给其打上 Java、maven、gradle 三个标签。
标签的维度次要有以下几个:
- 标签配置: 判断构建配置是否配置了标签,依据标签抉择对应标签的 Jenkins,比方配置了(docker 等)。
- 构建语言: 依据构建配置的语言,比方 Java、C++、Python、Go 等。
- 构建工具和版本: 比方 Maven、gradle、Ant,Cmark、Blade 等。
- JDK 版本:比方 JDK7、JDK8 等。
- Go 语言版本:比方 1.15.x.、1.16.x 等。
- GCC 版本:如 6.x、4.x 等。
- Python 版本:2.x、3.x 等。
- 是否存活:判断 Jenkins 是否存活,如果宕机间接过滤。
- (可选策略)抉择执行过该 job 的 Jenkins,缩小下载代码的过程:(第一次构建还是会比较慢,能够采纳预执行的形式,在配置构建配置的时候,就事后执行一次,这样在用户执行的时候就应用该 job 执行过得 workspace,缩小代码下载的工夫)。
- (可选策略)依据 job 的构建的均匀构建时长,如果构建时长达到某个配置阈值时,优先选择构建器闲暇多的 Jenkins 进行执行,并指出 Jenkins 的锁定性能。其余的 job 不容许调配上来。
如果咱们给 Jenkins 打上标签,那么咱们就能够应用标签为维度将 Jenkins 进行分组,并且存入至 Redis 中缓存,不便后续选取 Jenkins 用来执行工作:
7.3.2 Jenkins 选取算法
当 Jenkins 分组好了后,咱们承受到执行的 job 的信息就能够应用 Jenkins 选取算法进行疾速的选取适合的 Jenkins 进行解决 job,如下图所示。
其中 label 子线程、语言子线程……就是咱们下面的 Jenkins 分组的维度,有多少维度,那么这里就会有多少子线程解决。
构建工作进入主线程,而后主线程会依照分组维度分组操作并进行过滤,而后获取到每个分组中适合的 Jenkins,再进行取交加(这个时候就获取到能够执行该构建工作的 Jenkins 了),在判断是否须要通过可选策略,最终失去 Jenkins。
7.4 流控治理 & 队列治理
调度零碎中的的工作承受采纳的是队列的形式实现,当零碎申请量达到阀后,零碎将不会进入 Redis 队列,会将申请长久化至 MySQL。后续如果有申请过去,job 治理模块会查看数据库 MySQL 中是否有申请,如果有申请,会将申请放入 Redis 队列,如果没有申请就会将以后申请放入 Redis 队列,具体流程如下:
其中基于 Redis 实现的音讯队列的时序图如下:
7.5 回调核心
该模块次要是监控工作的状态,当工作开始执行、中断执行、执行胜利、执行失败的时候进行告诉业务并存储数据,用于保留构建记录,不便后续数据的统计,用来实现数据的可视化。
八、施行成果
目前该零碎曾经投入生产环境运行,Jenkins 工作已采纳调度零碎进行调度执行,运行稳固,运行成果。
九、后续瞻望
随着 vivo Jenkins 调度零碎的性能缓缓欠缺,Jenkins 的机器也越来越多,目前还大多数运行在虚拟机上,从资源利用率和业务公布效率来看,将来的业务公布状态将会是以容器为主。目前公司也在大力发展 k8s 的容器生态建设,
所以咱们心愿将 Jenkins 工具前期进行容器化、池化,在进步资源利用率和公布效率的同时也能够为用户提供牢靠的、简洁的、稳固调度执行。