Jenkins 遇见 Argo CD:构建可靠 GitOps 流水线的实战指南
Jenkins 可以说是 CI 领域的老牌 "瑞士军刀",无数团队用它构建、测试、打包应用。但当部署环节还停留在 kubectl apply 脚本或 SSH 到服务器时,版本不可追踪、配置漂移、回滚困难这些痛点就会接踵而至。这时候,引入 Argo CD 实践 GitOps,让 Jenkins 与 Argo CD 各司其职,往往能让交付流水线瞬间变得优雅且可靠。本文将带你一步步拆解它们如何协同工作。
重新划分职责:CI 与 CD 彻底解耦
传统 Jenkins 流水线通常一头扎到底:拉代码 → 测试 → 构建镜像 → 直接部署到 Kubernetes。部署步骤里塞满了复杂的 Shell 命令和 if-else 判断,久而久之,流水线变成了难以维护的"面条代码"。
GitOps 的理念则要求我们有一个 "声明式的单一事实来源"------Git 仓库。集群的期望状态全部用 YAML 描述,并由控制器自动同步。于是 Jenkins 和 Argo CD 的职责变得异常清晰:
-
Jenkins 负责 CI(持续集成) :编译、测试、构建容器镜像、推送镜像,以及最关键的一步------把新镜像的标签写回 GitOps 仓库。
-
Argo CD 负责 CD(持续部署):监视 GitOps 仓库中的声明变更,自动(或手动批准后)将集群的实际状态调和为期望状态。
这种分工让每一环都专注本行:Jenkins 确保代码和镜像质量;Argo CD 确保集群与 Git 声明一致。部署逻辑不再深埋在流水线脚本里,而是透明地记录在 Git 提交历史中。
实战:构建一条 Jenkins → Argo CD 流水线
以下是一个典型的 GitOps 流水线设计,以微服务 user-service 为例。
仓库结构
我们使用 两个独立的 Git 仓库(也可以合并在一个仓库不同目录,但分开更利于权限和职责隔离):
-
应用仓库 (
app-user-service):存放服务源码、Dockerfile、Jenkinsfile。 -
GitOps 仓库 (
gitops-deployments):存放所有服务的 Kubernetes 部署清单,例如deployments/user-service/下包含 Deployment、Service 等 YAML,使用 Kustomize 或 Helm 编排。
Jenkins Pipeline:三步到位
Jenkins 在完成测试构建后,重点是优雅地更新 GitOps 仓库。下面是一段简化但完整的 Jenkinsfile 片段:
groovy
pipeline {
agent any
environment {
IMAGE_TAG = "v${BUILD_NUMBER}"
REGISTRY = "myregistry.io"
APP_NAME = "user-service"
GITOPS_REPO = "github.com/team/gitops-deployments.git"
}
stages {
stage('Build & Push Image') {
steps {
sh "docker build -t ${REGISTRY}/${APP_NAME}:${IMAGE_TAG} ."
sh "docker push ${REGISTRY}/${APP_NAME}:${IMAGE_TAG}"
}
}
stage('Update GitOps Repo') {
steps {
// 检出 GitOps 仓库
git branch: 'main', url: "https://${GIT_CREDENTIALS}@${GITOPS_REPO}"
// 用 Kustomize 修改镜像标签(也可以用 sed/yq 修改普通 YAML)
dir("deployments/${APP_NAME}") {
sh "kustomize edit set image ${REGISTRY}/${APP_NAME}:${IMAGE_TAG}"
}
// 提交变更并推送
sh '''
git config user.email "jenkins@team.com"
git config user.name "Jenkins CI"
git add .
git commit -m "Update ${APP_NAME} image tag to ${IMAGE_TAG}"
git push origin main
'''
}
}
}
}
要点:
-
尽量使用 Kustomize 或 Helm 这类结构化工具修改清单,而不是粗暴的
sed替换,这能避免格式破坏。 -
GitOps 仓库的 push 应设置严格的分支保护:要求 PR、代码审查、CI 检查,但这条流水线推送通常是自动的;如果要求审批,可以让 Jenkins 只创建一个 PR 分支,由人工合并,而不是直接推送 main。
Argo CD:自动同步集群
在集群中,我们为 user-service 定义一个 Argo CD Application:
yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: user-service
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/team/gitops-deployments.git
targetRevision: main
path: deployments/user-service
destination:
server: https://kubernetes.default.svc
namespace: user-service
syncPolicy:
automated:
prune: false # 谨慎开启 prune
selfHeal: true # 自动修复手动修改
当 Jenkins 推送新镜像标签后,Argo CD 检测到 Git 仓库中 Kustomize 描述的 Deployment 镜像字段发生变化,如果开启了 automated 策略,它将自动执行 kubectl apply,滚动更新 Pod。
如果你需要手动审批,可以关闭 automated,只使用 Argo CD 的 UI/CLI 点击 "Sync" 按钮,或者通过 Webhook 触发特定审批流。
多环境管理:同样的流水线,不同的目标
很多团队需要管理开发、预发、生产环境。同样一套 Jenkins + Argo CD 组合可以灵活应对。
-
GitOps 仓库分支/路径策略 :
例如,GitOps 仓库维护
staging和production分支,或使用目录overlays/staging、overlays/production存放 Kustomize overlays。Jenkins 根据构建分支或参数,更新对应环境的清单。例如,
main分支构建触发更新 staging 目录,release分支触发更新 production 目录。 -
Argo CD ApplicationSet :
利用 ApplicationSet 根据目录或集群自动为每个环境生成 Application,无需重复配置。
密钥处理:别把密码放在 Git 里
这是 Jenkins + Argo CD 协作中极易疏忽的一环。Secret 绝不能以明文形式保存在 GitOps 仓库中。推荐两种方案:
-
External Secrets Operator:存储密文在 Vault 或云密钥管理服务中,通过 ExternalSecret 资源从集群内同步,该资源可以安全地存放在 GitOps 仓库。
-
Sealed Secrets:Jenkins 或开发者在本地将 Secret 加密成 SealedSecret 后提交,集群控制器解密生成真正的 Secret。
无论如何,Jenkins 都不要在更新清单时写入明文密码,这是安全底线。
回滚:比以往任何时候都简单
过去你可能要跑另一个 Jenkins Job 执行一堆 kubectl 命令回滚。有了 GitOps,回滚变成了纯粹的 Git 操作:
-
方案一 :在 GitOps 仓库中
git revert那个更新镜像标签的 commit,并推送。Argo CD 检测到变更后自动(或手动)同步回旧版本。这符合完整的审计记录。 -
方案二:直接在 Argo CD UI 中使用 "History and Rollback" 功能,退回到之前的同步版本。但注意这是绕过 Git 的临时操作,应配合后续 Git 修正。
常见误区提醒(来自实践者的血泪)
-
把 Argo CD 当 CI 用:不要试图让 Argo CD 执行镜像构建,那个世界属于 Jenkins。
-
开启自动修剪 (
prune: true) 而不加思索:一旦 Git 目录误删,集群资源会被瞬间清除,生产环境可能迎来灾难。建议谨慎开启,或配合 Sync Windows 限制。 -
Jenkins 直接推送 GitOps 仓库的 main 分支无保护:至少要求 CI 流水线自身通过后可合并,或使用 Git 钩子做基本校验。
-
忘记监控 Argo CD 自身:Argo CD 控制器宕机会让自动同步失效,务必对其健康状态进行监控。
-
Jenkins 触发 Argo CD 同步打破 Git 事实来源:有时团队喜欢在 Jenkins 更新完 Git 后立即调用 Argo CD API 强制同步,这并非不可,但会掩盖 Argo CD 自身的自动同步能力,并可能造成状态混乱。更纯粹的 GitOps 方式是让 Argo CD 按自己的节奏同步(或 webhook 触发)。
结语
Jenkins 与 Argo CD 的组合,不是对旧工具的抛弃,而是一次优雅的能力重新划分。Jenkins 继续擅长它最拿手的持续集成和自动化管道,而部署的"最后一公里"则交给 Argo CD,让它以声明式的方式守护集群的终态。这样一来,你的交付流水线既保留了 Jenkins 生态的灵活性,又获得了 GitOps 带来的可审计性、一致性和极速回滚能力。
现在,不妨检查一下你现有的 Jenkins 流水线,把那些复杂的部署脚本,迁移到 Git 仓库里,让 Argo CD 开始倾听 Git 的声音吧。这条融合之路,值得一试。