GitOps 部署实践: ArgoCD 与 Flux
深入理解 GitOps 理念,学习使用 ArgoCD 和 Flux 实现声明式部署,以及构建可靠的 GitOps 工作流。
概述
GitOps 是一种以 Git 为唯一信任源的运维理念和实践模式。通过将基础设施和应用声明式地存储在 Git 仓库中,实现自动化、可审计、可回滚的部署体验。本文将深入探讨:
学习目标:
- 理解 GitOps 核心理念与优势
- 掌握 ArgoCD 的安装与使用
- 学会 Flux 的集群同步配置
- 构建多环境 GitOps 工作流
- 实现密钥管理与安全加固
GitOps 核心理念
什么是 GitOps?
┌─────────────────────────────────────────────────────────────────┐
│ GitOps 理念 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ GitOps = Git + Operations │
│ │
│ 核心原则: │
│ ✓ 声明式配置(Everything as Code) │
│ ✓ Git 是唯一事实来源(Single Source of Truth) │
│ ✓ 自动化同步(Automated Synchronization) │
│ ✓ 拉取式部署(Pull-based Deployment) │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Git │ ────▶│ CD │ ────▶│ Cluster │ │ │
│ │ │ Repo │ │ Tool │ │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ YAML/ │ │ ArgoCD │ │ K8s │ │ │
│ │ │ Helm/ │ │ Flux │ │ Deploy │ │ │
│ │ │ Kustom │ │ │ │ │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ ◀──────────────────────────────────────── │ │
│ │ 自动同步(观察实际状态 vs 期望状态) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
GitOps vs 传统 CD
┌─────────────────────────────────────────────────────────────────┐
│ GitOps vs 传统 CI/CD │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 传统 CI/CD(Push-based) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Code → CI → Build → Push → kubectl apply │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────┐ │ │
│ │ │ Cluster │ │ │
│ │ └─────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ 问题: │
│ - 凭证需要推送到 CI 系统 │
│ - 难以审计和回滚 │
│ - 配置漂移难以检测 │
│ │
│ GitOps(Pull-based) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────┐ │ │
│ │ │ Git │◀─────────│ CD │ │ │ │ │
│ │ │ Repo │ │ Agent │◀────────│ K8s │ │ │
│ │ └─────────┘ └────┬────┘ └──┬──┘ │ │
│ │ │ │ │ │
│ │ ▼ ▼ │ │
│ │ Watch Git Deploy │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ 优点: │
│ - 无需集群凭证在 CI 系统 │
│ - 自动检测和修复配置漂移 │
│ - 完整的审计日志(git commit) │
│ - 一键回滚(git revert) │
│ │
└─────────────────────────────────────────────────────────────────┘
ArgoCD
ArgoCD 简介
┌─────────────────────────────────────────────────────────────────┐
│ ArgoCD 核心概念 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ArgoCD 是声明式的 GitOps 持续交付 工具 │
│ │
│ 特性: │
│ ✓ 声明式应用定义(Application CRD) │
│ ✓ 自动部署到目标集群 │
│ ✓ 实时状态同步 │
│ ✓ Web UI 和 CLI │
│ ✓ 多环境/多集群支持 │
│ ✓ RBAC 权限控制 │
│ ✓ 可观测性(指标、日志、事件) │
│ │
└─────────────────────────────────────────────────────────────────┘
安装 ArgoCD
# 方式1:kubectl 安装
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v2.10.0/manifests/install.yaml
# 方式2:HA 安装
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v2.10.0/manifests/ha/install.yaml
# 方式3:Helm 安装
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd argo/argo-cd -n argocd --create-namespace
# 访问 ArgoCD Server
# 方式1:LoadBalancer
kubectl patch svc argocd-server -n argocd -p '{"spec":{"type":"LoadBalancer"}}'
# 方式2:NodePort
kubectl patch svc argocd-server -n argocd -p '{"spec":{"type":"NodePort"}}'
# 方式3:Ingress
kubectl apply -f ingress.yaml
# 获取初始密码
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
Application CRD
# application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp.git
targetRevision: main
path: deploy/k8s # Chart 或 K8s YAML 目录
helm:
valueFiles:
- values-prod.yaml
parameters:
- name: image.tag
value: v1.2.0
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # 自动删除清理
selfHeal: true # 自动修复漂移
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
多集群部署
# app-of-apps.yaml - 应用集
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: appset
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/infra.git
path: apps
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
---
# clusters/staging.yaml
- name: staging
server: https://staging.example.com
namespaces:
- app
- monitoring
---
# clusters/production.yaml
- name: production
server: https://production.example.com
namespaces:
- app
- monitoring
ArgoCD 模板
# application-template.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: {{ name }}
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: {{ repoURL }}
targetRevision: {{ branch | default "main" }}
path: {{ path }}
helm:
valueFiles:
{{- range .values }}
- {{ . }}
{{- end }}
destination:
server: {{ server }}
namespace: {{ namespace }}
syncPolicy:
automated:
prune: true
selfHeal: true
Flux
Flux 简介
┌─────────────────────────────────────────────────────────────────┐
│ Flux 工作原理 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Flux v2 组件: │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Source │ │ Kustomize │ │ Helm │ │
│ │ Controller │ │ Controller│ │ Controller │ │
│ ├─────────────┤ ├─────────────┤ ├─────────────┤ │
│ │ GitRepo │ │ Kustomize │ │ HelmRelease│ │
│ │ HelmRepo │ │ Overlay │ │ │ │
│ │ Bucket │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Reconciliation │ │
│ │ │ │
│ │ 检测 Git 变化 → 应用 Kustomize/Helm → 部署到集群 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
安装 Flux
# 安装 Flux CLI
curl -s https://fluxcd.io/install.sh | bash
# 验证安装
flux --version
# 引导安装(创建所有 CRD 和控制器)
flux bootstrap github \
--owner=myorg \
--repository=flux-infra \
--branch=main \
--path=./clusters/production \
--token-auth
# 或 bootstrap gitlab
flux bootstrap gitlab \
--owner=myorg \
--repository=flux-infra \
--path=./clusters/production
# 检查状态
flux get all -n default
GitRepository
# gitrepository.yaml
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
name: myapp
namespace: flux-system
spec:
interval: 1m
url: https://github.com/myorg/myapp.git
ref:
branch: main
# 或使用 tag
# tag: v1.0.0
# semver: ">=1.0.0"
secretRef:
name: git-credentials
ignore: |
# 忽略特定文件/目录
.git/
*.md
---
# 创建 credentials
apiVersion: v1
kind: Secret
metadata:
name: git-credentials
namespace: flux-system
type: Opaque
stringData:
username: git
password: <token>
Kustomization
# kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: myapp
namespace: flux-system
spec:
interval: 5m # 同步间隔
path: ./deploy/production # Kustomize 路径
prune: true # 删除清理
wait: true # 等待资源就绪
sourceRef:
kind: GitRepository
name: myapp
namespace: flux-system
targetNamespace: production # 部署到目标命名空间
postBuild:
substitute:
IMAGE_TAG: v1.2.0
ENVIRONMENT: production
dependsOn:
- name: common-config # 依赖其他 Kustomization
HelmRelease
# helmrelease.yaml
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: myapp
namespace: production
spec:
interval: 5m
chart:
spec:
chart: myapp
version: "1.x"
sourceRef:
kind: HelmRepository
name: myapp-charts
namespace: flux-system
values:
image:
repository: myregistry/myapp
tag: v1.2.0
replicaCount: 3
resources:
limits:
cpu: 1000m
memory: 1Gi
# 覆盖 values
postRenderers:
- kustomize:
patches:
- target:
kind: Deployment
name: myapp
patch: |
- op: replace
path: /spec/replicas
value: 5
多租户隔离
# tenants.yaml - 多租户 Flux 配置
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
name: app1
namespace: app1-namespace
annotations:
toolkit.fluxcd.io/tenant: app1
spec:
url: https://github.com/app1/deploy.git
# ...
---
# RBAC 配置
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: flux-app1-reconciler
namespace: app1-namespace
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
多环境管理
目录结构
repository/
├── clusters/ # 集群配置
│ ├── production/
│ │ ├── kustomization.yaml
│ │ └── apps.yaml
│ └── staging/
│ ├── kustomization.yaml
│ └── apps.yaml
├── apps/ # 应用配置
│ ├── myapp/
│ │ ├── base/
│ │ │ ├── kustomization.yaml
│ │ │ ├── deployment.yaml
│ │ │ └── service.yaml
│ │ ├── overlays/
│ │ │ ├── staging/
│ │ │ │ ├── kustomization.yaml
│ │ │ │ └── replica-count.yaml
│ │ │ └── production/
│ │ │ ├── kustomization.yaml
│ │ │ └── replica-count.yaml
│ │ └── releases/
│ │ ├── v1.0.yaml
│ │ └── v1.1.yaml
├── infrastructure/ # 基础设施
│ ├── cert-manager/
│ ├── ingress-nginx/
│ └── monitoring/
└── README.md
Kustomize 多环境
# apps/myapp/overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patches:
- path: replica-count.yaml
images:
- name: myapp
newName: myregistry/myapp
newTag: v1.2.0-prod
configMapGenerator:
- name: app-config
behavior: merge
literals:
- ENVIRONMENT=production
- LOG_LEVEL=warn
replicas:
- name: myapp
count: 5
环境晋升流程
┌─────────────────────────────────────────────────────────────────┐
│ 环境晋升流程 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ PR ┌─────────┐ PR ┌─────────┐ │
│ │ develop │ ──────▶ │ staging │ ──────▶ │production│ │
│ │ │ │ │ │ │ │
│ │ 开发环境 │ │ 预发环境 │ │ 生产环境 │ │
│ │ 自动部署 │ │ 自动部署 │ │ 手动部署 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ feature/* develop release/* │
│ 分支开发 分支 标签/版本 │
│ │
│ Promotion 策略: │
│ - develop: 任何合并自动部署 │
│ - staging: main 分支自动部署 │
│ - production: 需要手动审批 │
│ │
└─────────────────────────────────────────────────────────────────┘
应用集管理
# root-app.yaml - 根应用(管理所有应用)
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/infra.git
path: apps
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
密钥管理
Sealed Secrets
# 安装 Sealed Secrets
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm install sealed-secrets sealed-secrets/sealed-secrets -n kube-system
# 加密 Secret
kubectl create secret generic db-credentials \
--dry-run=client \
-o yaml | \
kubeseal --cert pub-cert.pem --format yaml > sealed-secret.yaml
# 解密由集群自动完成
SOPS + Age
# 安装 age 和 SOPS
brew install age sops
# 生成密钥对
age-keygen -o key.txt
# 创建 .sops.yaml
cat > .sops.yaml << EOF
creation_rules:
- age: <public-key>
namespaces:
- production
- staging
path_regex: .*.yaml$
EOF
# 加密文件
sops --encrypt secret.yaml > secret.enc.yaml
# GitOps 仓库只存储加密文件
External Secrets Operator
# external-secrets.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: password
remoteRef:
key: secret/data/db
property: password
CI/CD 集成
GitHub Actions
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure kubectl
run: |
echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > kubeconfig
- name: Trigger ArgoCD Sync
uses: octo-cli/argocd@v1
with:
args: >
app sync myapp
--auth-token ${{ secrets.ARGOCD_TOKEN }}
--server ${{ secrets.ARGOCD_SERVER }}
Flux Image Updates
# image-policy.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: myapp
namespace: production
spec:
imageRepositoryRef:
name: myapp
policy:
semver:
range: ">=1.0.0"
# 或使用 alphabetical
# alphabetical:
# order: asc
---
# ImageRepository
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: myapp
namespace: production
spec:
image: myregistry/myapp
interval: 1m
source: dockerhub
自动镜像更新
# 启用 Image Update Automation
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageUpdateAutomation
metadata:
name: update-myapp
namespace: production
spec:
git:
checkout:
ref:
branch: main
commit:
author:
email: flux@example.com
name: flux
push:
branch: main
update:
strategy: Setters
path: ./deploy
sourceRef:
kind: GitRepository
name: myapp
最佳实践
仓库结构
.gitops/
├── apps/
│ ├── frontend/
│ │ ├── base/
│ │ │ ├── kustomization.yaml
│ │ │ └── templates/
│ │ └── overlays/
│ │ ├── staging/
│ │ └── production/
│ ├── backend/
│ └── worker/
├── infra/
│ ├── cert-manager/
│ ├── ingress-nginx/
│ ├── monitoring/
│ └── secrets/
└── clusters/
├── staging/
│ └── flux-system/
└── production/
└── flux-system/
团队协作
┌─────────────────────────────────────────────────────────────────┐
│ GitOps 协作模式 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 应用团队(App Teams) │
│ ├── 修改 apps/myapp/overlays/*/kustomization.yaml │
│ ├── 创建 Pull Request │
│ └── 审查后合并到 main │
│ │
│ 基础设施团队(Platform Team) │
│ ├── 管理 clusters/ 目录 │
│ ├── 配置 ArgoCD/Flux 全局设置 │
│ └── 审批敏感配置变更 │
│ │
│ 安全团队(Security Team) │
│ ├── 管理 secrets/ 目录 │
│ ├── 审计配置变更 │
│ └── 处理安全漏洞 │
│ │
└─────────────────────────────────────────────────────────────────┘
审查流程
# 强制代码审查
# .github/workflows/review.yml
name: Require Review
on:
pull_request:
branches: [main]
jobs:
require-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check approvals
run: |
count=$(gh pr view ${{ github.event.pull_request.number }} --json reviews --jq '.reviews | length')
if [ "$count" -lt 1 ]; then
echo "At least 1 approval required"
exit 1
fi
常见问题与避坑指南
Q1:同步失败?
# 排查步骤
# 1. 查看 ArgoCD 应用状态
argocd app get myapp
# 2. 查看同步差异
argocd app diff myapp
# 3. 查看日志
argocd app logs myapp
# 4. 强制同步
argocd app sync myapp --force
# Flux 日志
flux logs -n flux-system
kubectl logs -n flux-system -l app=source-controller
Q2:回滚问题?
# ArgoCD 回滚
argocd app rollback myapp
# 指定版本
argocd app sync myapp --revision v1.0.0
# Flux 回滚
# 修改 Git 中的版本即可,Flux 会自动同步
git revert <commit>
git push
Q3:多集群配置?
# ArgoCD 多集群
# 1. 注册集群到 ArgoCD
argocd cluster add staging --kubeconfig staging.kubeconfig
# 2. 应用部署到不同集群
spec:
destination:
server: https://staging.example.com
namespace: production
Q4:配置漂移?
# ArgoCD 自动修复
spec:
syncPolicy:
automated:
selfHeal: true # 自动修复漂移
# 查看漂移
argocd app get myapp --show-diffs
# 强制同步(覆盖集群状态)
argocd app sync myapp --force
总结
┌─────────────────────────────────────────────────────────────────┐
│ 核心要点回顾 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ GitOps 理念 │
│ ├── Git 是唯一事实来源 │
│ ├── 声明式配置 │
│ └── 拉取式部署 │
│ │
│ ArgoCD │
│ ├── Application CRD 定义应用 │
│ ├── Web UI 和 CLI │
│ ├── 多集群支持 │
│ └── 自动化同步和回滚 │
│ │
│ Flux │
│ ├── Source/Kustomization/Helm Controller │
│ ├── GitRepository 自动同步 │
│ └── Image Update Automation │
│ │
│ 多环境管理 │
│ ├── Kustomize overlays │
│ ├── 渐进式环境晋升 │
│ └── 权限隔离 │
│ │
│ 密钥管理 │
│ ├── Sealed Secrets │
│ ├── SOPS + Age │
│ └── External Secrets Operator │
│ │
└─────────────────────────────────────────────────────────────────┘
思考题
- GitOps 和传统 Push 方式的 CI/CD 相比,各自的适用场景是什么?
- 如何处理多租户场景下的权限隔离?
- 在 GitOps 模式下,如何保证敏感信息的安全?
引用与参考
下篇预告
下一篇文章我们将探讨 可观测性体系,包括:
- Prometheus + Grafana 监控
- 日志收集(ELK/Loki)
- 分布式追踪(Jaeger)
- AlertManager 告警
敬请期待!