从仓库交接推导分离
前面已经完成两段操作:构建镜像并推送仓库,目标环境拉取并启动。健康检查又说明“镜像存在”和“服务可用”之间还有距离。现在才给这两段工作划分职责:上游生成并验证制品,下游在确定环境中发布和验收。
一个镜像可以经过测试,但目标环境可能没有容量,或数据库还不兼容。CI 与 CD 分离让构建结果和发布决定各有明确输入、权限与证据。
个人项目中可以由同一个人承担两种职责,也可以把两个阶段放在同一个工作流。分离不要求两个部门、两个平台或每次都人工审批。上一课的健康判断会成为 CD 的验收步骤,而不是重新写一套成功标准。
制品是交接契约
| 阶段 | 输入 | 输出 | 权限 |
|---|---|---|---|
| CI | 确定的源码 commit、依赖和构建配置 | 经过测试的镜像 digest、报告与来源记录 | 读取源码、写目标镜像仓库 |
| CD | 已批准的制品和配置、目标环境 | 实际发布版本、验收和恢复记录 | 读取制品、变更指定环境 |
同一制品从 dev 晋级到 prod 时不重新构建。镜像 digest 用于识别内容,签名用于验证身份;不能把 MD5 或一个标签当作可信来源保证。
责任按能力与场景划分
开发维护应用行为、测试与部署声明;平台维护执行环境、权限和可观测能力;发布责任人确认目标与验收条件。实际可由一个团队共同承担,也可按组织要求分工。
故障归因需要查看应用、基础设施、配置和流程证据,不预设“所有生产故障运维全责”。CI 与 CD 都可能并行或串行,执行模型取决于依赖关系,不是两者的定义差异。
一个可落地的边界
- PR 仅运行检查,不读取生产密钥。
- 合并受保护分支后构建并推送镜像,保存 digest。
- 发布申请固定镜像和配置版本,按风险决定自动准入或人工审批。
- CD 验证来源、部署、检查健康,失败保持失败并保留诊断信息。
- 发布记录关联执行身份、版本、环境和结果,保留周期按实际要求确定。
正式实施时,用独立账号测试”CI 无法修改生产、CD 无法覆盖镜像”;只在架构图上画两个框不算完成分离。
上的权限边界
以 GitHub Actions 为例,CI 和 CD 可以放在同一个仓库的两个 workflow 中,但权限配置不同:
# .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 }}# .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 流水线生成这份交接物。思考:如果审批后又修改了镜像标签,原审批还指向同一个内容吗?