GitOps 落地实践
大约 12 分钟约 3542 字
GitOps 落地实践
简介
GitOps 的核心思想是让 Git 成为系统期望状态的唯一可信来源(Single Source of Truth),并由自动化控制器持续把运行环境拉回到 Git 所描述的状态。它不是简单地"把 YAML 存到 Git",而是围绕声明式配置、审计、审批、漂移检测、回滚和自动同步建立一整套交付模式。
GitOps 的设计哲学可以追溯到基础设施即代码(IaC)和声明式系统管理理念。它的核心假设是:如果系统的期望状态被精确地描述在版本控制中,那么任何运行环境的偏差都是可以被检测和自动修复的。这意味着部署不再是"执行一系列命令",而是"声明我想要什么状态,让系统自己去达成"。
特点
GitOps 核心原则
四大原则
# GitOps 四大核心原则(OpenGitOps 标准)
# 原则一:声明式
# 系统的期望状态必须以声明式方式描述
# 而不是命令式脚本(如 kubectl run, helm install)
# Kubernetes YAML、Kustomize overlay、Helm values 都是声明式
# 原则二:版本控制
# 所有声明式配置必须存储在版本控制系统中
# Git 是事实上的标准
# 支持 PR 审核、历史追溯、回滚
# 原则三:自动拉取(Pull-based)
# 系统状态通过自动化的拉取方式同步
# 控制器(Argo CD/Flux)定期检查 Git 仓库的变化
# 而不是 CI 推送到集群(Push-based)
# 原则四:持续调和(Continuous Reconciliation)
# 控制器持续监控并自动修复偏差
# 任何手工修改都会被检测到并自动回滚
# 确保集群状态始终与 Git 保持一致Push 模式 vs Pull 模式
# 传统 Push 模式(CI/CD Pipeline)
[开发者] -> [Git Push] -> [CI Pipeline] -> [kubectl apply] -> [K8s 集群]
# CI 需要集群访问权限
# 部署由 CI 触发
# 状态不可自动修复
# GitOps Pull 模式
[开发者] -> [Git Push] -> [Git 仓库] <- [Argo CD/Flux 自动拉取] <- [K8s 集群]
# 控制器在集群内部运行
# 自动检测变更并同步
# 自动修复漂移实现
Argo CD 基础应用定义
# Argo CD Application 定义
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: order-service
namespace: argocd
labels:
team: backend
env: production
annotations:
notifications.argoproj.io/subscribe.on-deployed.slack: platform-deploys
notifications.argoproj.io/subscribe.on-health-degraded.slack: platform-alerts
# Finalizer 确保删除 Application 时同步清理集群资源
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/example/platform-config.git
targetRevision: main
path: apps/order-service/overlays/prod
# Helm 源配置(可选)
# repoURL: https://charts.example.com
# chart: order-service
# targetRevision: "1.5.0"
# helm:
# values: |
# replicas: 4
# image:
# tag: "1.0.5"
destination:
server: https://kubernetes.default.svc
namespace: order-prod
syncPolicy:
automated:
prune: true # 自动删除 Git 中不存在的资源
selfHeal: true # 自动修复漂移
allowEmpty: false # 不允许空目录
syncOptions:
- CreateNamespace=true # 自动创建命名空间
- PrunePropagationPolicy=foreground
- PruneLast=true # 最后执行 prune
retry:
limit: 3 # 同步失败重试次数
backoff:
duration: 5s
factor: 2
maxDuration: 3m
# 忽略特定字段的漂移
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas # 忽略 HPA 修改的副本数# apps/order-service/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
labels:
app: order-service
version: v1
spec:
replicas: 2
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: registry.example.com/order-service:1.0.0
ports:
- containerPort: 8080
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
env:
- name: APP_ENV
value: "production"
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: order-service-secret
key: db-password# apps/order-service/base/service.yaml
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order-service
ports:
- port: 80
targetPort: 8080
type: ClusterIP# apps/order-service/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- configmap.yaml
- hpa.yaml# apps/order-service/overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
# 命名空间覆盖
namespace: order-prod
# 镜像覆盖
images:
- name: registry.example.com/order-service
newTag: "1.0.5"
patches:
- target:
kind: Deployment
name: order-service
patch: |-
- op: replace
path: /spec/replicas
value: 4
- op: replace
path: /spec/template/spec/containers/0/resources/requests/memory
value: "512Mi"
- op: replace
path: /spec/template/spec/containers/0/resources/limits/memory
value: "1Gi"
# ConfigMap 生成器覆盖
configMapGenerator:
- name: order-service-config
behavior: merge
files:
- application-prod.yml# Argo CD 命令行操作
# 安装 Argo CD
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# 获取初始密码
argocd admin initial-password -n argocd
# 创建应用
argocd app create order-service \
--repo https://github.com/example/platform-config.git \
--path apps/order-service/overlays/prod \
--dest-server https://kubernetes.default.svc \
--dest-namespace order-prod \
--sync-policy automated \
--auto-prune \
--self-heal \
--revision main
# 同步应用
argocd app sync order-service
argocd app sync order-service --prune
argocd app sync order-service --force # 强制同步(删除并重建)
# 查看应用状态
argocd app get order-service
argocd app diff order-service # 查看差异
argocd app list
argocd app history order-service # 查看部署历史
# 回滚
argocd app rollback order-service <revision>
# 删除应用
argocd app delete order-service --cascadeRepo 分层、密钥与多环境管理
# 推荐的 Git 仓库目录结构
platform-config/
├── apps/ # 应用配置
│ ├── order-service/
│ │ ├── base/ # 基础配置
│ │ │ ├── deployment.yaml
│ │ │ ├── service.yaml
│ │ │ ├── configmap.yaml
│ │ │ └── kustomization.yaml
│ │ └── overlays/ # 环境覆盖
│ │ ├── dev/
│ │ │ ├── kustomization.yaml
│ │ │ └── configmap-dev.yaml
│ │ ├── staging/
│ │ │ └── kustomization.yaml
│ │ └── prod/
│ │ ├── kustomization.yaml
│ │ └── configmap-prod.yaml
│ ├── payment-service/
│ └── user-service/
├── infrastructure/ # 基础设施配置
│ ├── ingress-nginx/
│ ├── cert-manager/
│ ├── prometheus/
│ ├── grafana/
│ └── external-secrets/
└── clusters/ # 集群级配置
├── dev/
│ └── argocd-apps.yaml # App of Apps 入口
└── prod/
└── argocd-apps.yaml# 密钥管理:SealedSecrets
# 不要把密钥明文提交到 Git
# 安装 SealedSecrets Controller
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/latest/download/controller.yaml
# 加密密钥
echo -n 'my-db-password' | kubeseal --raw --name order-service-secret --namespace order-prod
# SealedSecret 资源(可以安全提交到 Git)
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: order-service-secret
namespace: order-prod
spec:
encryptedData:
db-password: AgBycHJvZHlAaGRyZWdyZWUub3JnL3YxYml0c2...
template:
type: Opaque
metadata:
name: order-service-secret
namespace: order-prod# 密钥管理:External Secrets(推荐)
# 从外部密钥管理系统同步密钥到 K8s
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: payment-secret
namespace: payment-prod
spec:
refreshInterval: 1h # 每小时刷新
secretStoreRef:
name: vault-backend # Vault 密钥存储
kind: ClusterSecretStore
target:
name: payment-secret
creationPolicy: Owner
template:
type: Opaque
data:
- secretKey: databasePassword
remoteRef:
key: prod/payment-service
property: databasePassword
- secretKey: apiSecretKey
remoteRef:
key: prod/payment-service
property: apiSecretKey# 密钥管理:AWS Secrets Manager
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: aws-secrets-manager
spec:
provider:
aws:
service: SecretsManager
region: cn-east-1
auth:
jwt:
serviceAccountRef:
name: external-secrets-sa
namespace: external-secrets# App of Apps 模式 — 统一管理所有应用
# clusters/prod/argocd-apps.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: prod-cluster-root
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/example/platform-config.git
targetRevision: main
path: clusters/prod
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true# clusters/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../infrastructure/ingress-nginx
- ../../infrastructure/cert-manager
- ../../infrastructure/prometheus
- ../../apps/order-service/overlays/prod
- ../../apps/payment-service/overlays/prod
- ../../apps/user-service/overlays/prodFlux 自动化
# Flux GitRepository
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: app-config
namespace: flux-system
spec:
interval: 1m
url: https://github.com/example/platform-config.git
ref:
branch: main
# SSH 认证
secretRef:
name: git-credentials# Flux Kustomization
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: order-service
namespace: flux-system
spec:
interval: 5m
path: ./apps/order-service/overlays/prod
prune: true
sourceRef:
kind: GitRepository
name: app-config
targetNamespace: order-prod
# 验证配置
validation: client
# 健康检查
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: order-service
namespace: order-prod
# 变更等待
patches:
- target:
kind: Deployment
name: order-service
patch: |-
- op: replace
path: /spec/replicas
value: 4# Flux Image Repository
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: order-service
namespace: flux-system
spec:
image: registry.example.com/order-service
interval: 1m
# 私有仓库认证
secretRef:
name: registry-credentials# Flux Image Policy(自动选择最新镜像版本)
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: order-service-policy
namespace: flux-system
spec:
imageRepositoryRef:
name: order-service
policy:
semver:
range: ">=1.0.0 <2.0.0"
# 选择最新稳定版本
# alphabetical: latest# Flux Image Update Automation
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageUpdateAutomation
metadata:
name: order-service-auto-update
namespace: flux-system
spec:
interval: 5m
sourceRef:
kind: GitRepository
name: app-config
git:
commit:
author:
email: flux-bot@example.com
name: flux-bot
messageTemplate: |
automated: update image for order-service
{{range .Updated.Images}}{{println .}}{{end}}
push:
branch: main
update:
path: ./apps/order-service/overlays/prod
strategy: Setters漂移检测与治理
# GitOps 漂移检测常见场景:
# 1. 运维人员 kubectl edit 手改 Deployment
# -> Argo CD 检测到 diff,自动回滚(selfHeal: true)
# -> 或者发出告警,等待人工确认
# 2. HPA 自动修改副本数
# -> ignoreDifferences 配置忽略 replicas 字段
# -> 避免与 HPA 冲突
# 3. Admission Webhook 注入字段(如 sidecar)
# -> ignoreDifferences 配置忽略注入字段
# -> 或使用 server-side apply
# 4. Operator 管理的字段被 GitOps 覆盖
# -> ignoreDifferences 或 syncOptions: RespectIgnoreDifferences=true
# 5. 不可变字段修改导致 sync 失败
# -> 使用 --force 强制同步(删除并重建)
# -> 或修改 Git 配置以避免不可变字段冲突# 常见漂移忽略配置
spec:
ignoreDifferences:
# 忽略 HPA 修改的副本数
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas
# 忽略 Istio 注入的 sidecar
- group: apps
kind: Deployment
jsonPointers:
- /spec/template/spec/containers/1
# 忽略 managedFields
- group: ""
kind: Secret
jsonPointers:
- /metadata/managedFields回滚策略
# Argo CD 回滚
# 方式一:Git 回滚
git revert HEAD
git push
# Argo CD 自动同步回滚后的配置
# 方式二:Argo CD 回滚命令
argocd app rollback order-service <revision>
argocd app history order-service
# 方式三:回滚到特定 Git 提交
argocd app set order-service --revision <commit-hash>
argocd app sync order-service
# 方式四:回滚到特定标签
argocd app set order-service --revision v1.0.0
argocd app sync order-serviceArgo CD 项目与权限
# Argo CD Project 定义
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: backend-team
namespace: argocd
spec:
description: Backend team applications
# 允许的源仓库
sourceRepos:
- https://github.com/example/backend-apps.git
- https://github.com/example/shared-configs.git
# 允许的目标集群和命名空间
destinations:
- namespace: 'backend-*'
server: https://kubernetes.default.svc
- namespace: order-prod
server: https://kubernetes.default.svc
# 集群资源黑名单
clusterResourceWhitelist:
- group: ''
kind: Namespace
# 命名空间资源黑名单
namespaceResourceBlacklist:
- group: ''
kind: ResourceQuota
# 同步窗口(限制同步时间)
syncWindows:
- kind: allow
schedule: '0 10 * * 1-5' # 工作日上午 10 点
duration: 2h
applications:
- '*-prod-*'Argo CD 通知
# Argo CD 通知配置
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
service.slack: |
token: $slack-token
template.app-deployed: |
message: |
Application {{.app.metadata.name}} has been deployed.
Status: {{.app.status.sync.status}}
Health: {{.app.status.health.status}}
Revision: {{.app.status.sync.revision}}
trigger.on-deployed: |
- description: Application is synced and healthy
send:
- app-deployed
oncePer: app.status.sync.revision
when: "app.status.operationState.phase in 'Succeeded' and app.status.health.status == 'Healthy'"优点
缺点
总结
GitOps 的真正价值是把"部署动作"转化为"配置状态治理"。要想真正落地,不仅要有 Argo CD 或 Flux,还要配套目录分层、密钥方案、PR 审核、回滚策略和 drift 治理规则;否则只是把 YAML 放进 Git,并不能自动获得 GitOps 的好处。
关键知识点
- Git 保存的是期望状态,不是操作步骤
- GitOps 控制器负责持续对比并同步运行环境状态
- 密钥、镜像版本、环境覆盖层是最容易出问题的三个点
- 自动同步前,必须先解决 drift、不可变字段和回滚策略问题
- App of Apps 模式适合统一管理多集群多应用
- ignoreDifferences 是解决 HPA、Admission 注入导致漂移的关键配置
- SealedSecrets 和 External Secrets 是密钥管理的两大主流方案
项目落地视角
- 平台团队统一维护基础设施仓库,业务团队维护应用 overlay
- 所有生产变更通过 PR 审核,禁止直接
kubectl edit - 镜像版本通过 Git 提交驱动发布,而不是手工改 tag
- 使用 App of Apps / 分环境目录统一管理多集群应用
- 建立多级审批流程:测试环境自动同步,生产环境手动审批
常见误区
- 把 GitOps 理解成"YAML 放 Git + 手工点同步"
- 敏感信息明文提交到仓库
- 多环境直接复制 YAML,不做 base/overlay 分层
- 集群里仍然允许大量手工修改,导致 Git 与真实状态长期漂移
- 不配置 ignoreDifferences,导致 HPA 和 Admission 注入引发持续 diff
- 忽视回滚策略,遇到不可变字段变更时无法回滚
进阶路线
- 引入 Argo Rollouts 实现 GitOps + 金丝雀/蓝绿发布
- 使用 Image Update Automation 自动提升镜像版本
- 建立 GitOps 审计、策略校验(OPA/Kyverno)和合规检查
- 把 Terraform / Crossplane 等基础设施声明也纳入 GitOps 体系
- 学习 Argo CD ApplicationSet 实现动态多集群应用管理
- 建立 GitOps 度量体系(同步成功率、漂移率、回滚频率)
适用场景
- Kubernetes 应用持续交付
- 多环境配置和多集群治理
- 需要强审计、强审批、强回滚能力的平台团队
- 希望减少人工部署差异与环境漂移的组织
- 需要标准化交付流程的规模化团队
落地建议
- 从非核心环境先试点 GitOps,再推广到生产
- 统一目录结构、命名规范、环境分层和 PR 流程
- 密钥必须使用 SealedSecrets、Vault 或 External Secrets 管理
- 定期做 drift 巡检,逐步消灭集群中的手工变更入口
- 为生产环境配置手动同步 + 审批流程
- 建立 GitOps 培训和最佳实践文档
排错清单
- 检查 Git 仓库目标分支、路径和 revision 是否正确
- 检查控制器 sync 状态、事件和 diff 内容
- 检查是否存在 admission 注入、不可变字段修改或权限问题
- 检查集群真实状态与 Git 声明状态是否被手工修改过
- 检查 Argo CD/Flux 的 RBAC 权限是否足够
- 检查 Webhook 是否正确配置(Git 变更是否能触发同步)
复盘问题
- 你的环境里,真正的"单一可信来源"是否已经是 Git?
- 哪些发布操作仍然依赖人工命令而不是 PR?
- 回滚时,是回 Git 提交就够了,还是还需要人工补救?
- 当前最大的 GitOps 障碍,是流程、权限、工具还是组织习惯?
- 密钥管理是否已经安全地集成到 GitOps 流程中?
- 多环境配置是否通过 overlay 而不是复制 YAML 来管理?
