GitOps 与 ArgoCD 实战:声明式持续交付的最佳实践

系统讲解 GitOps 理念与 ArgoCD 实战,从核心概念、架构设计、生产级部署到渐进式发布策略,构建基于 Git 的云原生持续交付体系

GitOps 与 ArgoCD 实战:声明式持续交付的最佳实践

引言:为什么需要 GitOps

传统的发布流程是这样的:开发提交代码 → CI 构建镜像 → 运维 ssh 到集群执行 kubectl apply。这种模式有三个问题:

  1. 配置漂移:集群里的实际状态和文档对不上了,谁改的、什么时候改的,没人知道
  2. 环境差异:dev、staging、prod 三套环境的配置靠人肉维护,极易出错
  3. 回滚困难:出问题时要回滚,要么找镜像备份、要么翻 Git 历史,效率极低

GitOps 的核心思想用一句话概括:

用 Git 作为应用和环境配置的"唯一事实源",集群的实际状态应该始终与 Git 中的声明一致。

本文将系统讲解 GitOps 理念与 ArgoCD 的实战应用。

第一章:GitOps 核心概念

1.1 GitOps 的四个原则

Weaveworks 提出的 GitOps 四大原则:

  1. 声明式:整个系统用声明式描述(K8s YAML、Helm Chart)
  2. 版本化且不可变:所有配置存储在 Git,享受版本管理天然能力
  3. 自动拉取:Agent 自动从 Git 拉取变更并应用到集群
  4. 持续调和:Agent 持续确保集群状态与 Git 一致

1.2 Push vs Pull:两种部署模式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
传统 Push 模式(CI 触发部署):
┌──────┐    push    ┌─────────┐
│  CI  │ ──────────▶│ Cluster │
└──────┘            └─────────┘
(CI 拥有集群写权限)

GitOps Pull 模式(CD 自主同步):
┌──────┐    pull    ┌─────────┐
│  Git │ ◀──────────│ ArgoCD  │
└──────┘            └─────────┘
(CD Agent 在集群内运行,自主决定同步时机)

为什么 Pull 更优?

  • 安全性:CI 不需要集群凭证,凭证只在集群内部
  • 解耦:CI 只负责构建与推送,CD 负责部署
  • 可控性:集群状态永远可重建(“Git 即真理”)

1.3 GitOps 工具生态

工具 特点
ArgoCD CNCF 毕业项目,UI 强大,K8s 原生
Flux CNCF 毕业项目,轻量,GitOps Toolkit
Jenkins X 基于 Tekton 的云原生 CI/CD
Fleet Rancher 出品,擅长多集群

本文重点讲 ArgoCD,它是目前最受欢迎的 GitOps 工具。

第二章:ArgoCD 架构剖析

2.1 核心组件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
┌─────────────────────────────────────────────────┐
│                  ArgoCD                          │
│  ┌─────────┐  ┌──────────────┐  ┌────────────┐  │
│  │ API Server│ │ Repo Server  │  │ Application│ │
│  │          │  │ (git clone)  │  │ Controller │  │
│  └─────────┘  └──────────────┘  └─────┬──────┘  │
└─────────────────────────────────────┼──────────┘
                                      │
                                      ▼
                              ┌─────────────┐
                              │  K8s Cluster│
                              └─────────────┘
  • API Server:对外提供 Web UI 与 gRPC/REST API
  • Repo Server:从 Git 仓库拉取清单(Helm/Kustomize 渲染)
  • Application Controller:持续比对 Git 与集群状态,发现差异就同步

2.2 CRD 资源

ArgoCD 通过 CRD 管理应用:

  • Application:单个应用的 GitOps 单元
  • ApplicationSet:批量管理多套环境/多集群的应用
  • AppProject:权限与项目边界

2.3 同步策略

ArgoCD 有两种同步方式:

  • 自动同步(Automated):检测到 Git 变更后自动 apply
  • 手动同步(Manual):通过 UI/CLI 触发 apply

第三章:ArgoCD 安装与初始化

3.1 安装方式

1
2
3
4
5
6
7
# 方式一:官方 manifest(最简单)
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# 方式二:Helm(推荐生产)
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd argo/argo-cd -n argocd --create-namespace

3.2 访问配置

1
2
3
4
5
# 端口转发(开发环境)
kubectl port-forward svc/argocd-server -n argocd 8080:443

# 获取初始密码
argocd admin initial-password -n argocd

3.3 Ingress 暴露(生产推荐)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd-server-ingress
  namespace: argocd
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: HTTPS
spec:
  ingressClassName: nginx
  rules:
  - host: argocd.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: argocd-server
            port:
              number: 443

第四章:第一个 Application

4.1 准备 Git 仓库结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
my-app/
├── base/                  # 基础配置
│   ├── deployment.yaml
│   ├── service.yaml
│   └── kustomization.yaml
└── overlays/
    ├── dev/               # 开发环境
    │   └── kustomization.yaml
    └── prod/              # 生产环境
        └── kustomization.yaml

4.2 创建 Application

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app-prod
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/my-app.git
    targetRevision: main
    path: overlays/prod
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true        # 删除集群中存在但 Git 中不存在的资源
      selfHeal: true     # 自动修复偏离(drift)
    syncOptions:
      - CreateNamespace=true

4.3 CLI 操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 登录
argocd login argocd.example.com

# 创建应用
argocd app create my-app-prod \
  --repo https://github.com/myorg/my-app.git \
  --path overlays/prod \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace production \
  --sync-policy automated

# 同步
argocd app sync my-app-prod

# 查看状态
argocd app get my-app-prod

第五章:进阶功能

5.1 多环境管理:ApplicationSet

当你要部署多套环境(dev/staging/prod)或多集群时,逐个管理 Application 会很累。ApplicationSet 通过模板生成:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: my-app
  namespace: argocd
spec:
  generators:
  - list:
      elements:
      - cluster: dev
        url: https://dev-cluster.example.com
        version: '1.0'
      - cluster: staging
        url: https://staging-cluster.example.com
        version: '1.0'
      - cluster: prod
        url: https://prod-cluster.example.com
        version: '1.1'
  template:
    metadata:
      name: 'my-app-{{cluster}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/myorg/my-app.git
        targetRevision: '{{cluster}}'
        path: overlays/{{cluster}}
      destination:
        server: '{{url}}'
        namespace: '{{cluster}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true

5.2 渐进式发布:Argo Rollouts

Argo Rollouts 提供高级发布策略(蓝绿、金丝雀、流量切分):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: my-app
spec:
  replicas: 5
  strategy:
    canary:
      steps:
      - setWeight: 10         # 第一步:10% 流量
      - pause: {duration: 2m}  # 暂停 2 分钟观察
      - setWeight: 50         # 第二步:50% 流量
      - pause: {duration: 5m}
      - setWeight: 100        # 全量
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: my-app:1.0.0

5.3 Secret 管理

Git 中存明文密码是禁忌。推荐方案:

方案一:Sealed Secrets

1
2
3
4
# 加密
kubeseal --cert pub-cert.pem < secret.yaml > sealed-secret.yaml

# 应用后由 controller 自动解密

方案二:External Secrets Operator

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
spec:
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: db-credentials-secret
  data:
  - secretKey: password
    remoteRef:
      key: secret/data/db
      property: password

方案三:SOPS + Mozilla

1
2
3
4
# 用 KMS 密钥加密
sops --encrypt --kms arn:aws:kms:... secret.yaml > secret.enc.yaml

# Git 中是密文,ArgoCD 拉取时通过 plugin 解密

5.4 通知与告警

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
  namespace: argocd
data:
  service.slack: |
    token: $slack-token
  trigger.on-deployed: |
    - when: app.status.operationState.phase in ['Succeeded']
      send: [app-deployed]
  template.app-deployed: |
    message: |
      Application {{.app.metadata.name}} 部署成功 🚀

第六章:生产级最佳实践

6.1 仓库结构设计

推荐使用应用清单与业务代码分离的仓库结构:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
infrastructure-repo/      # 基础设施仓库
  ├── clusters/
  │   ├── dev/
  │   ├── staging/
  │   └── prod/
  └── apps/
      ├── my-app/
      └── other-app/

app-source-repo/          # 业务代码仓库
  ├── src/
  ├── Dockerfile
  └── .argocd-source-my-app.json   # 指向 manifest 仓库

6.2 同步窗口

生产环境建议设置同步窗口(避免深夜自动发布):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
syncPolicy:
  automated:
    prune: true
    selfHeal: true
  syncWindow:
    kind: allow
    schedule: '0 9 * * 1-5'   # 工作日 9 点到 18 点
    duration: 9h
    applications:
    - '*-prod'

6.3 RBAC 与项目隔离

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: production
spec:
  sourceRepos:
  - 'https://github.com/myorg/prod-manifests'
  destinations:
  - namespace: 'prod-*'
    server: https://kubernetes.default.svc
  clusterResourceWhitelist:
  - group: ''
    kind: Namespace
  namespaceResourceWhitelist:
  - group: 'apps'
    kind: Deployment

6.4 健康检查

ArgoCD 会根据 CRD 健康检查自动判断应用状态:

1
2
3
4
5
6
7
8
apiVersion: argoproj.io/v1alpha1
kind: Application
spec:
  ignoreDifferences:
  - group: apps
    kind: Deployment
    jsonPointers:
    - /spec/replicas    # 忽略 HPA 导致的 replicas 差异

第七章:常见问题与排障

7.1 OutOfSync 状态

应用显示 “OutOfSync” 但 git 已经是最新:

1
2
3
4
5
# 刷新
argocd app get my-app --refresh

# 硬刷新(重新拉取清单)
argocd app get my-app --hard-refresh

7.2 Sync 失败:Webhook 问题

1
2
3
4
5
# 重启 webhook
kubectl rollout restart deployment argocd-server -n argocd

# 检查 repo server 日志
kubectl logs -n argocd -l app.kubernetes.io/name=argocd-repo-server

7.3 卡在 Progressing

通常是健康检查失败:

1
2
# 查看资源详情
argocd app manifests my-app | kubectl apply --dry-run=server -f -

第八章:面试高频问题

Q1:GitOps 和 DevOps 的关系?

DevOps 是文化与流程理念,强调开发运维协作。GitOps 是 DevOps 在云原生时代的具体实现方式,用 Git 作为唯一事实源。

Q2:为什么用 Pull 模式而不是 Push 模式?

安全性:CI 不需要集群凭证,只在集群内部的 ArgoCD 持有凭证。 解耦:CI 负责构建推送,CD 负责应用部署。 可恢复:集群可以从 Git 完全重建。

Q3:ArgoCD 和 Flux 怎么选?

ArgoCD:UI 强大,团队协作友好,企业首选。 Flux:轻量,GitOps Toolkit 灵活,DevOps 平台嵌入友好。

Q4:ApplicationSet 和 Application 的区别?

Application 是单个应用。ApplicationSet 是模板生成器,能基于 list、cluster、git 等生成器批量产出 Application。

Q5:如何处理 Git 中的 Secret?

几种方案:

  1. Sealed Secrets(密钥对加密)
  2. External Secrets Operator(运行时从 Vault 拉取)
  3. SOPS + KMS(基于云 KMS 加密)

Q6:drift 是什么?如何处理?

Drift 指集群实际状态偏离 Git 期望状态。可能是 HPA 调整副本数、运维手动改了配置等。处理方式:selfHeal 自动恢复,或通过 ignoreDifferences 白名单忽略已知差异。

结语:GitOps 是云原生的"版本控制"

GitOps 不是新工具,而是一种新的工作范式。它把版本控制的能力从代码扩展到了整个生产环境:

  • 每次变更都有迹可循
  • 出问题可以一键回滚
  • 新环境从 Git 即可克隆

掌握 GitOps + ArgoCD,已经成为云原生工程师的标配能力。建议你在本地用 minikube + ArgoCD 实操一遍,体验从 Git 提交到应用更新的快感。

下一篇,将进入面试总结:从高频问题到系统化回答方法论。


配套阅读:

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
使用 Hugo 构建
主题 Stack 由 Jimmy 设计