主题
03 Jenkins 高可用部署
3.1 高可用方案说明
开源版 Jenkins Controller 不支持 active-active 多活(JENKINS_HOME 不允许多实例并发写)。 本次采用社区标准的 K8s 高可用模式:
| 层面 | 措施 |
|---|---|
| 控制器可用性 | K8s StatefulSet 自愈:Pod/节点故障时自动在健康节点重建,Recreate 策略保证单实例写 |
| 数据持久化 | NFS StorageClass(ReadWriteMany,20Gi),节点故障不丢数据 |
| 构建可用性 | Kubernetes 插件弹性 Agent:构建 Pod 动态调度到任意健康节点,控制器 0 执行器 |
| 配置可用性 | JCasC 配置即代码 + ConfigMap,控制器可在数分钟内无损重建/迁移 |
| 配置热更新 | kiwigrid/k8s-sidecar 监听 ConfigMap 变更自动 reload JCasC |
如需 RTO 更短的"双活"方案,需商业版 CloudBees CI(Hazelcast 主备)。开源方案下 控制器重建耗时约 1-2 分钟(Pod 重建 + Jenkins 启动),期间正在运行的 Agent 构建不受影响。
3.2 预创建资源
bash
export KUBECONFIG=~/.kube/config-122.31
K=./tools/kubectl
# 命名空间
$K create namespace jenkins
# SonarQube token 占位 secret(真实 token 在 SonarQube 部署后更新,见 04 文档)
$K -n jenkins create secret generic sonar-credentials --from-literal=sonar-token=xxx
# Maven 阿里云镜像 settings.xml(agent 构建加速)
$K -n jenkins create configmap maven-settings --from-file=settings.xml=deploy/jenkins/maven-settings.xml
# Java 示例项目源码(ConfigMap 挂载到 agent pod /examples)
$K -n jenkins create configmap jenkins-examples \
--from-file=java-demo-pom.xml=deploy/examples/java-demo/pom.xml \
--from-file=java-demo-App.java=deploy/examples/java-demo/src/main/java/demo/App.java \
--from-file=java-demo-AppTest.java=deploy/examples/java-demo/src/test/java/demo/AppTest.java3.3 Helm 安装
values 文件:deploy/jenkins/values.yaml,关键点:
controller.image: 指向 Harborjenkins/jenkins:lts-jdk21controller.serviceType: NodePort,nodePort: 30880controller.persistence: storageClassnfs、RWX、20Gicontroller.existingSecret: sonar-credentials:secret 挂载到/run/secrets/additional/,JCasC 用${readFile:...}引用controller.additionalPlugins:sonar、job-dsl(chart 默认已含 kubernetes、workflow-aggregator、git、configuration-as-code)controller.JCasC.configScripts: 系统信息 / SonarQube 服务器与凭据 / 种子任务(详见 05 文档)agent.podTemplates: maven8、maven21、node21、golang、python 五个构建模板
bash
helm install jenkins ./charts/jenkins -n jenkins -f deploy/jenkins/values.yaml --timeout 10m插件下载说明:controller 的 init 容器会从 updates.jenkins.io 下载插件。 本次实测集群可正常访问。若不可访问,可在 values 中配置国内更新中心:
yamlcontroller: initContainerEnv: - name: JENKINS_UC value: https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates
3.4 验证
bash
$K -n jenkins get pods -o wide # jenkins-0 Running 2/2
$K -n jenkins get pvc # jenkins 20Gi Bound
$K -n jenkins get svc # NodePort 30880 / agent 50000
$K -n jenkins logs jenkins-0 -c jenkins | tail浏览器访问 http://192.168.122.23:30880 ,账号 admin / xxx。
3.5 高可用验证(故障演练,已执行)
bash
# 写入数据标记 → 删除控制器 Pod → 观察自愈
$K -n jenkins exec jenkins-0 -c jenkins -- sh -c 'date +%s > /var/jenkins_home/HA_MARKER'
$K -n jenkins delete pod jenkins-0实测结果(2026-08-14):
- Pod 被删除后 StatefulSet 立即重建,调度到
sza122030.local - NFS 上 JENKINS_HOME 完整保留:
HA_MARKER内容前后一致(1786686009) - 恢复时间:首次经历冷启动约 4-5 分钟(NFS 插件加载慢);预热后实测约 2 分 20 秒(13:50 重建 → 14:05 就绪,含探针等待)
- 恢复后所有配置(JCasC)、任务、凭据、构建历史无丢失
加速建议见 07 运维手册与"性能优化"章节(插件预装自定义镜像可显著缩短恢复时间)。
3.6 踩坑记录
- 探针预算不足:chart 默认 startupProbe 12×10s=120s,NFS 上首次启动(插件解压/加载) 远超此值,导致启动循环。已在 values 中设置
controller.probes.startupProbe.failureThreshold: 60。 注意探针配置嵌套在controller.probes.*下(不是controller.startupProbe)。 - JCasC 缩进错误:configScripts 中 job-dsl
script('''...''')内嵌 pipeline 的 缩进必须深于 YAMLscript: |键,否则 snakeyaml 解析失败导致 Jenkins 启动即退出(exit 5)。 - envVars 语法:kubernetes 插件 JCasC 中容器环境变量必须写
- envVar: {key, value}, 不能直接写- key: ...。 - location 冲突:
unclassified.location.url由 chart 默认配置生成(来自controller.jenkinsUrl),在自定义 configScript 中重复定义会触发ConfiguratorConflictException。正确做法:设置controller.jenkinsUrl值。