本文探讨如何使用开源版本构建高可用的 Jenkins。
在开始讨论高可用性之前,您首先需要了解 Jenkins 如何管理其数据和高层架构。如果您不了解该架构,我强烈建议您阅读 Jenkins 架构帖子。
核心要点摘要
- 开源 Jenkins 很难做真正的主主高可用,因为 Jenkins 的核心数据大量保存在平面文件中,同一份数据通常只能由一个主节点实例安全读写。
- 对多数使用开源 Jenkins 的团队,更现实的方案是 active-passive 思路:保证同一时刻只有一个 Jenkins master 运行,故障后自动拉起新实例并挂载同一份数据。
- 在虚拟机或云主机场景,可以用自动扩缩组把最小和最大实例数都设为 1,再配合外部磁盘、生命周期钩子和启动脚本恢复 Jenkins。
- 在 Kubernetes 场景,Jenkins master 更适合用 StatefulSet 加持久卷部署,并把副本数保持为 1。
- Jenkins 的构建能力可以通过动态 Agent 横向扩展,但这不等于 master 主节点高可用。
先明确:本文说的 Jenkins HA 是什么
这里讨论的不是“多个 Jenkins master 同时读写同一份数据并同时接任务”的主主高可用。对开源 Jenkins 来说,这条路很容易带来数据一致性问题。
本文讨论的是更常见也更保守的恢复型高可用:Jenkins master 故障后,由自动化机制尽快拉起另一个 master,并挂载原有 Jenkins 数据目录,让服务恢复到可用状态。它不能做到零中断,但能显著减少人工恢复时间。
Jenkins HA 方案
由于 Jenkins 管理数据的方式,没有直接的方法将 Jenkins 设置为高可用模式。
Jenkins 在平面文件 (xml) 中管理其数据,并且您只能拥有一个可以读取 Jenkins 数据的主节点实例。
因此,官方不支持以主-主的方式运行 Jenkins,即有多个 master 节点,都可以处理任务的方式。例如,如果您尝试使用共享卷配置多个主节点,则会出现读写不一致的情况,从而导致 Jenkins 不稳定。
有两种方法可以让 Jenkins 处于 HA 模式。
- Jenkins active-active/active-passive 模式 只有企业 Jenkins 附带受支持的插件才能进行此设置。但大多数组织都使用开源版本,他的选择超出了范围。另外,还有一个使用 HAproxy 的选项,但是,我认为这会产生一些管理开销。
- 基于自动扩缩组的 Jenkins HA 架构:让 Jenkins 加入自动扩缩组是获得高可用 Jenkins 的一种解决方法。它不是 100% HA 解决方案;但是,无论出于何种原因,如果您的 Jenkins 服务器崩溃,短时间内就会出现另一个实例。这适用于基于 VM 和 Kubernetes 的 Jenkins 设置
基于自动扩缩组的 Jenkins HA 架构
您可以将此方法称为 Jenkins HA 的穷人解决方案。因为,当一个实例宕机时,另一个实例需要几分钟的宕机时间才能启动(vm + java服务启动时间)。但它有效。
此方法适用于任何具有自动缩放选项的私有/公共云平台。
这种方法类似于在 Kubernetes 上部署 Jenkins,如果 Jenkins pod 出现故障,另一个 pod 将提供相同的数据。
这里不是 pod,而是虚拟机,因此启动时间比启动新 pod 需要更多时间。
让我们看看使用自动缩放组的 Jenkins HA 设置的高级架构。

这里的理念非常简单:
- Jenkins 部署在一个自动缩放组中,最小和最大数量都设置为 1。它确保我们始终只有一个 Jenkins 实例在运行。
- 然后,我们有一个专用的外部磁盘来保存Jenkins数据。它可以是单独的卷或 NFS 共享。自动缩放映像启动脚本(AMI 用户数据)会在该磁盘启动时正常附加该磁盘。
- 如果活动的 Jenkins 实例出现故障,自动扩展策略将启动另一个实例,同时终止不活动的实例。在此过程中,数据磁盘从终止实例中优雅地分离(在 AWS 中使用生命周期挂钩)并附加到新实例,保留之前的 Jenkins 状态和数据。
- 所有现有作业都将在停机期间失败,或者在新实例出现时继续。
此设置还使升级和修补过程变得如此简单。
基于 Kubernetes 的 Jenkins HA 架构
当部署在 Kubernetes 时,它应该通过 StatefulSet 部署。此外,我们需要将 StatefulSet 副本保持为一个,并且 Jenkins 数据目录应该挂载到持久卷以存储 Jenkins 数据(例如,作业历史、插件、配置)。
即使 Jenkins master pod 被重新调度或重新启动,这也可以确保数据仍然存在。
有多种方法可以扩展 Jenkins 代理。在此方法中,一旦构建完成,代理就会动态配置和终止。
Agent 水平扩展
好消息是,您可以水平扩展 Jenkins agent。有多种方法可以水平扩展 Jenkins agent。以下方法,agent 都是动态提供,用完了就自动终止:
- 使用 Kubernetes Pod 扩展 Jenkins agent
- 使用 Docker 扩展 Jenkins agent
- 使用 EC2 扩展 Jenkins agent
部署 Jenkins HA
如果您想在 AWS 云上尝试此部署,可以使用我的文档。我在这里记录了 AWS 的整个部署方法:《使用 AWS Autoscaling group 部署 Jenkins HA》,相关 IaC 代码在:
https://github.com/techiescamp/devops-projects 请尝试此这套配置,看看它是否适合您。
另外,您应该使用插件和磁盘快照定期备份 jenkins 数据。如果您有所有数据备份,您可以轻松恢复可以正常工作的版本。
结论
开源 Jenkins 的高可用设计,要先接受一个事实:master 主节点不适合用共享卷做主主读写。更稳妥的方案,是把 master 做成单实例、可自动重建、数据外置、备份可恢复;把并发构建压力放到动态 Agent 上解决。
如果业务对 CI/CD 中断极其敏感,需要评估企业版 Jenkins 或其他具备更完整 HA 能力的方案。对于多数团队,自动扩缩组或 Kubernetes StatefulSet 加持久化存储,再配合备份和动态 Agent,已经能覆盖常见故障恢复需求。
FAQ
Q1:开源 Jenkins 可以做主主高可用吗? A:不建议。Jenkins 大量数据存放在平面文件中,多个 master 同时读写共享数据目录容易造成读写不一致,进而让 Jenkins 不稳定。
Q2:自动扩缩组方案是不是 100% 高可用? A:不是。它属于恢复型高可用。活动实例故障后,新实例需要启动虚拟机、挂载磁盘并启动 Java 服务,因此会有短暂停机。
Q3:Kubernetes 上部署 Jenkins master 应该用 Deployment 还是 StatefulSet? A:文中建议使用 StatefulSet,并保持副本数为 1,同时把 Jenkins 数据目录挂载到持久卷。
Q4:Jenkins Agent 水平扩展能解决 master 高可用吗? A:不能。Agent 水平扩展解决的是构建并发和资源弹性问题,master 高可用还需要单独处理数据持久化、实例恢复和备份。
