4、持续交付与部署:CD的概念与价值、部署流水线设计、环境管理(Dev/Test/Staging/Prod)

4.1 持续交付到底是什么?

聊完CI,咱们自然要聊CD。很多人把CD理解成「自动部署到生产环境」,其实不准确。

持续交付(Continuous Delivery)的核心是:让每个通过测试的版本,都具备随时上线的能力。说白了,就是你的代码任何时候想发布,点一下按钮就能发,而不是需要折腾半天环境、配置、依赖。

我个人习惯把CD分成两层:

  • 持续交付:代码通过所有测试后,自动部署到类生产环境(Staging),但上线需要手动确认。
  • 持续部署:连手动确认都省了,测试通过直接推生产。

你想想看,如果你的团队每次上线都要熬夜、回滚手忙脚乱、发版像在拆炸弹——那说明你的CD还没玩明白。

CD的核心价值:降低发布风险、缩短反馈周期、让发布变成「日常操作」而不是「大事件」。

4.2 部署流水线设计——从代码到生产的管道

部署流水线,说白了就是一条自动化管道。代码从提交开始,一路经过编译、测试、部署,最终到达生产环境。

我在项目中遇到过不少团队,流水线设计得过于复杂,动不动就十几个Stage。结果呢?一次构建跑40分钟,没人愿意等,最后大家又回到手动部署的老路。

我的建议是:流水线要「够用就好」,别过度设计

一个典型的部署流水线长这样:

  1. Commit Stage:代码提交 → 编译 → 单元测试 → 代码扫描
  2. Acceptance Stage:部署到Dev环境 → 集成测试 → API测试
  3. Capacity Stage:性能测试 → 安全扫描
  4. Production Stage:手动确认 → 灰度发布 → 全量上线

嗯,这里要注意:每个Stage都应该有明确的「门禁」。比如单元测试没过,后面的Stage直接跳过,别浪费时间。

我的经验:流水线里的每个Stage尽量控制在5分钟以内。超过10分钟,开发人员就会开始摸鱼等结果了。

代码示例:一个简单的GitLab CI流水线

stages:
  - build
  - test
  - deploy_dev
  - deploy_staging
  - deploy_prod

build:
  stage: build
  script:
    - mvn clean package
  artifacts:
    paths:
      - target/*.jar

test:
  stage: test
  script:
    - mvn test
    - sonar-scanner

deploy_dev:
  stage: deploy_dev
  script:
    - scp target/*.jar dev-server:/app/
  environment:
    name: dev

deploy_staging:
  stage: deploy_staging
  script:
    - scp target/*.jar staging-server:/app/
  environment:
    name: staging
  when: manual  # 需要手动触发

deploy_prod:
  stage: deploy_prod
  script:
    - ./deploy-prod.sh
  environment:
    name: production
  when: manual
  only:
    - tags  # 只有打tag才允许部署生产

你看,这个流水线很清晰。开发环境自动部署,Staging和Prod需要手动确认。我曾经见过有人把生产部署也设成自动的,结果某次测试环境的数据污染了,直接推到了生产……嗯,那场面,挺刺激的。

4.3 环境管理——Dev/Test/Staging/Prod

环境管理是CD里最容易翻车的地方。我见过太多团队,Dev环境跑得好好的,一到Staging就炸,到了Prod直接崩。

为什么会这样?说白了就是环境不一致

四种环境的定位:

环境 用途 谁在用 数据 稳定性要求
Dev 开发自测、联调 开发人员 模拟数据 低,可以随时重启
Test 功能测试、集成测试 QA团队 脱敏数据 中等
Staging 预发布验证、性能测试 QA、产品、运维 类生产数据 高,尽量接近生产
Prod 线上服务 最终用户 真实数据 最高,不能随便动

避坑指南:我曾经遇到一个项目,Staging环境和Prod环境的数据库版本差了三个大版本。结果Staging测试全过,上线后Prod直接报错——因为Prod的MySQL不支持某个新语法。从那以后,我要求所有环境的中间件版本必须锁死,用Docker镜像统一管理。

环境管理的最佳实践:

  • 基础设施即代码:用Terraform、Ansible或Docker Compose定义环境,别手动配服务器。我习惯把环境配置也放到Git里,和代码一起版本管理。
  • 环境隔离:Dev和Test可以共用资源,但Staging和Prod必须物理隔离。别问我为什么,问就是「数据安全」。
  • 配置分离:代码里不要写死任何环境相关的配置。用环境变量或者配置中心,比如Consul、Spring Cloud Config。
  • 一键部署:每个环境都应该能通过一条命令或一个按钮完成部署。如果还需要SSH上去手动改配置,那你的CD还停留在石器时代。

环境配置示例(Spring Boot):

# application-dev.yml
server:
  port: 8080
database:
  url: jdbc:mysql://dev-db:3306/myapp
  username: dev_user
  password: dev_pass

# application-prod.yml
server:
  port: 8080
database:
  url: jdbc:mysql://prod-db:3306/myapp
  username: ${DB_USER}
  password: ${DB_PASS}

你看,Prod环境的密码用环境变量注入,而不是写死在配置文件里。这个习惯我吃了不少亏才养成的。

4.4 回滚策略——CD的最后一道防线

再完美的CD流程,也挡不住业务方临时改需求或者某个隐藏Bug。所以,回滚能力是CD的标配

我个人习惯把回滚策略分成三种:

  • 版本回滚:直接切回上一个稳定版本。适合单体应用,简单粗暴。
  • 灰度回滚:先回滚一部分流量,观察没问题再全量回滚。适合微服务架构。
  • 功能开关回滚:通过配置中心关闭某个功能,而不是回滚整个版本。适合功能粒度较细的场景。

我的建议:别等到出问题了才想回滚方案。在部署流水线里就把回滚脚本写好,每次部署自动生成回滚包。我曾经见过一个团队,上线后出Bug,结果回滚脚本找不到了,最后花了两个小时手动恢复——那晚的加班费,够买好几台服务器了。

4.5 小结

持续交付和部署,说白了就是让「发布」这件事变得可预测、可重复、可回滚。环境管理是基础,流水线是骨架,回滚策略是保险。

你想想看,如果你的团队能做到:代码提交后自动测试、自动部署到Staging、点一下按钮就上线、出问题30秒内回滚——那你的DevOps成熟度,至少已经超过了80%的团队。

嗯,下一章咱们聊聊更进阶的话题:蓝绿部署与金丝雀发布。到时候我会分享一个我在金融项目里踩过的坑,保证让你印象深刻。