GitOps 与 ArgoCD 实战:声明式持续交付的最佳实践
引言:为什么需要 GitOps
传统的发布流程是这样的:开发提交代码 → CI 构建镜像 → 运维 ssh 到集群执行 kubectl apply。这种模式有三个问题:
- 配置漂移:集群里的实际状态和文档对不上了,谁改的、什么时候改的,没人知道
- 环境差异:dev、staging、prod 三套环境的配置靠人肉维护,极易出错
- 回滚困难:出问题时要回滚,要么找镜像备份、要么翻 Git 历史,效率极低
GitOps 的核心思想用一句话概括:
用 Git 作为应用和环境配置的"唯一事实源",集群的实际状态应该始终与 Git 中的声明一致。
本文将系统讲解 GitOps 理念与 ArgoCD 的实战应用。
第一章:GitOps 核心概念
1.1 GitOps 的四个原则
Weaveworks 提出的 GitOps 四大原则:
- 声明式:整个系统用声明式描述(K8s YAML、Helm Chart)
- 版本化且不可变:所有配置存储在 Git,享受版本管理天然能力
- 自动拉取:Agent 自动从 Git 拉取变更并应用到集群
- 持续调和: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?
几种方案:
- Sealed Secrets(密钥对加密)
- External Secrets Operator(运行时从 Vault 拉取)
- SOPS + KMS(基于云 KMS 加密)
Q6:drift 是什么?如何处理?
Drift 指集群实际状态偏离 Git 期望状态。可能是 HPA 调整副本数、运维手动改了配置等。处理方式:selfHeal 自动恢复,或通过 ignoreDifferences 白名单忽略已知差异。
结语:GitOps 是云原生的"版本控制"
GitOps 不是新工具,而是一种新的工作范式。它把版本控制的能力从代码扩展到了整个生产环境:
- 每次变更都有迹可循
- 出问题可以一键回滚
- 新环境从 Git 即可克隆
掌握 GitOps + ArgoCD,已经成为云原生工程师的标配能力。建议你在本地用 minikube + ArgoCD 实操一遍,体验从 Git 提交到应用更新的快感。
下一篇,将进入面试总结:从高频问题到系统化回答方法论。
配套阅读: