15 KiB
tags, create time, update time
| tags | create time | update time | |||||||
|---|---|---|---|---|---|---|---|---|---|
|
2026-05-17 10:00 | 2026-05-17 10:30 |
GitOps 与 ArgoCD
概述
本文档深入讲解 GitOps 工作流和 ArgoCD 的使用。内容覆盖:从"传统 CI/CD 的痛点"到 "Git 即真相源",ArgoCD 架构解析、Application CRD 编写、App of Apps 模式、Helm/Kustomize 混合使用、同步钩子与安全实践。工具选型对比参见 ../03-CICD与GitOps。
核心思想:让集群自己"拉取"状态
[!question] 谁来"推动"变更到集群?
传统模式下,Jenkins 拿着 kubeconfig SSH 到 K8s 执行
kubectl apply。但问题来了:如果有人在集群里直接改了配置(比如手动kubectl edit deployment),Jenkins 并不知道——这就是配置漂移。GitOps 的答案:让 K8s 集群自己"拉取"自己的状态。 Git 仓库是唯一真相源,任何变更都通过 PR 进入 Git,工具自动同步到集群。
flowchart LR
Dev["开发者 PR"] -->|"修改 K8s manifest"| Git[(Git Repo)]
subgraph Cluster["K8s Cluster"]
Argo["ArgoCD / Flux"] -->|同步| K8sState["Pod/Service/ConfigMap"]
end
Git -.->|Webhook Polling| Argo
Argo -->|"检测到差异"| Diff{"状态一致?"}
Diff -- 否 --> Sync["自动同步到 K8s ✅"]
Diff -- 是 --> OK["已一致 ⏸️"]
style Git fill:#e3f2fd
style Argo fill:#fff3e0
style K8sState fill:#e8f5e9
Push vs Pull:本质区别
| 传统 CI/CD (Push) | GitOps (Pull) | |
|---|---|---|
| 部署驱动 | CI 服务器主动推送 | Git 仓库变动触发拉取 |
| 安全边界 | CI 需要直连 K8s(暴露 kubeconfig) | ArgoCD 在集群内运行,无需外部访问 |
| 漂移检测 | 通常无 | 持续比对,自动修复 |
| 回滚方式 | 回到上一次 pipeline | git revert + 自动同步 |
[!tip] Push vs Pull 的安全含义
- Push:CI 服务器持有集群凭据,主动向 K8s 发请求。凭据泄露 = 集群沦陷。
- Pull:ArgoCD 在集群内部以 Pod 运行,只需读取 Git 的只读权限。即使 Git 凭据泄露,攻击者也无法写入集群——他们无法改变 Git 中的 YAML。
ArgoCD 架构深度解析
ArgoCD 是 CNCF 级别的 GitOps 持续交付工具。
flowchart TB
Git[(Git Repository)]
subgraph ArgoCDServer["ArgoCD Server (集群外)"]
UI["Web UI"]
API["API"]
end
subgraph ArgoCDController["ArgoCD Controller (集群内)"]
SyncLoop["同步循环\n(每 3 分钟)"]
Reconcile["Reconcile: Git Manifest vs K8s 实际状态"]
end
Git -->|只读 access_token| SyncLoop
SyncLoop --> Reconcile
Reconcile -->|"发现不一致"| Apply["kubectl apply"]
Apply --> K8s["K8s Cluster"]
K8s -->|"读取实际状态"| SyncLoop
style Git fill:#e3f2fd
style ArgoCDServer fill:#fff3e0
style ArgoCDController fill:#e8f5e9
关键概念
| 术语 | 说明 |
|---|---|
| Application | ArgoCD 管理的核心资源,定义"从哪个 Git 路径同步到哪个命名空间" |
| Sync Policy | 决定是自动同步还是手动触发;以及同步策略(Prune resources, Self-heal) |
| Health Status | ArgoCD 对资源的健康检查(Deployment 是否有可用副本、Pod 是否 Running 等) |
| Drift Detection | 对比 Git 中声明的配置与实际 K8s 状态的差异 |
| App of Apps | 用 Application 来管理 Application,实现分层编排 |
Application 配置实战
典型 Application
# apps/order-service.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: order-service
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/team/k8s-manifests.git
targetRevision: main
path: overlays/production/order-service
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # 删除 Git 中不存在的资源
selfHeal: true # 自动修复被手动改动的资源
syncOptions:
- CreateNamespace=true # 目标命名空间不存在时自动创建
字段速查:
prune: true— Git 里删了的东西,集群上也删掉selfHeal: true— 有人手动改了 Deployment?下次同步循环自动改回来CreateNamespace=true— 不需要提前手动创建命名空间
App of Apps:多层级应用编排
当有几十上百个服务时,用一个 Application 管理一个服务太繁琐了。ArgoCD 支持 "应用的 Application" 模式:
# root-application.yaml —— 根级别 Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: cluster-services
spec:
sources:
- repoURL: https://github.com/team/k8s-manifests.git
targetRevision: main
path: apps/order-service
- repoURL: https://github.com/team/k8s-manifests.git
targetRevision: main
path: apps/payment-service
- repoURL: https://github.com/team/k8s-manifests.git
targetRevision: main
path: apps/user-service
这种模式下,开发者只需要往 apps/ 目录下新增文件夹并提交 PR,根 Application 就会自动把新服务拉到集群。
[!tip] App of Apps 的最佳实践
- 按团队或环境划分层级:
root-app → team-a-services / team-b-services- 每个子 Application 可以有自己的
syncPolicy和namespace- 不要超过 3 层嵌套,调试会变得困难
进阶:中间件集成
Helm + Kustomize 混合使用
ArgoCD 同时支持 Helm 和 Kustomize 作为 source plugin。实际工程中,最常见的组合是:
CI pipeline 用 Helm build chart → ArgoCD 通过 Helm source 读取并部署到集群。
# apps/order-service.yaml —— 使用 Helm Source
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: order-service
spec:
project: default
source:
repoURL: https://github.com/team/k8s-manifests.git
targetRevision: main
path: charts/order-service # Helm Chart 目录
helm:
valueFiles:
- values.yaml # 默认值文件
- values-production.yaml # 生产环境覆盖
parameters: # 命令行参数覆盖(优先级最高)
- name: replicas
value: "3"
- name: image.tag
value: "{{ .Values.image.sha }}" # 引用 CI 写入的 commit SHA
destination:
server: https://kubernetes.default.svc
namespace: production
[!question] 为什么不只用纯 YAML?
想象一下:每个环境的 Deployment 只有
replicas、resources、imageTag不同,其余完全一样。如果全部写为裸 YAML,维护 5 个环境 = 维护 5 份几乎相同的文件。Helm/Kustomize 让你用 模板化 + 差异覆盖 解决这个 DRY 问题。
ArgoCD 原生 Kustomize 示例
# 直接用 kustomize 作为 source
spec:
source:
repoURL: https://github.com/team/k8s-manifests.git
targetRevision: main
path: overlays/production/order-service # kustomize overlay 路径
kustomize:
images:
- name: myregistry/order-service
newTag: v1.2.3 # CI 注入的镜像版本
[!note] 选择建议
场景 推荐 需要复杂的条件渲染和复用 Helm 简单的环境覆盖(改几个字段) Kustomize ArgoCD 原生支持两者,可以混用(多源模式已在 App of Apps 中展示) —
同步工作流:Hook 与健康检查
同步生命周期
flowchart LR
A["Git 提交"] --> B{"ArgoCD\n检测到差异"}
B -->|"执行 PreSync Hook"| C["PreSync"]
C -->|"迁移 DB Schema"| D[健康检查]
D -->|"前向兼容? "| E["Sync"]
E -->|"部署新版本"| F["PostSync Hook"]
F -->|"灰度验证 / 通知"| G["Health Status"]
style C fill:#fff3e0
style E fill:#e3f2fd
style F fill:#e8f5e9
style G fill:#f3e5f5
PreSync Hook:数据库迁移示例
# hooks/db-migration.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
annotations:
argocd.argoproj.io/hook: PreSync # Sync 之前执行
argocd.argoproj.io/hook-delete-policy: HookSucceeded # 成功后自动清理
spec:
template:
spec:
containers:
- name: migrate
image: myregistry/order-service:v1.2.3
command: ["./migrate", "--up"]
restartPolicy: Never
常用 Hook 阶段:
| 阶段 | 时机 | 典型用途 |
|---|---|---|
PreSync |
Sync 之前 | DB 迁移、缓存预热 |
Sync |
替代默认同步行为 | 复杂的多步骤部署 |
PostSync |
Sync 之后 | 灰度验证、发 Slack 通知 |
SyncFail |
Sync 失败时 | 回滚、告警 |
[!important] Hook 注意事项
hook-delete-policy: HookSucceeded— 避免残留大量已完成的历史 Job- PreSync Hook 本身也有健康检查机制,Job 必须 Running → Succeeded 才算通过
- Hook Job 和目标 Application 必须在同一个 Kubernetes 集群
自定义健康检查
ArgoCD 内置了对 Deployment、StatefulSet、Service 等资源的健康检查。对于自定义 CRD(比如 CassandraCluster),可以通过 Script Health Check 实现:
# ConfigMap 挂载到 ArgoCD Server
apiVersion: v1
kind: ConfigMap
metadata:
name: resource-customizations
namespace: argocd
data:
myapp.example.com_CassandraCluster.health.lua: |
local status = {}
if obj.status ~= nil then
if obj.status.readyNodes ~= nil then
if obj.status.readyNodes >= 3 then
status.status = "Healthy"
else
status.status = "Progressing"
status.message = "Only " .. tostring(obj.status.readyNodes) .. " ready nodes"
end
end
end
return status
[!tip] 常见内置资源健康状态速查
资源类型 Healthy 条件 Progressing 条件 Deployment 所有 replicas Ready 且当前 replicaReadyCount < desired StatefulSet 所有 Pod Running Pending 或 replica 不足 Service 存在即 Healthy —(通常不 Progressing) Ingress 有 backend 即 Healthy — ConfigMap/Secret 存在即 Healthy —
日志调试与故障排查
ArgoCD CLI 常用命令
# 实时日志
argocd app logs order-service --follow
# 指定Pod日志(查看特定容器)
argocd app logs order-service -p order-service-pod-abc123 -c sidecar
# 查看应用事件(谁触发的同步、为什么失败)
argocd app events order-service
# 强制刷新(跳过缓存)
argocd app get order-service --refresh
常见故障排查流程
flowchart TD
A["Application 显示 OutOfSync"] --> B{手动 sync 是否成功?}
B -- 是 --> C["✅ 可能是临时网络抖动, Watch 恢复即可"]
B -- 否 --> D["查看 Events\nargocd app events"]
D --> E{"错误原因?"}
E -- "ImagePullBackOff" --> F["镜像仓库不可达/凭据过期\n→ 检查 ImagePullSecrets"]
E -- "CrashLoopBackOff" --> G["应用启动失败\n→ 查看 Pod 日志\nargocd app logs"]
E -- "ResourceQuota exceeded" --> H["命名空间配额不足\n→ 调整 Quota 或精简资源"]
E -- "RBAC denied" --> I["ArgoCD SA 权限不足\n→ 检查 ClusterRole Binding"]
E -- "Custom health check failing" --> J["自定义健康脚本语法错误\n→ 检查 resource-customizations ConfigMap"]
style F fill:#ffebee
style G fill:#e3f2fd
style H fill:#fff3e0
style I fill:#f3e5f5
style J fill:#e8f5e9
调试 Checklist
kubectl get application -n argocd— 确认 Application CR 状态kubectl describe application xxx -n argocd— 查看 Conditions 和最后同步信息argocd app logs xxx --tail 100— Controller 日志,搜索 Error 关键字- 确认 Git Repo URL 和 token 可用:手动 curl 测试
- 如果是 self-heal 反复触发:检查是否有外部控制器在修改资源
安全要点
RBAC 配置
# argocd-rbac-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-rbac-cm
namespace: argocd
data:
policy.default: role:readonly # 默认只读
policy.csv: |
# g, github-org:team-name, role:admin # 团队级管理
p, role:order-service-deployer, applications, sync, */order-service, allow
g, github:alice, role:order-service-deployer # alice 可同步 order-service
scopes: '[groups]' # 从 OIDC token 获取 groups
Secrets 管理建议
| 方式 | 适用场景 | 备注 |
|---|---|---|
| ArgoCD Secret | Git 仓库凭据、K8s cluster 注册 | 存储为 SealedSecret/ExternalSecret |
| External Secrets Operator | RDS 密码、API Key | 从 AWS Secrets Manager / Vault 拉取 |
| SealedSecret | 跨集群复用加密 secrets | 公钥加密,仅 controller 可解密 |
[!warning] 常见误区
- 不要把 Git SSH Private Key 存入集群的普通 Secret — 应该用
argocd reponame配置项统一管理- Application 的 namespace 要单独隔离 —
argocd命名空间不应和生产共享- 启用 OIDC + RBAC scopes — 让团队只能看到自己管理的 Application
现在回到日常操作:
常见运维场景
手动触发同步
当 Git 已更新但 ArgoCD 未自动同步时:
argocd app sync order-service --force
查看同步状态和历史
argocd app get order-service # 当前状态
argocd app history order-service # 同步历史
argocd app diff order-service # Git vs 实际的差异
回滚到上一个版本
argocd app rollback order-service
# 或直接 git revert 对应的 commit,ArgoCD 自动同步
解除锁定(Stuck App 恢复)
argocd app unlock order-service
工具选型:ArgoCD vs Flux
| 特性 | ArgoCD | Flux v2 |
|---|---|---|
| UI | 丰富的 Web UI,可视化对比 | CLI + Kubernetes-native,轻量 UI |
| 通知 | Slack/Discord/GitHub native | Event controller + Webhook |
| Helm | 内置 Helm Source 插件 | 一等公民(HelmRelease) |
| 多集群 | 多集群统一管理 | 需配合 Image Automation |
| 适合场景 | 可视化管理需求强的团队 | 纯 GitOps 极客团队 |
[!note] 选型建议
- 如果你已经重度使用 Helm:Flux 的 HelmRelease CRD 更自然
- 如果你希望可视化查看每次部署的差异:ArgoCD 的 diff view 是杀手功能
- 两者可以并存——比如 ArgoCD 管应用层,Flux 管基础设施层(CNI、CSI 等)
关联笔记
- 01-CICD基础与实践 — CI/CD Pipeline 的搭建与实践
- 03-Helm模板管理 — Helm Chart 编写与管理
- 04-安全与发布策略 — 安全管理与发布决策
- ../03-CICD与GitOps — 参考手册与决策指南