Files
cs-note/hhs/MS/05-部署运维/03-CICD与GitOps/02-GitOps与ArgoCD.md
T
2026-05-24 11:42:38 +08:00

15 KiB
Raw Blame History

tags, create time, update time
tags create time update time
gitops
argocd
flux
kubernetes
deployment
cicd
app-of-apps
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 等)

关联笔记