如果你找人要一张 CI/CD 图,通常拿到的是一排方框:构建、测试、部署。这不算错,但人们看图时想问的问题,它几乎一个都答不上来。到底部署的是什么?谁能把变更推到生产环境?审批在哪里?怎么回滚,又是什么告诉我们需要回滚?
本文以一套常见配置为例,介绍如何画出能回答这些问题的 CI/CD 流水线图:GitHub 风格的 pull request、容器镜像仓库,以及借助 Argo CD 部署到 Kubernetes 的 GitOps 流程。这些规则同样适用于其他工具。
流水线图应该展示什么
- 触发条件。 是什么启动了每个部分:pull request、合并到 main、打 tag、定时任务。
- 阶段及其顺序。 lint、测试、构建、扫描、部署、验证。
- 制品。 在阶段之间流转的东西,通常是容器镜像。标明它的标识方式:tag,或者更好的 digest。
- 环境。 制品在哪里运行,以及按什么顺序到达那里。
- 关卡。 能拦下变更的人工审批、必需检查和策略。
- 凭据。 哪个系统可以修改哪个环境。
- 反馈。 生产环境的信号如何叫停或回滚有问题的发布。
一排阶段只覆盖了前两项。其余部分才是事故和审计发生的地方。
示例:通过 GitOps 部署到 Kubernetes
- 开发者在应用仓库中发起 pull request。
- CI 在每次 push 时运行:lint、单元测试、构建镜像、扫描镜像。合并到 main 后,它把镜像推送到镜像仓库,并记录镜像的 digest。
- 接着,CI 把新的镜像 digest 提交到独立的配置仓库中的 staging overlay。
- 在 staging 集群中,Argo CD 发现这个提交,拉取配置并同步集群。
- 要推进到生产环境,有人发起一个 pull request,把这个引用复制到生产环境的 overlay。必需的评审就是审批关卡。
- 合并后,生产环境中的 Argo CD 完成同步,集群中另一个独立的控制器 Argo Rollouts 则以金丝雀方式发布新版本:先放一小部分流量,再放全部流量。
- 金丝雀发布期间,Argo Rollouts 会基于 Prometheus 指标运行分析。分析失败会中止发布,把流量切回稳定版本,同时告警会呼叫值班工程师。
图表内容
- Developer
- app repo
- CI: lint, test, build, scan
- Image registry
- config repo (GitOps)
- staging
- Argo CD
- staging cluster
- approve
- production
- Argo CD + Argo Rollouts
- production cluster
- Prometheus
- SLO alert
- On-call
- pull request
- on push
- image, by digest
- write image digest
- pull & sync
- apply
- PR: promote
- merge, pull & sync
- canary
- metrics
- failed check stops the canary
- SLO burn
- page
这张图上有两个细节很容易被忽略,却非常重要。CI 从不与集群直接通信:它只把镜像推送到镜像仓库,并向 Git 提交。生产环境也只会通过经过评审的提交发生变化,这同时也是回滚的方式:revert 这个提交,Argo CD 就会同步回上一个版本。
推送还是拉取:画出凭据存放在哪里
在推送式流水线中,CI 持有集群的凭据,并自己执行部署命令。在拉取式的 GitOps 方案中,每个集群内的代理(例如 Argo CD 或 Flux)从 Git 拉取期望状态并加以应用,因此集群外部的任何东西都不需要对集群的写权限。
两种方式都可行,图应该让人清楚看出选的是哪一种。如果是推送式,就从 CI 向每个集群画一条连线,并标上它使用的凭据。如果是拉取式,就画出配置仓库为每个集群中的代理提供配置,CI 与任何集群之间都没有连线。这样评审者一眼就能看出,CI 的 secret 一旦泄露,影响范围有多大。
如果 CI 需要访问云平台,比如推送镜像,请注明它是如何获得访问权限的。在图上,通过 OpenID Connect 获取的短期令牌,远比作为 secret 保存的长期密钥更站得住脚。
让流水线图易读的规则
让制品清晰可见
给进入镜像仓库的连线标上制品及其标识方式:image shop-api, by digest。tag 可以被挪动,digest 则始终指向同一个镜像。如果你还生成了 SBOM 或签名,就把它们画在镜像旁边。
把环境画成框
每个环境是一个框,里面放着它的部署代理和集群。框的先后顺序展示了推进路径,任何跳过某个框的东西都会很显眼。
给关卡单独的节点
审批是一个有负责人的步骤,而不是箭头上的一个标签。把它画成环境之间的一个节点,并写明由谁审批:approve: release manager 或 2 reviews required。
形成闭环
止步于“部署”的流水线没有反馈。画出是什么在监控生产环境,以及它能做什么:叫停金丝雀发布、呼叫某个人、触发回滚。
把作业细节留在 CI 文件里
十二个并行的测试作业属于 CI 配置。在图上,一个带简短标签(lint, test, build, scan)的阶段节点就够了。
常见错误
- 没有制品。 方框之间用箭头相连,箭头上却没有承载任何具体的东西。读者看不出被推进的是什么。
- 把环境画成阶段。 把“部署 staging”和“部署 prod”画成一排中的两个方框,会掩盖它们是权限不同的两个地方。
- 缺少回滚路径。 如果没人能在图上指出它,它很可能从未被测试过。
- 每个作业都画成节点。 图就变成了 CI 日志。
- 画工具而不是职责。 标着产品名的方框,传达的信息还不如
build and scan image。
在 Archboard 中构建
- 使用 Google 或 GitHub 登录,并新建一张图。
- 从 DevOps 节点包中,为应用仓库和配置仓库添加代码仓库节点,为 CI 添加一个流水线。再从 Docker 节点包中添加一个镜像仓库。
- 为每个环境添加一个基础节点包中的框架,在里面放入 DevOps 节点包中的部署节点(用于 Argo CD,生产环境中还包括 Argo Rollouts)和云节点包中的 Kubernetes 集群。
- 从基础节点包中添加一个菱形形状,作为审批关卡。
- 添加 DevOps 节点包中的指标和告警节点,并为开发者和值班工程师添加 C4 模型节点包中的人员节点。
- 连接端口,给每条连线标上流经的内容,并把反馈连线设为虚线。
这个示例用了 15 个图表节点,正好是 Free 套餐的上限。想看内置可观测性的流水线,可以打开 /examples/cicd-observability;集群这一侧,请参阅如何画 Kubernetes 架构图。
常见问题
每个 CI 作业都要画出来吗? 不用。把作业按阶段分组,细节留在 CI 文件里。只有当某个作业本身就是关卡时才单独画出来,比如会阻止发布的安全扫描。
功能开关怎么表示? 画成生产环境旁边的一个独立系统,并用连线连到读取开关的服务。开关无需部署就能改变行为,所以值得在图上单独占一条线。
图上的 secret 放在哪里? 标出哪个系统持有哪种凭据、用于什么,而不是 secret 本身。对于 CI,注明它用的是短期 OIDC 令牌还是存储的密钥。
每个仓库都需要一张图吗? 通常是每条交付路径一张图。如果许多服务共用同一条流水线,画一次就够了,再在一个便签里列出这些服务。
怎样让图保持最新? 流水线变化时评审这张图,就像评审 CI 文件一样。在仓库的 README 中链接到在线的图,这样就只有一份副本。