强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第 13 章:CI/CD 流水线

第 13 章:CI/CD 流水线

微服务的核心优势之一是独立部署。没有自动化的 CI/CD,这个优势就无法发挥。


13.1 微服务 CI/CD 的特殊性

13.1.1 单体 vs 微服务 CI/CD

  单体 CI/CD:
  ┌─────────────────────────────────────────────┐
  │              单体代码仓库                     │
  │                                             │
  │  代码变更 ──▶ 构建(慢) ──▶ 测试(全量) ──▶ 部署│
  │                                             │
  │  问题:                                     │
  │  • 一个功能变更,需要构建整个应用             │
  │  • 回归测试范围大                            │
  │  • 部署影响所有人                            │
  └─────────────────────────────────────────────┘

  微服务 CI/CD:
  ┌──────────┐ ┌──────────┐ ┌──────────┐
  │ 服务 A   │ │ 服务 B   │ │ 服务 C   │
  │ 独立仓库  │ │ 独立仓库  │ │ 独立仓库  │
  │ 独立流水线│ │ 独立流水线│ │ 独立流水线│
  │ 独立部署  │ │ 独立部署  │ │ 独立部署  │
  └──────────┘ └──────────┘ └──────────┘
  优势:
  • 只构建变更的服务
  • 只跑该服务的测试
  • 独立发布,不影响其他服务

13.1.2 微服务 CI/CD 基本要求

要求说明
每个服务独立流水线代码变更只触发对应服务的流水线
自动化一切构建、测试、部署全部自动化
容器化交付统一交付物:Docker 镜像
版本化管理语义化版本号(SemVer)
环境一致性Dev/Staging/Prod 环境一致
快速反馈流水线 < 15 分钟完成

13.2 CI/CD 流水线设计

13.2.1 标准流水线

┌──────────────────────────────────────────────────────────────────┐
│                   微服务 CI/CD 流水线                             │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│  CI 阶段 (Continuous Integration)                                │
│  ┌──────┐  ┌──────┐  ┌──────┐  ┌──────┐  ┌──────┐             │
│  │ 代码  │─▶│ 构建  │─▶│ 单元  │─▶│ 契约  │─▶│ 镜像  │             │
│  │ 提交  │  │ 编译  │  │ 测试  │  │ 测试  │  │ 构建  │             │
│  └──────┘  └──────┘  └──────┘  └──────┘  └──────┘             │
│  ~0s       ~30s       ~60s      ~30s       ~60s                │
│                                                                  │
│  CD 阶段 (Continuous Delivery/Deployment)                        │
│  ┌──────┐  ┌──────┐  ┌──────┐  ┌──────┐  ┌──────┐             │
│  │ 镜像  │─▶│ 部署  │─▶│ 集成  │─▶│ 部署  │─▶│ 部署  │             │
│  │ 推送  │  │ Dev   │  │ 测试  │  │ Staging│  │ Prod  │             │
│  └──────┘  └──────┘  └──────┘  └──────┘  └──────┘             │
│  ~20s      ~30s       ~120s     ~30s      ~60s(灰度)            │
│                                                                  │
│  总时间:< 10 分钟                                               │
└──────────────────────────────────────────────────────────────────┘

13.2.2 GitHub Actions 示例

# .github/workflows/order-service.yml
name: Order Service CI/CD

on:
  push:
    branches: [main]
    paths:
      - 'order-service/**'    # 只在该服务代码变更时触发
  pull_request:
    branches: [main]
    paths:
      - 'order-service/**'

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: order-service

jobs:
  # ========== CI 阶段 ==========
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK 21
        uses: actions/setup-java@v4
        with:
          java-version: '21'
          distribution: 'temurin'

      - name: Build and Test
        run: |
          cd order-service
          ./mvnw clean verify

      - name: Contract Tests
        run: |
          cd order-service
          ./mvnw pact:verify

      - name: Build Docker Image
        run: |
          cd order-service
          docker build -t $REGISTRY/$IMAGE_NAME:${{ github.sha }} .

      - name: Push Docker Image
        if: github.ref == 'refs/heads/main'
        run: |
          echo ${{ secrets.GITHUB_TOKEN }} | docker login $REGISTRY -u ${{ github.actor }} --password-stdin
          docker push $REGISTRY/$IMAGE_NAME:${{ github.sha }}
          docker tag $REGISTRY/$IMAGE_NAME:${{ github.sha }} $REGISTRY/$IMAGE_NAME:latest
          docker push $REGISTRY/$IMAGE_NAME:latest

  # ========== CD 阶段 ==========
  deploy-dev:
    needs: build-and-test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - name: Deploy to Dev
        run: |
          kubectl set image deployment/order-service \
            order-service=$REGISTRY/$IMAGE_NAME:${{ github.sha }} \
            -n dev

  integration-test:
    needs: deploy-dev
    runs-on: ubuntu-latest
    steps:
      - name: Run Integration Tests
        run: |
          cd order-service
          ./mvnw verify -Pintegration-test \
            -Dtest.base-url=http://dev.example.com

  deploy-staging:
    needs: integration-test
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to Staging
        run: |
          kubectl set image deployment/order-service \
            order-service=$REGISTRY/$IMAGE_NAME:${{ github.sha }} \
            -n staging

  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment: production    # 需要手动审批
    steps:
      - name: Deploy to Production (Canary)
        run: |
          # 金丝雀部署:先部署 10% 流量
          kubectl apply -f k8s/canary-deployment.yaml

13.3 部署策略

13.3.1 策略总览

策略停机时间风险资源需求回滚速度
滚动更新
蓝绿部署2 倍极快
金丝雀发布极低少量额外
A/B 测试少量额外
重建部署

13.3.2 滚动更新(Rolling Update)

  滚动更新过程(ReplicaSet = 4):

  时间 ──────────────────────────────────────▶

  Step 1: [v1] [v1] [v1] [v1]        (全部 v1)
  Step 2: [v1] [v1] [v1] [v2-new]    (启动 1 个 v2)
  Step 3: [v1] [v1] [v2] [v2-new]    (v2 就绪,终止 1 个 v1)
  Step 4: [v1] [v2] [v2] [v2-new]    (继续滚动)
  Step 5: [v2] [v2] [v2] [v2]        (全部 v2)

  K8s 配置:
  spec:
    strategy:
      type: RollingUpdate
      rollingUpdate:
        maxSurge: 1        # 最多多出 1 个 Pod
        maxUnavailable: 0   # 不允许不可用

13.3.3 蓝绿部署(Blue-Green Deployment)

  蓝绿部署:

  ┌─────────────────────────────────────────────────┐
  │                                                 │
  │  负载均衡器 / Ingress                            │
  │  ┌─────────────────────────────────┐            │
  │  │         路由规则                 │            │
  │  └──────────┬──────────────────────┘            │
  │             │                                   │
  │    ┌────────┴────────┐                          │
  │    ▼                 ▼                          │
  │ ┌──────────┐    ┌──────────┐                   │
  │ │  蓝环境   │    │  绿环境   │                   │
  │ │  (v1)    │    │  (v2)    │                   │
  │ │ [v1][v1] │    │ [v2][v2] │                   │
  │ │ [v1][v1] │    │ [v2][v2] │                   │
  │ └──────────┘    └──────────┘                   │
  │    当前活跃 ✅      待验证                       │
  │                                                 │
  │  切换流量(瞬间完成):                           │
  │  蓝 (v1) ──▶ 不活跃    绿 (v2) ──▶ 活跃 ✅     │
  │                                                 │
  │  回滚(瞬间完成):                               │
  │  蓝 (v1) ──▶ 活跃 ✅   绿 (v2) ──▶ 不活跃      │
  └─────────────────────────────────────────────────┘

13.3.4 金丝雀发布(Canary Deployment)

  金丝雀发布过程:

  阶段1:10% 流量到新版本
  ─────────────────────────────
  用户流量 ──▶ [Ingress]
                 ├── 90% ──▶ [v1] [v1] [v1] [v1] [v1]
                 └── 10% ──▶ [v2]

  阶段2:验证无异常,增加到 30%
  ─────────────────────────────
  用户流量 ──▶ [Ingress]
                 ├── 70% ──▶ [v1] [v1] [v1]
                 └── 30% ──▶ [v2] [v2]

  阶段3:验证无异常,增加到 100%
  ─────────────────────────────
  用户流量 ──▶ [Ingress]
                 └── 100% ──▶ [v2] [v2] [v2] [v2] [v2]

  自动回滚条件(任一触发):
  • 错误率 > 5%
  • P99 延迟 > 1s
  • 5xx 错误数突增

13.3.5 Argo Rollouts 金丝雀配置

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: order-service
spec:
  replicas: 5
  strategy:
    canary:
      steps:
        - setWeight: 10          # 10% 流量
        - pause: {duration: 5m}  # 观察 5 分钟
        - setWeight: 30          # 30% 流量
        - pause: {duration: 5m}  # 观察 5 分钟
        - setWeight: 60          # 60% 流量
        - pause: {duration: 5m}  # 观察 5 分钟
        - setWeight: 100         # 全量
      analysis:
        templates:
          - templateName: success-rate
        startingStep: 1
        args:
          - name: service-name
            value: order-service
---
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
spec:
  args:
    - name: service-name
  metrics:
    - name: success-rate
      interval: 1m
      successCondition: result[0] >= 0.99
      failureLimit: 3
      provider:
        prometheus:
          address: http://prometheus:9090
          query: |
            sum(rate(http_requests_total{service="{{args.service-name}}",status=~"2.."}[5m]))
            /
            sum(rate(http_requests_total{service="{{args.service-name}}"}[5m]))

13.4 GitOps

13.4.1 GitOps 原则

┌──────────────────────────────────────────────────────────────┐
│                    GitOps 工作流                              │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  开发者                    Git 仓库               K8s 集群    │
│  ┌──────┐                ┌──────────┐           ┌─────────┐ │
│  │      │  push code     │          │  同步     │         │ │
│  │ 代码  │───────────────▶│ 应用代码  │          │         │ │
│  │ 变更  │                │          │          │         │ │
│  └──────┘                └────┬─────┘          │         │ │
│                               │ CI             │         │ │
│                               ▼                │         │ │
│                         ┌──────────┐          │         │ │
│                         │ 构建镜像  │          │         │ │
│                         │ 更新配置  │          │         │ │
│                         └────┬─────┘          │         │ │
│                              │                │         │ │
│                              ▼                │         │ │
│                         ┌──────────┐          │         │ │
│                         │ 配置仓库  │◄─────────│ ArgoCD  │ │
│                         │ (K8s YAML)│  监听    │         │ │
│                         │          │─────────▶│ 部署    │ │
│                         └──────────┘          └─────────┘ │
│                                                              │
│  核心原则:                                                  │
│  1. Git 是唯一事实来源                                        │
│  2. 声明式配置(K8s YAML / Helm)                            │
│  3. 自动同步(ArgoCD / Flux 监听变更)                        │
│  4. 可审计(Git 提交历史就是变更历史)                         │
│  5. 可回滚(Git revert 就是回滚)                             │
└──────────────────────────────────────────────────────────────┘

13.4.2 ArgoCD 配置

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: order-service
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/k8s-configs.git
    targetRevision: HEAD
    path: production/order-service
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true       # 自动删除不存在的资源
      selfHeal: true    # 自动修复手动修改
    syncOptions:
      - CreateNamespace=true

13.5 多仓库管理

13.5.1 单仓库 vs 多仓库

维度单仓库 (Monorepo)多仓库 (Polyrepo)
代码共享容易需要包管理
CI 配置需要路径过滤独立流水线
权限控制粗粒度细粒度
依赖管理简单需要版本管理
推荐场景初期/小团队成熟/大团队

13.5.2 多仓库的版本管理

  服务间版本兼容性矩阵:

  订单服务版本     商品服务版本    是否兼容
  ─────────────   ─────────────  ────────
  v2.1.0          v3.2.0         ✅
  v2.1.0          v3.3.0         ✅
  v2.1.0          v4.0.0         ❌ (API 不兼容)
  v2.2.0          v3.2.0         ✅

  管理方式:
  1. 契约测试保证兼容性
  2. API 版本号管理(v1/v2 共存)
  3. 语义化版本号(SemVer)

13.6 业务场景:电商 CI/CD 全景

  ┌──────────────────────────────────────────────────────────────┐
  │              电商 CI/CD 全景架构                              │
  ├──────────────────────────────────────────────────────────────┤
  │                                                              │
  │  代码层                                                       │
  │  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐       │
  │  │用户服务  │ │订单服务  │ │商品服务  │ │支付服务  │       │
  │  │ Git Repo │ │ Git Repo │ │ Git Repo │ │ Git Repo │       │
  │  └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘       │
  │       └─────────────┼─────────────┼─────────────┘            │
  │                     ▼                                        │
  │  CI 层                                                        │
  │  ┌──────────────────────────────────────────────────────┐   │
  │  │  GitHub Actions / GitLab CI                          │   │
  │  │  • 构建 → 测试 → 镜像 → 推送                         │   │
  │  │  • 每个服务独立流水线                                 │   │
  │  └───────────────────────┬──────────────────────────────┘   │
  │                          ▼                                   │
  │  CD 层                                                        │
  │  ┌──────────────────────────────────────────────────────┐   │
  │  │  ArgoCD (GitOps)                                     │   │
  │  │  • 监听配置仓库变更                                   │   │
  │  │  • 自动同步到 K8s                                     │   │
  │  │  • 支持蓝绿/金丝雀                                    │   │
  │  └───────────────────────┬──────────────────────────────┘   │
  │                          ▼                                   │
  │  运行层                                                        │
  │  ┌──────────────────────────────────────────────────────┐   │
  │  │  Kubernetes 集群                                     │   │
  │  │  • Dev → Staging → Production                       │   │
  │  │  • Argo Rollouts (金丝雀)                            │   │
  │  │  • Prometheus + Grafana (监控)                       │   │
  │  └──────────────────────────────────────────────────────┘   │
  └──────────────────────────────────────────────────────────────┘

⚠️ 注意事项

  1. 流水线速度——CI 流水线超过 15 分钟会严重影响开发效率
  2. 数据库迁移——Schema 变更需要与代码部署协调
  3. 配置管理——敏感信息使用 Secret 管理,不要提交到 Git
  4. 回滚策略——每次部署都要有回滚方案
  5. 环境一致性——Dev/Staging/Prod 使用相同的 K8s 配置

📖 扩展阅读

  1. ArgoCD Documentation (argoproj.github.io) — GitOps 持续部署
  2. Argo Rollouts — 渐进式交付
  3. Flux CD — CNCF GitOps 工具
  4. GitHub Actions Documentation — CI/CD 自动化
  5. Continuous Delivery — Jez Humble — 持续交付经典著作

本章小结

部署策略停机风险适用场景
滚动更新常规更新
蓝绿部署需要快速回滚
金丝雀发布极低高风险变更
GitOps配置管理最佳实践

📌 下一章第 14 章:安全架构 — 零信任、mTLS、JWT、OAuth2。