Skip to content

CI/CD 自动化部署流程

CI/CD(Continuous Integration / Continuous Deployment)是现代软件交付的核心理念,通过自动化流水线将代码从提交到生产环境的过程标准化、可视化、可追溯。

一、核心概念

CI 与 CD 的区别

缩写全称含义触发点终点
CIContinuous Integration持续集成代码提交自动化构建 + 测试通过
CDContinuous Delivery持续交付CI 通过可随时一键部署到生产
CDContinuous Deployment持续部署CI 通过自动部署到生产环境

Delivery vs Deployment:Delivery 强调"随时可部署但需人工确认",Deployment 强调"自动部署无需人工"。团队根据合规要求选择。

价值收益

  • 频率提升:从周级发布到日级甚至小时级发布
  • 缺陷前置:每次提交都跑测试,问题在引入时即被发现
  • 回滚迅速:每次部署都是原子操作,失败可快速回退
  • 环境一致:通过容器和 IaC 消除"在我机器上能跑"问题
  • 审计可追溯:每次发布都有完整的构建日志和审批记录

二、典型流水线阶段

一条完整的 CI/CD 流水线通常包含以下阶段,每个阶段失败都会阻断流水线并通知责任人:

代码提交 → 代码扫描 → 依赖安装 → 构建 → 单元测试 → 集成测试

   [CI 结束]

   镜像打包 → 推送仓库 → 部署预发 → 冒烟测试 → 人工审批 → 部署生产 → 健康检查

   [CD 结束]

   监控告警 → 日志聚合

各阶段详解

阶段任务失败处理典型耗时
代码扫描Lint、格式检查、安全漏洞扫描阻断提交,通知作者修复10~30s
依赖安装npm ci / pip install / mvn install缓存失效时重试30s~3min
构建编译、打包、生成制品检查构建配置和依赖版本1~5min
单元测试运行 npm test / pytest标记失败用例,阻断流水线30s~3min
集成测试启动依赖服务,跑端到端测试检查测试环境配置2~10min
镜像打包docker build 生成镜像检查 Dockerfile 语法1~5min
推送仓库推送到 Harbor / ACR / GHCR检查权限和仓库配额30s~2min
部署预发滚动更新预发环境健康检查失败自动回滚1~3min
冒烟测试核心链路 API 验证通知值班人员介入30s~2min
人工审批生产环境合规要求审批人可以在 4 小时内决策数分钟~数小时
部署生产蓝绿 / 金丝雀 / 滚动发布健康检查失败自动回滚1~5min
健康检查探活接口、关键指标监控触发告警并自动回滚持续

三、主流工具链选型

CI/CD 平台对比

平台特点适用场景价格模式
GitHub Actions与 GitHub 深度集成,生态丰富开源项目、GitHub 托管项目按分钟计费,公开仓库免费
GitLab CI一体化 DevOps 平台,自托管友好企业内网部署、合规要求高自托管免费,云版按用户
Jenkins老牌开源,插件生态庞大复杂定制化需求、遗留系统完全免费,需自维护
CircleCI速度快,并行能力强重测试场景、需要 macOS按 credito 按用量
Drone云原生、容器化原生K8s 环境、轻量级需求免费开源

CI/CD 配套工具

类别推荐工具
容器运行时Docker、containerd、Podman
镜像仓库Harbor、ACR、ECR、GHCR
编排调度Kubernetes、Docker Compose、Nomad
配置管理Ansible、Chef、Puppet
基础设施即代码Terraform、Pulumi、Crossplane
密钥管理Vault、AWS Secrets Manager、Sealed Secrets
监控告警Prometheus + Grafana、Datadog、夜莺
日志聚合ELK、Loki、ClickHouse
制品仓库Nexus、JFrog Artifactory

四、GitHub Actions 实战示例

以一个 VitePress 文档站点为例,演示从提交到自动部署到 GitHub Pages 的完整流程。

工作流文件

在仓库根目录创建 .github/workflows/deploy.yml

yaml
name: Build and Deploy

on:
  push:
    branches: [main]          # 主分支推送触发
  workflow_dispatch:           # 支持手动触发

permissions:
  contents: read
  pages: write
  id-token: write

# 同一分支只跑最新一次,取消历史构建
concurrency:
  group: pages
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: docs/.vitepress/dist

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

关键字段说明

字段作用
on.push.branches触发条件:指定分支推送时执行
workflow_dispatch允许在 Actions 面板手动触发
permissions授予 GITHUB_TOKEN 的权限(pages 部署必需)
concurrency并发控制,避免重复部署
cache: npm缓存 npm 依赖,加速后续构建
needs作业依赖关系,deploy 必须等 build 成功
environment部署环境,可在 Settings → Environments 配置审批

环境变量与密钥

敏感信息(API Key、Token)通过 Secrets 注入:

yaml
- name: Deploy to server
  env:
    SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
    DEPLOY_HOST: ${{ vars.DEPLOY_HOST }}
  run: |
    mkdir -p ~/.ssh
    echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    chmod 600 ~/.ssh/id_rsa
    rsync -avz --delete docs/.vitepress/dist/ user@${DEPLOY_HOST}:/var/www/html

密钥类型

  • secrets.* — 加密变量,日志中自动打码,适合敏感数据
  • vars.* — 明文变量,所有协作者可见,适合配置项

五、部署策略

1. 滚动部署(Rolling Update)

逐步替换旧版本实例,适合无状态服务:

v1 v1 v1 v1  →  v2 v1 v1 v1  →  v2 v2 v1 v1  →  v2 v2 v2 v2
  • 优点:资源占用平稳,无需额外容量
  • 缺点:过渡期 v1 v2 共存,需保证兼容性
  • K8s 配置strategy: type: RollingUpdatemaxSurge: 25%maxUnavailable: 25%

2. 蓝绿部署(Blue-Green)

准备两套完全一致的环境,切换流量:

[蓝环境 v1 ← 流量]    [绿环境 v2]
                    ↓ 部署新版本到绿环境
[蓝环境 v1]    [绿环境 v2 ← 流量,验证通过后切换]
  • 优点:切换瞬时完成,回滚只需切回
  • 缺点:需要双倍资源
  • 适用:数据库变更风险高、要求零停机的场景

3. 金丝雀发布(Canary)

小流量先试,逐步扩大:

v1 100%  →  v1 90% / v2 10%  →  v1 50% / v2 50%  →  v2 100%
  • 优点:风险可控,问题影响范围小
  • 缺点:需要流量分发和监控支持
  • K8s 工具:Argo Rollouts、Flagger

4. 特性开关(Feature Flag)

代码已部署但功能默认关闭,按需开启:

javascript
if (featureFlags.isEnabled('new-checkout-flow')) {
  return newCheckoutFlow();
}
return legacyCheckoutFlow();
  • 优点:解耦"部署"与"发布",可随时关闭
  • 缺点:代码路径复杂,需管理开关生命周期
  • 工具:LaunchDarkly、Unleash、Flagsmith

六、回滚机制

回滚决策矩阵

场景决策操作
健康检查失败立即自动回滚切换到上一个稳定版本
错误率 > 1% 持续 5 分钟自动回滚 + 告警触发 PagerDuty 通知
业务反馈异常人工决策回滚运维人员执行回滚脚本
数据库已变更谨慎评估优先恢复数据,再回滚代码

快速回滚实践

K8s 回滚

bash
# 查看发布历史
kubectl rollout history deployment/my-app

# 回滚到上一版本
kubectl rollout undo deployment/my-app

# 回滚到指定版本
kubectl rollout undo deployment/my-app --to-revision=3

Git 回滚策略

  • 优先使用 git revert(保留历史)
  • 紧急情况可用 git reset + 强推(确保无人基于该分支开发)
  • 数据库迁移必须配套"回滚迁移"脚本

七、最佳实践

1. 流水线设计原则

  • 快速失败:将耗时短的检查(lint、单测)放前面,快速阻断
  • 并行化:无依赖阶段并行执行,缩短整体耗时
  • 缓存优化:依赖、构建产物、Docker layer 全部缓存
  • 幂等性:任何阶段重跑都能得到相同结果
  • 可观测性:每个阶段都有清晰的日志和状态指标

2. 安全实践

yaml
# 最小权限原则
permissions:
  contents: read      # 只授予必要权限

# 第三方 Action 锁定版本
- uses: actions/checkout@v4  # ✅ 锁定大版本
  # 而非 actions/checkout@main ❌

# SAST 扫描
- uses: github/codeql-action/init@v3
- uses: github/codeql-action/analyze@v3

# 依赖漏洞扫描
- run: npm audit --audit-level=high
- uses: snyk/actions/node@master
  env:
    SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

# 镜像签名(Cosign)
- uses: sigstore/cosign-installer@v3
- run: cosign sign --key env://COSIGN_PRIVATE_KEY my-registry/app:v1

3. 制品管理

  • 版本规范:语义化版本 v1.2.3 或 Git SHA 短哈希
  • 不可变标签:禁止覆盖已发布的镜像标签
  • 保留策略:开发环境保留 7 天,生产环境保留 90 天
  • 多架构镜像docker buildx 构建 amd64/arm64 多架构

4. 数据库变更

yaml
# 数据库迁移独立于应用部署
jobs:
  migrate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run migrations
        run: |
          npm run db:migrate
          # 同时生成回滚脚本
          npm run db:migrate:rollback > rollback.sql
      - name: Save rollback script
        uses: actions/upload-artifact@v4
        with:
          name: rollback-sql
          path: rollback.sql

变更原则

  • 向后兼容:先部署兼容旧代码的 schema,再部署新代码
  • 分步执行:添加列 → 部署代码读写新列 → 数据迁移 → 删除旧列
  • 回滚优先:每次变更都要准备回滚脚本
  • 窗口期:大规模变更选低峰时段

5. 监控与告警

关键指标

  • SLO:服务等级目标(如 99.9% 可用性)
  • 错误预算:SLO 容许的错误率,超支则冻结发布
  • DORA 四指标:部署频率、变更前置时间、变更失败率、平均恢复时间

告警分级

级别响应时间通知方式
P0 紧急5 分钟电话 + 短信 + IM
P1 高15 分钟短信 + IM
P2 中1 小时IM
P3 低工作日邮件

八、CI/CD 成熟度模型

级别特征典型表现
L0 手动全人工操作手动打包、手动上传、手动改配置
L1 脚本化半自动部分步骤脚本化,仍需人工触发
L2 CI持续集成提交自动触发构建和测试
L3 CD持续交付自动部署到预发,生产需人工确认
L4 全自动持续部署测试通过即自动上线
L5 自治GitOps + 渐进式发布声明式配置、自动金丝雀、自适应回滚

演进建议:从 L2 起步,建立信心后过渡到 L3,关键业务再考虑 L4+。盲目追求 L4 可能因测试覆盖不足导致事故。


九、常见陷阱

1. "雪花"环境

问题:手动配置的环境随时间漂移,无法复现 解决:基础设施即代码(Terraform / Ansible),所有变更通过 PR

2. 流水线过长

问题:单次构建 30+ 分钟,反馈太慢 解决

  • 拆分流水线,关键路径优先(lint → 单测 → 部署,集成测试并行)
  • 缓存依赖和构建产物
  • 测试分片(test sharding)

3. 脆弱测试(Flaky Test)

问题:偶发失败的测试阻断流水线 解决

  • 隔离测试数据,避免共享状态
  • 时间敏感测试使用 mock 时钟
  • 标记 flaky 测试,quarantine 后修复

4. 密钥泄露

问题:Token 写在代码或日志中 解决

  • 一律使用 Secrets Manager
  • CI 日志自动打码敏感字段
  • 启用 push protection 阻止提交密钥

5. 数据库迁移卡住

问题:长事务迁移锁表导致服务不可用 解决

  • 大表变更使用 pt-online-schema-changegh-ost
  • 分批迁移,每批限制行数
  • 低峰期执行

十、学习路径

入门阶段(1~2 周)

  1. 阅读 GitHub Actions 官方文档
  2. 为现有项目添加一个 lint + test 工作流
  3. 体验部署到 GitHub Pages

实践阶段(1~2 月)

  1. 学习 Docker 基础,编写 Dockerfile
  2. 使用 docker-compose 编排多容器应用
  3. 在 VPS 上部署一个完整应用(前端 + 后端 + 数据库)
  4. 配置 Nginx 反向代理和 HTTPS

进阶阶段(3~6 月)

  1. 学习 Kubernetes 基础,部署应用到 K8s
  2. 使用 Helm 管理应用部署
  3. 接入 Prometheus + Grafana 监控
  4. 实践蓝绿部署和金丝雀发布

高级阶段(持续)

  1. 学习 GitOps(ArgoCD / Flux)
  2. 掌握 IaC(Terraform)
  3. 实践混沌工程(Chaos Mesh)
  4. 构建平台工程能力(Backstage)

参考资料