ithuang
ithuang
发布于 2026-06-12 / 6 阅读
0

CI/CD的部署实现

CI/CD(Continuous Integration / Continuous Delivery / Continuous Deployment) 不是单一工具,而是一套从代码变更到生产运行的自动化工程体系。它由多个阶段、多种工具、多层策略组合而成,核心目标是:在保障质量的前提下,缩短从"代码提交"到"用户可用"的周期。

下面从理论模型、流水线阶段、工具实现、K8s 集成、高级策略五个维度系统拆解。


一、CI/CD 的三层模型

业界通常将 CI/CD 划分为三个递进的层次,理解它们的边界至关重要:

层次全称自动化范围人工干预点目标
CIContinuous Integration代码提交 → 构建 → 测试无(自动触发)快速发现集成错误
CDeliveryContinuous DeliveryCI 产物 → 打包 → 部署到预发布/生产(具备发布能力)发布到生产需人工审批随时可发布,发布决策权在人
CDeploymentContinuous DeploymentCDelivery 基础上,自动发布到生产无(完全自动)变更即时上线,依赖自动化测试与监控

关键差异: Continuous Delivery 与 Continuous Deployment 的唯一区别是"生产部署是否自动"。


二、CI/CD 流水线的核心阶段

一个完整的 CI/CD 流水线通常包含 8 个阶段:

┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────┐
│  Source │ → │  Build  │ → │  Test   │ → │  Security│ → │ Package │ → │  Deploy │ → │ Verify  │ → │ Monitor │
│  代码触发│   │  编译构建│   │  测试   │   │  安全扫描│   │  制品打包│   │  部署   │   │  验证   │   │  监控   │
└─────────┘   └─────────┘   └─────────┘   └─────────┘   └─────────┘   └─────────┘   └─────────┘   └─────────┘
     │              │              │              │              │              │              │              │
   Git Push    Maven/Gradle    Unit Test     SAST/DAST     Docker Build   Helm Upgrade   Smoke Test     Prometheus
   Webhook     npm/Go          Integration   Dependency    Image Push     K8s Apply      E2E Test       Alert
               镜像构建        Test          Scan          Sign/Scan      ArgoCD Sync    Chaos Test     Rollback

阶段 1:Source(代码触发)

触发源:

  • 代码提交:git push 到 main / develop 分支
  • Merge Request:代码审查通过后自动触发
  • 定时触发: nightly build(每日构建)
  • 上游触发:A 服务构建成功后触发 B 服务构建

关键实践:

# GitLab CI 触发配置
stages:
  - build
  - test

build-job:
  stage: build
  # 只有 main 分支和 tag 才触发构建
  only:
    - main
    - tags
  # 排除文档修改触发构建
  except:
    changes:
      - "*.md"
      - "docs/**/*"

阶段 2:Build(编译构建)

目标:将源代码转换为可运行产物。

典型任务:

  • 编译 Java(Maven/Gradle)、Go(go build)、前端(npm run build)
  • 生成代码(Protobuf、OpenAPI Generator)
  • 静态代码分析(SonarQube)

与 K8s 的衔接:

# ============================================
# Dockerfile:多阶段构建,减小最终镜像体积
# ============================================
# 阶段 1:构建阶段(使用完整 JDK + Maven)
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /app
# 先复制 pom.xml 下载依赖(利用 Docker 缓存层)
COPY pom.xml .
RUN mvn dependency:go-offline
# 再复制源码编译
COPY src ./src
RUN mvn clean package -DskipTests

# 阶段 2:运行阶段(仅使用 JRE,无构建工具)
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
# 从构建阶段复制产物
COPY --from=builder /app/target/order-service-*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

阶段 3:Test(测试)

测试金字塔模型:

      /\
     /  \     E2E 测试(少而精,验证完整链路)
    /____\        ↑ 慢、贵、脆弱
   /      \   集成测试(服务间交互)
  /________\      ↑ 中等速度
 /          \  单元测试(多而快,覆盖核心业务逻辑)
/____________\    ↓ 快、便宜、稳定

流水线中的测试策略:

测试类型工具示例触发时机失败处理
单元测试JUnit、pytest、JestBuild 后阻断流水线
集成测试TestContainers、Spring Boot Test容器启动后阻断流水线
契约测试Pact、Spring Cloud Contract服务间 API 变更时阻断流水线
E2E 测试Cypress、Selenium、Playwright部署到预发布环境后阻断生产发布
性能测试JMeter、k6、Gatling夜间定时或发布前人工判断是否发布

K8s 集成测试示例:

# GitLab CI 中使用 TestContainers 进行集成测试
integration-test:
  stage: test
  image: maven:3.9-eclipse-temurin-17
  services:
    - name: docker:24-dind
      alias: docker
  variables:
    DOCKER_HOST: tcp://docker:2376
  script:
    - mvn test -P integration-test
    # TestContainers 会自动在 DinD 中启动 MySQL/Redis 容器进行测试

阶段 4:Security(安全扫描)

DevSecOps 理念:安全左移(Shift Left),在开发早期发现漏洞。

扫描类型工具作用阶段
SASTSonarQube、Checkmarx、Semgrep静态代码分析,发现 SQL 注入、XSS 等Build 后
DASTOWASP ZAP、Burp Suite动态应用测试,模拟攻击运行中的应用部署后
SCASnyk、Trivy、Dependency-Check依赖组件漏洞扫描(Log4j 等)Build 后
Container ScanTrivy、Clair、Snyk容器镜像 OS 漏洞和软件包漏洞Package 后
Secret ScanGitLeaks、TruffleHog检测代码中硬编码的密码、TokenSource 阶段

Trivy 镜像扫描集成:

container-scan:
  stage: security
  image: aquasec/trivy:latest
  script:
    # 扫描 Harbor 中的镜像
    - trivy image --severity HIGH,CRITICAL \
        --exit-code 1 \
        harbor.company.com/ecommerce/order-service:$CI_COMMIT_SHA
  # 发现 HIGH/CRITICAL 漏洞时阻断流水线
  allow_failure: false

阶段 5:Package(制品打包)

目标:将构建产物打包为可部署的制品。

制品类型:

  • Docker 镜像:推送到 Harbor / Docker Hub / ECR
  • Helm Chart:打包为 .tgz,推送到 Harbor OCI / ChartMuseum
  • 二进制包:JAR、WAR、静态文件(存放到 S3 / Nexus / Artifactory)

版本管理策略:

# 语义化版本 + Git 元信息
IMAGE_TAG="${VERSION}-${GIT_COMMIT_SHORT_SHA}-${BUILD_NUMBER}"
# 示例:v2.1.0-a1b2c3d-156

# 多环境标签策略
docker tag order-service:v2.1.0-a1b2c3d harbor.company.com/ecommerce/order-service:staging
docker tag order-service:v2.1.0-a1b2c3d harbor.company.com/ecommerce/order-service:prod

阶段 6:Deploy(部署)

这是 CI/CD 与 K8s 结合最紧密的阶段,分为**推送式(Push)和拉取式(Pull)**两种模型。

模型 A:Push 式部署(传统 CI/CD)

CI 工具直接调用 K8s API 或 Helm 进行部署:

# GitLab CI / Jenkins 中执行
deploy-staging:
  stage: deploy
  image: alpine/helm:latest
  script:
    - helm upgrade --install ecommerce-staging ./ecommerce-chart \
        -n ecommerce-staging \
        --set global.imageRegistry=harbor.company.com \
        --set orderService.image.tag=$CI_COMMIT_SHA \
        --set userService.image.tag=$CI_COMMIT_SHA \
        --wait --timeout 10m
  environment:
    name: staging
    url: https://api-staging.ecommerce.com

缺点:

  • CI 工具需要 K8s 集群的 高权限凭据(kubeconfig),安全风险大
  • CI 工具成为部署的单一故障点
  • 难以实现回滚审计和漂移检测

模型 B:Pull 式部署(GitOps,现代推荐)

CI 只负责构建镜像并更新 Git 仓库中的配置;由 GitOps 控制器(如 ArgoCD、Flux)自动同步到 K8s。

开发者 push 代码
    ↓
CI 构建镜像 → 推送到 Harbor
    ↓
CI 修改 Git 配置仓库(image tag: v2.1.0)
    ↓
ArgoCD 检测到 Git 变更
    ↓
ArgoCD 自动 apply 到 K8s
    ↓
ArgoCD 持续监控 Git 与 K8s 状态一致性

ArgoCD Application 定义:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: ecommerce
  namespace: argocd
spec:
  # 源:Git 仓库中的 Helm Chart
  source:
    repoURL: https://gitlab.company.com/ecommerce/helm-charts.git
    targetRevision: HEAD
    path: ecommerce-chart
    helm:
      valueFiles:
        - values-prod.yaml
  # 目标集群
  destination:
    server: https://kubernetes.default.svc
    namespace: ecommerce
  # 同步策略:自动同步 + 自动修复漂移
  syncPolicy:
    automated:
      prune: true        # 删除 Git 中不存在的资源
      selfHeal: true     # 自动修复手动修改导致的漂移
    syncOptions:
      - CreateNamespace=true

GitOps 的优势:

  • 单一事实源(Single Source of Truth):Git 仓库定义了期望状态
  • 安全隔离:CI 不需要 K8s 写权限,ArgoCD 在集群内运行
  • 完整审计:所有变更通过 Git 提交记录可追溯
  • 回滚即 Revert:git revert 后 ArgoCD 自动回滚

阶段 7:Verify(验证)

部署后必须验证应用健康,否则可能引入"静默故障"。

验证类型工具/方法作用
Smoke Testcurl / HTTP 探针验证核心接口返回 200
Health CheckK8s Readiness/Liveness Probe验证 Pod 就绪
Synthetic MonitoringPrometheus Blackbox Exporter模拟用户请求验证链路
Chaos EngineeringChaos Mesh、Litmus注入故障验证系统韧性
A/B 测试验证Flagger、Argo Rollouts对比新旧版本业务指标

Jenkins 中集成 Smoke Test:

stage('Smoke Test') {
    steps {
        script {
            // 等待服务就绪
            sleep 30
            // 验证订单创建接口
            def response = sh(
                script: "curl -s -o /dev/null -w '%{http_code}' \
                         -X POST https://api.ecommerce.com/api/order/health",
                returnStdout: true
            ).trim()
            if (response != "200") {
                error("Smoke test failed with status ${response}")
            }
        }
    }
}

阶段 8:Monitor & Feedback(监控与反馈)

部署不是终点,而是持续验证的起点。

关键反馈回路:

Prometheus 采集指标
    ↓
Grafana 展示错误率 / 延迟 / 吞吐量
    ↓
错误率超过阈值 → Alertmanager 触发告警
    ↓
PagerDuty / 钉钉通知运维
    ↓
人工判断或自动触发 ArgoCD Rollback(Git Revert)
    ↓
Jenkins / GitLab CI 记录此次发布为失败
    ↓
DORA 度量平台统计部署失败率

三、两种主流 CI/CD 架构实现

架构 A:GitLab CI + K8s(一体化)

GitLab Server(代码 + CI 调度)
    │
    ├── GitLab Runner(K8s Executor)
    │       └── 每个 Job 启动一个 K8s Pod
    │           ├── build-pod(Maven 编译)
    │           ├── test-pod(运行测试)
    │           └── deploy-pod(Helm 部署)
    │
    └── GitLab Container Registry(镜像仓库)
            └── 镜像推送到 Harbor

GitLab Runner 配置(K8s Executor):

# config.toml
[[runners]]
  name = "k8s-runner"
  url = "https://gitlab.company.com"
  token = "TOKEN"
  executor = "kubernetes"
  [runners.kubernetes]
    namespace = "gitlab-runner"
    image = "ubuntu:22.04"
    # 使用特权容器运行 Docker in Docker
    privileged = true
    # 资源限制
    [runners.kubernetes.resources]
      [runners.kubernetes.resources.requests]
        cpu = "500m"
        memory = "512Mi"
      [runners.kubernetes.resources.limits]
        cpu = "2000m"
        memory = "2Gi"

架构 B:Jenkins + K8s(可编程编排)

Jenkins Master(调度中心)
    │
    ├── Jenkins Agent(K8s Pod Template)
    │       └── JNLP 连接后执行 Pipeline
    │           ├── 容器 maven:编译
    │           ├── 容器 docker:构建镜像
    │           └── 容器 helm:部署
    │
    └── Harbor(镜像仓库)

Jenkins Kubernetes Plugin 配置:

// Jenkinsfile 中声明 Pod 模板
podTemplate(
    yaml: '''
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: maven
    image: maven:3.9-eclipse-temurin-17
    command: ['cat']
    tty: true
  - name: docker
    image: docker:24-dind
    securityContext:
      privileged: true
  - name: helm
    image: alpine/helm:latest
    command: ['cat']
    tty: true
''',
    // 工作空间卷:多个容器共享构建产物
    volumes: [
        emptyDirVolume(mountPath: '/workspace', memory: false)
    ]
) {
    node(POD_LABEL) {
        stage('Build') {
            container('maven') {
                sh 'mvn clean package'
            }
        }
        stage('Docker Build') {
            container('docker') {
                sh 'docker build -t order-service:v1.0 .'
            }
        }
        stage('Deploy') {
            container('helm') {
                sh 'helm upgrade --install ecommerce ./chart'
            }
        }
    }
}

四、高级部署策略(CD 核心)

1. 蓝绿部署(Blue-Green Deployment)

原理:同时维护两套生产环境(Blue 当前、Green 新版本),切换流量。

Ingress / Service
    │
    ├──► Blue(当前 v1.0,3 个 Pod)← 100% 流量
    │
    └──► Green(新版本 v2.0,3 个 Pod)← 0% 流量
    
验证 Green 健康后,Ingress 切换 100% 流量到 Green
保留 Blue 一段时间,确认无问题后删除

Helm 实现:

# values.yaml
blueGreen:
  enabled: true
  active: blue    # 当前活跃版本

# 通过 Helm 切换
helm upgrade ecommerce ./chart --set blueGreen.active=green

2. 金丝雀发布(Canary Release)

原理:新版本只接收少量真实流量,逐步扩大比例,观察指标。

v1.0(95% 流量)          v2.0(5% 流量)
┌─────────┐              ┌─────────┐
│ Pod x 3 │              │ Pod x 1 │
└─────────┘              └─────────┘
    ▲                        ▲
    └──────────┬─────────────┘
               │
          Ingress 权重路由
          
观察 10 分钟:错误率 < 0.1%,延迟 < 100ms
→ 扩大 v2.0 到 50% → 100% → 删除 v1.0

Argo Rollouts 实现:

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: order-service
spec:
  replicas: 5
  strategy:
    canary:
      steps:
        - setWeight: 10      # 10% 流量给新版本
        - pause: {duration: 10m}  # 观察 10 分钟
        - setWeight: 50      # 50% 流量
        - pause: {duration: 10m}
        - setWeight: 100     # 100% 流量
      analysis:
        templates:
          - templateName: success-rate
        args:
          - name: service-name
            value: order-service

3. 灰度发布(Feature Flag)

原理:代码已部署到生产,但功能通过开关控制,仅对特定用户开放。

// Java 代码中使用 Feature Flag
if (featureFlags.isEnabled("seckill-v2", userId)) {
    // 新秒杀逻辑
    return seckillServiceV2.createOrder(request);
} else {
    // 旧逻辑
    return seckillService.createOrder(request);
}

优势:发布与上线解耦,出现问题无需回滚代码,只需关闭开关。


五、度量:DORA 指标

Google DevOps 研究与评估(DORA)团队提出的四个核心指标,用于衡量 CI/CD 成熟度:

指标定义精英团队表现度量方式
部署频率单位时间内生产部署次数按需部署,每日多次GitLab/Jenkins 部署日志
变更前置时间从代码提交到生产运行的时间< 1 小时CI Pipeline 持续时间
恢复服务时间生产故障发生后恢复的时间< 1 小时监控告警到修复的时长
变更失败率导致故障或需要回滚的部署占比< 5%失败部署数 / 总部署数

六、完整电商 CI/CD 流水线示例

# ============================================
# .gitlab-ci.yml:电商微服务完整 CI/CD
# ============================================
variables:
  DOCKER_REGISTRY: "harbor.company.com"
  KUBE_NAMESPACE: "ecommerce"

stages:
  - build
  - test
  - security
  - package
  - deploy-staging
  - verify-staging
  - deploy-production

# ============================================
# 1. 构建
# ============================================
build:
  stage: build
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn -B clean package -DskipTests
  artifacts:
    paths:
      - target/*.jar
    expire_in: 1 hour

# ============================================
# 2. 测试
# ============================================
unit-test:
  stage: test
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn test
  coverage: '/Total.*?(\d+\%)/'

integration-test:
  stage: test
  image: maven:3.9-eclipse-temurin-17
  services:
    - docker:24-dind
  variables:
    DOCKER_HOST: tcp://docker:2376
  script:
    - mvn test -P integration-test

# ============================================
# 3. 安全扫描
# ============================================
sast:
  stage: security
  image: returntocorp/semgrep:latest
  script:
    - semgrep --config=auto --error --json .
  artifacts:
    reports:
      sast: gl-sast-report.json

container-scan:
  stage: security
  image: aquasec/trivy:latest
  script:
    - trivy image --severity HIGH,CRITICAL --exit-code 1 \
        $DOCKER_REGISTRY/ecommerce/order-service:$CI_COMMIT_SHA

# ============================================
# 4. 打包镜像
# ============================================
docker-build:
  stage: package
  image: docker:24-dind
  services:
    - docker:24-dind
  script:
    - docker build -t $DOCKER_REGISTRY/ecommerce/order-service:$CI_COMMIT_SHA .
    - docker push $DOCKER_REGISTRY/ecommerce/order-service:$CI_COMMIT_SHA

# ============================================
# 5. 部署到预发布环境
# ============================================
deploy-staging:
  stage: deploy-staging
  image: alpine/helm:latest
  script:
    - helm upgrade --install ecommerce-staging ./chart
        --namespace $KUBE_NAMESPACE-staging
        --set orderService.image.tag=$CI_COMMIT_SHA
        --wait
  environment:
    name: staging
    url: https://api-staging.ecommerce.com

# ============================================
# 6. 预发布环境验证
# ============================================
smoke-test:
  stage: verify-staging
  image: curlimages/curl:latest
  script:
    - curl -f https://api-staging.ecommerce.com/api/order/health
    - curl -f https://api-staging.ecommerce.com/api/product/health

# ============================================
# 7. 部署到生产(需人工审批)
# ============================================
deploy-production:
  stage: deploy-production
  image: alpine/helm:latest
  script:
    - helm upgrade --install ecommerce ./chart
        --namespace $KUBE_NAMESPACE
        --set orderService.image.tag=$CI_COMMIT_SHA
        --wait
  environment:
    name: production
    url: https://api.ecommerce.com
  when: manual          # 手动触发
  only:
    - main              # 只有 main 分支可部署生产

七、总结

维度核心要点
CI代码提交 → 自动构建 → 自动测试,目标是快速反馈集成错误
CDeliveryCI 产物 → 自动打包 → 自动部署到类生产环境,具备随时发布能力
CDeployment自动发布到生产,完全无人干预,依赖强大的测试与监控
Push 部署CI 工具直接调用 Helm/kubectl,简单但安全风险高
Pull 部署(GitOps)CI 只更新 Git,ArgoCD 自动同步,推荐生产使用
高级策略蓝绿(快速切换)、金丝雀(渐进放量)、Feature Flag(代码与发布解耦)
度量DORA 四指标:部署频率、前置时间、恢复时间、失败率

CI/CD 不是"一个工具",而是一套"从代码到用户的自动化工程体系"。它的终极形态是:开发者提交代码后,系统自动完成测试、打包、部署、验证,并在出现问题时自动回滚——人只负责写代码和业务决策。