6.7. 端到端交付实战:从提交到生产

前面每个章节各讲一个零件:CI、镜像、GitOps、Rollouts、SLO、回滚。这一章把它们装成一条完整的 Golden Path:一次 commit 如何经过构建、扫描、签名、GitOps 同步、金丝雀发布和 SLO 验证,最后安全地进入生产。

层级:

L4 · 实战

难度:

进阶

预计:

90 分钟

前置:

CI/CD、Helm/Kustomize、Argo CD、Prometheus

6.7.1. 目标链路

架构图

图:应用仓库负责「制品」,GitOps 仓库负责「期望状态」,Argo CD 负责「收敛」,Rollouts 负责「放量」。

6.7.2. 0. 实验环境

kind create cluster --name golden-path
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install kps prometheus-community/kube-prometheus-stack -n monitoring --create-namespace

需要 kubectl、helm、argocd、kubectl argo rollouts 插件。实验集群至少 4C/8G;没有 LoadBalancer 时用 port-forward 访问 Argo CD 和 Grafana。

6.7.3. 1. 应用仓库:构建一次

应用仓库包含代码、Dockerfile、测试和 CI。关键约束:

  • 镜像 tag 使用 commit SHA,禁止 latest。

  • CI 产出 digest、SBOM、漏洞报告、签名。

  • 生产部署只引用 digest。

.github/workflows/release.yaml
name: release
on:
  push:
    branches: [main]
jobs:
  release:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - name: Build and push
        run: |
          IMAGE=ghcr.io/example/demoapp:${{ github.sha }}
          docker build -t "$IMAGE" .
          echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
          docker push "$IMAGE"
          docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE" > digest.txt
      - name: Scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: ghcr.io/example/demoapp:${{ github.sha }}
          exit-code: "1"
          severity: CRITICAL,HIGH

真实流水线还应加入测试、SBOM、Cosign 签名和 GitOps 仓库更新。具体写法见 CI/CD 流水线 与 供应链安全。

6.7.4. 2. GitOps 仓库:只存期望状态

GitOps 仓库按环境分层:

apps/demoapp/
├── base/
│   ├── deployment.yaml
│   ├── service.yaml
│   └── kustomization.yaml
└── overlays/
    ├── dev/kustomization.yaml
    └── prod/kustomization.yaml

CI 最后一步用 yq 把 prod overlay 的 image 改成新 digest,然后提交:

yq -i '.images[0].newName = "ghcr.io/example/demoapp" | .images[0].digest = strenv(DIGEST)' \
  apps/demoapp/overlays/prod/kustomization.yaml
git commit -am "release demoapp ${GITHUB_SHA}"
git push

不要让 CI 直接 kubectl apply 生产;CI 只改 Git,集群由 Argo CD 收敛。

6.7.5. 3. Argo CD:同步与漂移

application-demoapp.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: demoapp-prod
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/example/gitops-demo.git
    targetRevision: main
    path: apps/demoapp/overlays/prod
  destination:
    server: https://kubernetes.default.svc
    namespace: demo
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

验收:Git 改副本数 → Argo CD 自动同步;手工改副本数 → selfHeal 纠正;删除 Git 中的资源 → prune 清理。

6.7.6. 4. 金丝雀:用指标决定放量

rollout-demoapp.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: demoapp
spec:
  replicas: 10
  selector:
    matchLabels:
      app: demoapp
  template:
    metadata:
      labels:
        app: demoapp
    spec:
      containers:
        - name: demoapp
          image: ghcr.io/example/demoapp@sha256:<digest>
          ports:
            - containerPort: 80
  strategy:
    canary:
      analysis:
        templates:
          - templateName: success-rate
      steps:
        - setWeight: 10
        - pause: {duration: 2m}
        - setWeight: 50
        - pause: {duration: 2m}
        - setWeight: 100
analysis-success-rate.yaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
spec:
  metrics:
    - name: success-rate
      interval: 1m
      successCondition: result[0] >= 0.99
      failureLimit: 1
      provider:
        prometheus:
          address: http://kps-kube-prometheus-stack-prometheus.monitoring:9090
          query: |
            sum(rate(http_requests_total{job="demoapp",code!~"5.."}[2m]))
            /
            sum(rate(http_requests_total{job="demoapp"}[2m]))
kubectl argo rollouts get rollout demoapp --watch
kubectl argo rollouts set image demoapp demoapp=ghcr.io/example/demoapp@sha256:<new-digest>
kubectl argo rollouts promote demoapp
kubectl argo rollouts abort demoapp

分析失败会自动 abort;没有指标分析的 canary 只是慢速全量发布。

6.7.7. 5. SLO 与回滚

给服务定义 SLO,例如「30 天成功率 ≥ 99.9%」。错误预算消耗过快时:

  1. 暂停自动发布(GitOps 仍可同步,但 Rollout 不 promote)。

  2. 回滚到上一个已知良好的 digest。

  3. 检查数据库迁移是否兼容;应用回滚不等于数据回滚。

  4. 记录事件时间线与改进项。

kubectl argo rollouts undo demoapp
kubectl get rollout demoapp -o jsonpath='{.status.currentPodHash}'

回滚后观察 30 分钟错误率、P95 延迟与饱和度,再决定是否重新发布。

6.7.8. 6. 复盘与 DORA

一次完整演练后记录:

  • 部署频率:本周发布次数。

  • 变更前置时间:commit 到生产的时间。

  • 变更失败率:回滚/事故比例。

  • 恢复时间:从告警到恢复的时长。

复盘至少写清:触发原因、检测方式、止血动作、根因、改进项与负责人。流程见 SRE 与事件响应。

6.7.9. 验证清单

  • 每个 commit 产出唯一 digest,生产只引用 digest。

  • 镜像经过测试、扫描、签名,SBOM 已归档。

  • CI 只更新 GitOps 仓库,不直接 apply 生产。

  • Argo CD 能自动同步、纠正漂移、prune 资源。

  • Rollout 按 10% → 50% → 100% 放量,分析失败自动 abort。

  • 回滚到旧 digest 后服务恢复,数据库兼容。

  • SLO/错误预算与发布门禁关联。

  • 复盘有改进项与截止时间。

6.7.10. 排错表

现象

原因

处理

CI 推送成功但 Argo 不同步

GitOps 仓库未更新/digest 错

检查 commit 与 overlay

Argo OutOfSync 不收敛

手工改动/CRD 未安装

开 selfHeal,调整 sync-wave

Rollout 卡在 pause

无 promote/分析失败

argo rollouts promote 或查 AnalysisRun

分析查询无数据

ServiceMonitor/标签不对

查 Prometheus targets 与 job 标签

回滚后仍报错

数据库 schema 不兼容

用 expand/contract,先兼容再回滚

发布后延迟升高

资源不足/连接池

看指标,调 resources/HPA

6.7.11. 进阶挑战

  1. 把 GitHub Actions 换成 GitLab CI 或 Tekton,保持同样的 digest 流程。

  2. 用 Flagger 替代 Argo Rollouts,比较两者的分析模型。

  3. 给 Rollout 加 feature flag,按租户灰度。

  4. 把 SLO 告警接到 Slack,并演练一次 error budget 冻结发布。

6.7.12. 小结

  • 端到端交付的核心是「制品不可变、状态在 Git、放量看指标、回滚有路径」。

  • CI 只负责构建与验证,GitOps 负责收敛,Rollouts 负责流量,SRE 负责风险。

  • 任何一段没有可观测指标,发布就会退回人工判断。

  • 先用一条 Golden Path 跑通,再谈平台化与多团队自助。

6.7.13. 延伸阅读