Skip to content

16 | CI/CD 权责分离

从仓库交接推导分离 ​

前面已经完成两段操作:构建镜像并推送仓库,目标环境拉取并启动。健康检查又说明“镜像存在”和“服务可用”之间还有距离。现在才给这两段工作划分职责:上游生成并验证制品,下游在确定环境中发布和验收。

一个镜像可以经过测试,但目标环境可能没有容量,或数据库还不兼容。CI 与 CD 分离让构建结果和发布决定各有明确输入、权限与证据。

个人项目中可以由同一个人承担两种职责,也可以把两个阶段放在同一个工作流。分离不要求两个部门、两个平台或每次都人工审批。上一课的健康判断会成为 CD 的验收步骤,而不是重新写一套成功标准。

制品是交接契约 ​

阶段输入输出权限
CI确定的源码 commit、依赖和构建配置经过测试的镜像 digest、报告与来源记录读取源码、写目标镜像仓库
CD已批准的制品和配置、目标环境实际发布版本、验收和恢复记录读取制品、变更指定环境

同一制品从 dev 晋级到 prod 时不重新构建。镜像 digest 用于识别内容,签名用于验证身份;不能把 MD5 或一个标签当作可信来源保证。

责任按能力与场景划分 ​

开发维护应用行为、测试与部署声明;平台维护执行环境、权限和可观测能力;发布责任人确认目标与验收条件。实际可由一个团队共同承担,也可按组织要求分工。

故障归因需要查看应用、基础设施、配置和流程证据,不预设“所有生产故障运维全责”。CI 与 CD 都可能并行或串行,执行模型取决于依赖关系,不是两者的定义差异。

一个可落地的边界 ​

  • PR 仅运行检查,不读取生产密钥。
  • 合并受保护分支后构建并推送镜像,保存 digest。
  • 发布申请固定镜像和配置版本,按风险决定自动准入或人工审批。
  • CD 验证来源、部署、检查健康,失败保持失败并保留诊断信息。
  • 发布记录关联执行身份、版本、环境和结果,保留周期按实际要求确定。

正式实施时,用独立账号测试”CI 无法修改生产、CD 无法覆盖镜像”;只在架构图上画两个框不算完成分离。

上的权限边界 ​

以 GitHub Actions 为例,CI 和 CD 可以放在同一个仓库的两个 workflow 中,但权限配置不同:

yaml
# .github/workflows/ci.yml — PR 和合并触发
name: CI
on:
  push:
    branches: [main]
  pull_request:
permissions:
  contents: read       # 只读源码
  packages: write      # 推送镜像到制品库
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: docker build -t registry/app:${{ github.sha }} .
      - run: docker push registry/app:${{ github.sha }}
yaml
# .github/workflows/cd.yml — 仅 main 合并后触发,需环境审批
name: CD
on:
  workflow_run:
    workflows: [CI]
    types: [completed]
permissions:
  contents: read       # 只读部署配置
  id-token: write      # 用于 OIDC 认证到目标环境
environment: production # 触发环境审批(如果配置了保护)
jobs:
  deploy:
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    runs-on: ubuntu-latest
    steps:
      - run: |
          DIGEST=${{ github.event.workflow_run.head_sha }}
          kubectl set image deployment/app app=registry/app@sha256:${DIGEST}

CI workflow 能推镜像但不能访问;CD workflow 能部署但不能修改镜像。两个 workflow 通过镜像 digest 交接,而不是通过标签——标签可以被覆盖,digest 指向不可变内容。

常见反模式 ​

反模式问题修正方向
CI 流水线直接 kubectl apply 到生产构建和发布没有边界,PR 测试代码可能直接影响生产拆成 CI(构建)+ CD(发布)两个阶段
CD 阶段重新 docker build部署的内容未经 CI 验证,制品契约被绕过CD 只拉取 CI 产出的固定 digest
用 latest 标签做发布无法追溯部署的具体内容,回滚指向不明用 digest 或不可变标签标识制品
同一个 token 同时用于构建和部署凭据泄露时影响范围不可控CI 和 CD 使用独立的凭据和权限范围

判断分离是否有效的标准不是画了多少个框,而是:CI 的凭据泄露后,攻击者能否直接修改生产环境? 如果答案是否,分离就落地了。

最小验收与思考 ​

提交代码后只看到 CI 运行,生产版本没有改变;发布失败可以查到具体 digest 和恢复记录;无需重新构建就能把 staging 验证过的制品交给生产。

下一课通过 CI 流水线生成这份交接物。思考:如果审批后又修改了镜像标签,原审批还指向同一个内容吗?