【CI/CD·入门篇】CI vs CD vs Continuous Deployment:三个层次的区别与联系

前言

很多人把 CI/CD 当成一个词来用,但实际上它是三个递进的层次。理解这三个层次的边界,决定了你团队自动化的成熟度。本篇用三个实际的流水线配置,让你直观感受从 CI 到 CD 到 Continuous Deployment 的演进。


一、三个层次的关系:一个递进模型

复制代码
Level 1: Continuous Integration(持续集成)
         代码合并 → 自动构建 → 自动测试 → 反馈结果
         产出:可运行的构建产物

Level 2: Continuous Delivery(持续交付)
         CI + 自动部署到类生产环境 + 随时可发布状态
         产出:随时可以点击发布的系统

Level 3: Continuous Deployment(持续部署)
         CD + 自动发布到生产环境(无人工干预)
         产出:每次通过测试的代码自动上线

三者是包含关系:

复制代码
┌─────────────────────────────────────────┐
│        Continuous Deployment            │
│  ┌───────────────────────────────────┐  │
│  │      Continuous Delivery         │  │
│  │  ┌─────────────────────────────┐ │  │
│  │  │  Continuous Integration     │ │  │
│  │  │  代码 → 构建 → 测试 → 反馈   │ │  │
│  │  └─────────────────────────────┘ │  │
│  │  + 部署到预发/测试环境            │  │
│  │  + 保持随时可发布状态             │  │
│  └───────────────────────────────────┘  │
│  + 自动部署到生产环境                   │
└─────────────────────────────────────────┘

二、Level 1:持续集成(CI)长什么样

目标

每次代码提交后自动构建和测试,快速发现问题。这个阶段不涉及任何部署。

流水线配置(GitLab CI 示例)

复制代码
# .gitlab-ci.yml --- 仅 CI 阶段
stages:
  - build
  - test
  - scan

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"

# 构建阶段
build:
  stage: build
  image: maven:3.9-eclipse-temurin-17
  cache:
    key: maven-${CI_COMMIT_REF_SLUG}
    paths:
      - .m2/repository
  script:
    - mvn clean compile -DskipTests
  artifacts:
    paths:
      - target/
    expire_in: 1 hour
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

# 单元测试阶段
unit-test:
  stage: test
  image: maven:3.9-eclipse-temurin-17
  needs: [build]
  script:
    - mvn test
  artifacts:
    reports:
      junit: target/surefire-reports/TEST-*.xml
    paths:
      - target/site/jacoco/
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

# 代码质量扫描
code-scan:
  stage: scan
  image: sonarsource/sonar-scanner-cli:latest
  needs: [unit-test]
  script:
    - sonar-scanner
      -Dsonar.projectKey=myapp
      -Dsonar.sources=src
      -Dsonar.host.url=$SONAR_HOST
      -Dsonar.login=$SONAR_TOKEN
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

这条流水线做到了什么

  1. PR 或 main 分支提交时自动触发

  2. 编译代码------有编译错误立即失败

  3. 跑单元测试------测试不过立即失败

  4. 代码质量扫描------输出质量报告

  5. 没有部署任何东西到任何环境

**培训要点**:很多团队以为用了 Jenkins 就是"做 CI/CD"了,实际上如果流水线只做到编译+测试,连产物都没有固化,那只是 CI 的第一步。


三、Level 2:持续交付(CD)多了什么

目标

在 CI 基础上,把构建产物打包成可部署的格式(Docker 镜像),自动部署到测试和预发环境,保持系统处于"随时可发布"状态。但生产环境的发布需要人工触发。

流水线配置(增加部署阶段)

复制代码
# .gitlab-ci.yml --- CI + CD(持续交付)
stages:
  - build
  - test
  - scan
  - package        # 新增:打包镜像
  - deploy-test    # 新增:部署测试环境
  - deploy-staging # 新增:部署预发环境
  - release        # 新增:准备发布(人工审批后触发)

# ... build / test / scan 同上 ...

# 打包 Docker 镜像
package:
  stage: package
  image: docker:24
  needs: [unit-test]
  services:
    - docker:24-dind
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

# 部署到测试环境
deploy-test:
  stage: deploy-test
  image: bitnami/kubectl:latest
  needs: [package]
  environment:
    name: test
    url: https://test.myapp.com
  script:
    - kubectl set image deployment/myapp app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA -n test
    - kubectl rollout status deployment/myapp -n test --timeout=180s
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

# 部署到预发环境(需要手动触发)
deploy-staging:
  stage: deploy-staging
  image: bitnami/kubectl:latest
  needs: [deploy-test]
  environment:
    name: staging
    url: https://staging.myapp.com
  when: manual  # ← 关键:手动触发
  script:
    - kubectl set image deployment/myapp app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA -n staging
    - kubectl rollout status deployment/myapp -n staging --timeout=180s
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

# 准备生产发布(需要人工审批)
release:
  stage: release
  when: manual  # ← 人工审批后才执行
  script:
    - echo "Release $CI_COMMIT_SHORT_SHA is ready for production"
    - kubectl label deployment/myapp -n staging release-candidate=$CI_COMMIT_SHORT_SHA
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

关键区别

| 特征 | CI | CD(持续交付) |

|------|-----|---------------|

| 自动构建 | 是 | 是 |

| 自动测试 | 是 | 是 |

| 构建产物固化 | 否 | 是(Docker镜像) |

| 自动部署测试环境 | 否 | 是 |

| 自动部署预发环境 | 否 | 是(可设手动触发) |

| 生产部署 | 否 | 否,需人工触发 |

| 系统状态 | 知道代码能编译 | 随时可发布 |

**踩坑提示**:`when: manual` 是持续交付的关键------它保证生产部署永远需要人确认。如果漏了这个配置,你的"持续交付"就变成了"持续部署"------测试没通过就上线了。


四、Level 3:持续部署(Continuous Deployment)的终极形态

目标

去掉所有人工审批环节,通过测试的代码自动部署到生产环境。这需要极高的测试覆盖率和完善的监控告警支撑。

流水线配置(移除手动触发)

复制代码
# .gitlab-ci.yml --- CI + CD + Continuous Deployment
stages:
  - build
  - test
  - scan
  - package
  - deploy-test
  - deploy-staging
  - deploy-prod      # 新增:自动部署生产环境

# ... 前面阶段同上 ...

# 部署到预发环境(自动)
deploy-staging:
  stage: deploy-staging
  image: bitnami/kubectl:latest
  needs: [deploy-test]
  environment:
    name: staging
  script:
    - kubectl set image deployment/myapp app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA -n staging
    - kubectl rollout status deployment/myapp -n staging --timeout=180s
    # 在预发环境跑冒烟测试
    - |
      for i in $(seq 1 30); do
        STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://staging.myapp.com/health)
        if [ "$STATUS" = "200" ]; then break; fi
        sleep 5
      done
      if [ "$STATUS" != "200" ]; then exit 1; fi
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

# 自动部署到生产环境(金丝雀模式)
deploy-prod-canary:
  stage: deploy-prod
  image: bitnami/kubectl:latest
  needs: [deploy-staging]
  environment:
    name: production
  script:
    # 第一步:金丝雀部署------只更新1个Pod
    - kubectl set image deployment/myapp app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA -n production
    - |
      # 等待金丝雀Pod健康
      kubectl rollout status deployment/myapp -n production --timeout=300s
      # 观察5分钟,检查错误率
      sleep 300
      ERROR_RATE=$(curl -s http://monitoring:9090/api/v1/query \
        -d "query=rate(http_requests_total{status=~\"5..\",namespace=\"production\"}[5m])" \
        | jq -r '.data.result[0].value[1]')
      if [ $(awk "BEGIN {print ($ERROR_RATE > 0.01)}") -eq 1 ]; then
        echo "Error rate too high, rolling back"
        kubectl rollout undo deployment/myapp -n production
        exit 1
      fi
    # 第二步:全量更新
    - kubectl scale deployment/myapp --replicas=10 -n production
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

持续部署的前提条件

  1. 测试覆盖率 > 80%:没有充分的自动化测试,自动部署等于自杀

  2. 完善的监控告警:部署后能自动检测异常并自动回滚

  3. 金丝雀/蓝绿部署能力:降低自动部署的风险

  4. 数据库变更零停机:使用扩展-收缩模式

  5. 功能开关(Feature Flags):新功能可以先上线再开启

自动回滚配置示例

复制代码
# 监控驱动的自动回滚(Prometheus + ArgoCD)
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: myapp
spec:
  strategy:
    canary:
      steps:
      - setWeight: 10          # 10%流量到新版本
      - pause: { duration: 5m } # 观察5分钟
      analysis:                 # 自动分析指标
        templates:
        - templateName: success-rate
        args:
        - name: service-name
          value: myapp
      - setWeight: 50          # 通过后增加到50%
      - pause: { duration: 5m }
      - setWeight: 100          # 全量上线

五、你的团队在哪个层次

| 信号 | CI | CD | Continuous Deployment |

|------|-----|------|----------------------|

| 部署频率 | 每周 | 每天 | 每小时 |

| 部署方式 | 手动 | 手动点击 | 全自动 |

| 测试覆盖率 | 50%+ | 70%+ | 80%+ |

| 回滚方式 | 手动找包 | 一键回滚 | 自动回滚 |

| 监控告警 | 基础 | 完善 | 驱动回滚 |

| 团队心态 | 紧张 | 从容 | 习惯 |

**实践建议**:不要急于追求 Continuous Deployment。先把 CI 做扎实,再迈向持续交付,最后在测试和监控都成熟后再尝试自动部署。跳级发展只会让线上事故频发。


六、本篇要点回顾

  1. CI = 构建+测试,CD = CI+自动部署到预发,Continuous Deployment = CD+自动上线生产

  2. 持续交付的标志是 when: manual,持续部署的标志是自动触发+自动回滚

  3. 金丝雀部署 + 自动指标分析是持续部署的安全网

  4. 功能开关(Feature Flags)让新功能可以先部署再开启,降低风险

  5. 团队应按 CI → CD → Continuous Deployment 逐步演进,不可跳级

下一篇预告:《工具链全景:Jenkins、GitLab CI、GitHub Actions、Drone 对比选型》------了解了三个层次,我们来看看实现这些层次需要哪些工具,以及如何选型。

相关推荐
tianyuanwo1 天前
当提交标题重复阻塞CI:Git分支修复实战
git·ci/cd·分支基线调整
heimeiyingwang1 天前
【CI/CD·入门篇】CI/CD到底是什么:从手动部署到一键上线的演进之路
ci/cd
Python私教2 天前
GitHub Actions 实战:把测试、密钥扫描与 Docker 镜像检查接入 CI
ci/cd·docker·github·devsecops·github actions
增量星球3 天前
《持续交付2.0系列九》从手动到自动之持续集成
运维·ci/cd·持续部署·持续集成
海带紫菜菠萝汤3 天前
CI/CD集成文档翻译:自动化多语言发布流水线实践
运维·ci/cd·自动化
xexpertS4 天前
软件发布文化:CI/CD、合并队列与金丝雀发布实践
人工智能·ci/cd
ji_shuke4 天前
Playwright 从零到 CI 实战:基于 TypeScript 的端到端测试完整指南
javascript·ci/cd·typescript·playwright
DLYSB_4 天前
DevOps 运维实战:基于 CI/CD 流水线 Webhook 的构建状态物理现场声光反馈架构
运维·ci/cd·devops·报警灯
huameinan狮子5 天前
微服务化的基石——持续集成
大数据·ci/cd·微服务