跳至正文
Starone

能力

让生产发布成为日常的交付流水线

我们设计从提交到生产的整条路径:构建、测试、安全分析、制品管理、环境晋升与渐进式发布。安全检查就运行在这条路径之内,因此一次发布由交付它的同一套系统来验证。

概览

DevOps 是针对交付系统本身的工程。代码库、流水线、环境与反馈回路共同构成一台机器,它的产出是在生产环境中正常运行的软件;这台机器可以设计得好,也可以设计得差。设计得好的,每天多次发布小变更,失败率很低。设计得差的,则把数周的工作攒成一次发布,需要变更窗口,还要配上一份没人信得过的回滚方案。

DevSecOps 把同样的思路延伸到安全上。安全不再是最后的一道评审关卡,而是被自动化,并放在处理成本最低的位置:pull request 中的静态分析,构建阶段的依赖与容器扫描,准入时的签名验证,基础设施变更上的策略执行。开发者在几分钟内、在自己本来就在用的工具里拿到结果,此时上下文还很清晰。

我们把流水线、环境定义与策略当作生产软件来对待。它们有版本管理,经过评审与测试,并且有明确的负责人。我们的设计目标,是一套审计人员读得懂、工程师推理得清、新团队无需重新发明就能采用的交付流程。

我们构建什么

技术领域

01

CI/CD 流水线设计

流水线是一连串按成本与反馈速度排序的质量关卡。我们把快速且确定性的检查放在最前面,把可以独立运行的部分并行化,并积极使用缓存,使常见情况在几分钟内完成。流水线被定义为可复用的模板,这样每个服务都继承组织的标准,而不是复制 YAML。

  • GitHub Actions、GitLab CI 与 Jenkins 流水线设计
  • 可复用的 workflow 模板与共享流水线库
  • 构建缓存、测试分片与并行阶段
  • 单元、集成、契约与端到端测试阶段
  • 数据库迁移检查与向后兼容性关卡
  • 使用限定范围、短时效凭证的临时 runner
02

源码管理策略与构建管理

分支策略决定了变更的批量大小。我们倾向于主干开发,配合短生命周期分支与功能开关,因为长期存在的分支会把集成风险推迟到最糟糕的时刻。构建是可复现的,并产出唯一一个不可变、带版本的制品,原封不动地在各个环境之间晋升。

  • 主干开发,配合短生命周期的功能分支
  • 仅在监管要求或移动应用商店周期需要时才使用发布分支
  • 语义化版本与自动生成的变更日志
  • 以提交 digest 打标签的不可变容器镜像
  • Amazon ECR、GHCR、Harbor 与 Artifactory 等制品仓库
  • 支持受影响目标检测的 monorepo 与 polyrepo 构建工具
03

环境与渐进式交付

环境的存在是为了在进入生产之前降低不确定性,而渐进式交付则在生产之内进一步降低它。我们用同一套基础设施代码构建各个环境,仅以配置作为差异,并让同一个制品在其间晋升。在生产环境中,金丝雀与蓝绿发布先让变更只接触一小部分流量,把它的错误率和延迟与基线对比之后再继续推进。

  • 通过共享的 Terraform 模块与 Helm chart 保持环境一致
  • 每个 pull request 对应一个预览环境
  • 金丝雀分析,自动晋升与回滚
  • 面向有状态或高风险发布的蓝绿切换
  • 用功能开关把部署与发布分离
  • expand-and-contract 式的数据库 schema 迁移
04

GitOps 与基础设施自动化

在 GitOps 模型中,每个环境的期望状态都存放在 Git 里,由集群内的控制器把运行状态持续调谐到期望状态。这带来了完整的审计轨迹,让 CI 系统不再持有集群凭证,也让回滚变成一次 revert。同样的纪律也适用于云资源,通过带有 plan 评审与策略检查的 Terraform 流水线来实现。

  • 使用 Argo CD 与 Flux 进行持续调谐
  • 环境仓库,通过 pull request 晋升
  • 带远程状态与锁的 Terraform 与 OpenTofu 流水线
  • 漂移检测,自动纠正或告警后纠正
  • 使用 Sealed Secrets 与 External Secrets Operator 下发密钥
05

安全左移与供应链完整性

大多数漏洞要么来自团队自己写的代码,要么来自它引入的代码。我们在能给出可靠信号的最早阶段,对这两者都实现自动化检测,并对每个工具进行调优,使发现的问题可以付诸行动,而不是被忽略。随后,构建过程会产出证据:一份软件物料清单、一个签名,以及说明构建了什么、源自哪份源码、由哪条流水线构建的 provenance。

  • 使用 Semgrep、CodeQL 或 SonarQube 进行 SAST
  • 软件成分分析与依赖更新自动化
  • 使用 Trivy 或 Grype 扫描容器镜像
  • 使用 Gitleaks 检测提交与历史记录中的密钥
  • 生成 CycloneDX 或 SPDX 格式的 SBOM
  • 使用 Sigstore Cosign 签名镜像,并生成 SLSA provenance 证明
  • 针对已部署的测试环境进行 DAST 与 API 模糊测试
06

策略即代码与平台工程

写在文档里的规则,执行起来参差不齐;写在代码里的规则,每一次都会被执行。我们用 Open Policy Agent 或 Kyverno 表达安全与运维策略,并针对 Terraform plan、Kubernetes manifest 与流水线定义进行评估。在此之上,我们构建黄金路径:一批模板与自助工具,让合规的方式成为创建和运行服务最省力的方式。

  • 针对基础设施 plan 的 OPA 与 Conftest 检查
  • 集群中的 Kyverno 或 Gatekeeper 准入策略
  • 面向新仓库的服务模板与脚手架
  • Backstage 等内部开发者门户
  • 环境与数据库的自助供给
  • 从流水线与事故数据中采集的 DORA 指标

部署与发布是两件不同的事

部署是把新代码送入生产。发布是把新行为开放给用户。把两者当成一件事,就会迫使每一次部署都背负业务风险,进而催生变更窗口、发布列车和大批量变更。把它们分开,代码就可以持续交付,而对用户的开放程度则可以独立控制。

功能开关在行为层面提供这种分离;金丝雀与蓝绿策略则在运行时风险层面提供这种分离。金丝雀发布把一小部分流量导向新版本,并在一段既定的时间内把它的指标与稳定版本对比。如果错误率或延迟的退化超过阈值,流量就自动切回稳定版本。蓝绿发布保留两套完整的环境并一次性切换流量,适合无法同时服务于混合版本的发布。

两者都依赖数据层能够同时容纳两个应用版本。因此 schema 变更遵循 expand-and-contract 的顺序:先增加新结构,部署同时写入两处的代码,迁移数据,切换读取,然后在后续的某次发布中移除旧结构。跳过这一步,是回滚失败最常见的原因。

架构

带安全门禁的 CI/CD 流水线

构建与验证

  1. 01

    提交

    经评审后合并到主干分支

  2. 02

    构建

    可复现,依赖版本锁定

  3. 03

    测试

    单元、集成与契约测试

  4. 04

    SAST 与依赖扫描

    静态分析与依赖审计

  5. 05

    镜像扫描与签名

    扫描镜像层、签名并附 SBOM

发布

  1. 01

    预发布

    同一制品,类生产数据

  2. 02

    金丝雀

    小比例流量,观察信号

  3. 03

    生产

    带门禁的渐进式发布

  4. 04

    监控

    由 SLO 决定推进或回滚

同一个制品经过构建、验证、扫描和签名,再原样经由预发布环境和金丝雀发布进入生产。监控构成闭环,决定一次发布是继续推进还是回滚。

保护软件供应链

一个现代服务的大部分是第三方代码:开源库、基础镜像、构建工具与 CI action。每一样都是一条攻击者不必触碰应用自身源码就能抵达生产环境的通道。供应链安全这项实践,就是要清楚一个制品里包含了什么,并证明它在源码与运行时之间没有被篡改。

这些控制措施环环相扣。依赖按版本与哈希锁定,更新以经过评审的 pull request 形式到来。构建运行在隔离的临时 runner 上,不持有任何长期凭证。每次构建都输出一份 SBOM,这样当新漏洞被披露时,可以通过查询找出受影响的服务。制品会被签名,并由一份 provenance 证明记录生成它的源码提交与流水线。在部署时,准入策略会拒绝任何未签名或在可信流水线之外构建的镜像。

  • 按 digest 锁定依赖、基础镜像与 CI action
  • 为每次构建生成 SBOM,并与制品一同存储
  • 对制品签名,并在准入时验证签名
  • 对照 SLSA 框架的等级记录 provenance
  • 按事先商定的严重级别阈值让构建失败,并配有成文的例外流程

用 DORA 指标度量交付

四项 DORA 指标从两个侧面描述一套交付系统。部署频率与变更前置时间衡量吞吐:团队多久交付一次,以及一次提交需要多久才能到达生产。变更失败率与服务恢复时间衡量稳定性:发布引发事故的频率有多高,以及服务多快能够恢复。这些指标背后的研究表明,吞吐与稳定性是同步改善的,因为两者都来自小批量与快速反馈。

我们从流水线事件、部署记录与事故数据中采集这些指标,使它们由系统产生,而不是由人来上报。它们用于定位约束所在,例如一个缓慢的测试阶段,或一个让交付多出数天的人工审批,也用于验证对流程的某项调整是否达到了预期效果。它们是服务于团队的诊断工具,一旦被变成个人考核目标就会失效。

平台工程与黄金路径

当组织的规模超出少数几个团队之后,每个团队各自解决流水线、可观测性与部署问题,就会变得代价高昂且彼此不一致。平台工程的应对方式是提供一个内部平台:一套经过精心挑选的模板、流水线与自助能力,由一个以其他工程师为用户的团队来维护。

黄金路径是完成某项常见任务的受支持路线,例如创建一个新服务,其代码仓库、流水线、部署 manifest、仪表盘与告警都已经接好。它在设计上就是可选的。有特殊需求的团队可以离开这条路径,但要自行承担原本由路径承担的运维责任。当工程师因为它比自己搭建更快而选择它时,平台才算成功。

我们如何构建

我们的方法

我们改进交付系统的顺序,是先消除最大的那个约束,并在每次变更前后进行度量。

  1. 01

    梳理当前的价值流

    我们追踪一次变更从提交到生产的全过程,记录每一个阶段、每一次等待和每一个人工步骤,同时记录 DORA 指标的基线。由此可以看出时间损失在哪里,故障又是在哪里被引入的。

  2. 02

    稳定构建与测试

    让构建可复现,把不稳定的测试隔离并修复,并重构流水线以获得快速反馈。工程师不信任的流水线会被绕过,因此可靠性先于新能力。

  3. 03

    统一制品与环境

    每个服务构建出一个不可变的制品,并在由同一套代码定义的各个环境之间晋升。配置与密钥在部署时从托管的存储中注入。

  4. 04

    嵌入安全与策略关卡

    加入 SAST、依赖、容器与密钥扫描,并配以调优过的规则和商定的严重级别阈值。待构建稳定之后,再引入 SBOM 生成、签名与准入策略。

  5. 05

    引入 GitOps 与渐进式交付

    部署改为依据 Git 进行调谐,采用金丝雀或蓝绿策略,并把自动回滚与服务指标挂钩。功能开关把发布决策与部署分离开来。

  6. 06

    把成果沉淀为黄金路径

    把行之有效的模式转化为其他团队可以采用的模板与自助工具。指标继续采集,用以指导下一轮改进。

取舍

决定设计走向的决策

在确定架构之前,我们会与您的团队逐一厘清的问题。

主干开发还是 GitFlow?
对于持续部署的服务,选择主干开发:短生命周期分支、功能开关以及始终可发布的主分支,能把集成成本压得很低。只有在必须同时支持多个已投放版本时才选择发布分支模型,例如套装软件,或受应用商店审核周期约束的移动应用。GitFlow 的长期分支是用周期性的合并风险来换掉每日集成,对一个 Web 服务来说很少是划算的交换。
金丝雀、蓝绿还是滚动部署?
对于健康检查完善的无状态服务,滚动更新是合理的默认选择。当流量足以产生具有统计意义的对比,并且希望在全量开放之前进行自动化验证时,使用金丝雀。当不同版本无法共存、需要瞬间切回,或流量太低不足以做金丝雀分析时,使用蓝绿;同时要接受它会让容量成本暂时翻倍。
推送式 CI/CD 部署,还是拉取式 GitOps?
基于 Argo CD 或 Flux 的拉取式 GitOps 适合 Kubernetes 环境:集群依据 Git 自行调谐,CI 不需要集群凭证,漂移会被自动纠正。对于没有调谐控制器的 serverless、虚拟机与托管服务目标,由流水线推送部署仍然更简单。许多组织两者并用,按目标平台划分。
安全扫描的发现应该阻断构建,还是只发出警告?
只对范围窄、置信度高的一类问题进行阻断:泄露的密钥、已有修复方案的严重漏洞,以及未签名或未经批准的基础镜像。其余问题一律发出警告并跟踪,同时指定负责人和修复期限。对噪声很大的发现进行阻断,只会教会团队绕过流水线;什么都不阻断,扫描器就成了摆设。
Monorepo,还是每个服务一个仓库?
monorepo 让跨服务的原子变更、共享库和统一工具链变得容易,但需要只测试变更部分的构建工具,例如 Bazel、Nx 或 Turborepo。独立仓库给团队带来独立性和简单的流水线,代价是横切性变更更难,共享代码也容易出现版本漂移。应依据这些服务在实践中的耦合程度,以及你能够持续投入多少构建工程来做选择。
建设内部开发者平台,还是保留各团队自己的流水线?
团队数量不过屈指可数时,共享的流水线模板加上良好的文档就够了,平台团队反而是额外负担。当重复劳动、不一致的安全控制与缓慢的新人上手已经成为可以度量的成本时,再投入建设平台。从最薄但有用的那条黄金路径开始,根据真实需求逐步扩展。

生产就绪

怎样才算生产就绪

如何保障安全

流水线通过 OIDC 联邦与短时效令牌向云厂商认证,绝不使用存储的密钥,并运行在临时 runner 上,每个 job 只有最小权限。分支保护、强制评审与签名提交守护源码;签名与 provenance 验证则守护制品通往生产的路径。

如何扩展

流水线容量通过自动伸缩的 runner、远程构建缓存与测试分片来扩展,使构建时间不随代码库增长而增加。可复用的模板让服务数量可以增长,而流水线维护工作不必同比增加。

如何监控

每一次部署都被记录为一个事件,并叠加显示在服务仪表盘上,这样性能或功能退化就能关联到引发它的那次变更。流水线耗时、排队时间、失败原因与 DORA 指标都作为一等的运维数据来跟踪。

如何部署

同一个不可变制品通过 pull request 在各个环境之间晋升,每个阶段都有自动化检查,在生产环境中则渐进式发布。回滚就是 Git 中的一次 revert,或一次自动的流量切换,并且经过演练。

如何集成

流水线通过 API 与 webhook 对接工单系统、即时通讯、制品仓库、密钥存储、漏洞管理与变更管理系统。在需要正式变更审批的场合,流水线自动提供证据,而不是再增加一个人工步骤。

技术

根据工作负载和您现有的技术资产来选择。

  • GitHub Actions
  • GitLab CI
  • Jenkins
  • Argo CD
  • Argo Rollouts
  • Flux
  • Terraform
  • Helm
  • Docker
  • Trivy
  • Semgrep
  • Sigstore Cosign
  • Open Policy Agent
  • Backstage

从零到生产

工程生命周期

  1. 01

    想法

  2. 02

    探索

  3. 03

    系统架构

  4. 04

    UX / 产品设计

  5. 05

    应用工程

  6. 06

    AI / 数据层

  7. 07

    云基础设施

  8. 08

    安全

  9. 09

    质量保证与性能

  10. 10

    部署

  11. 11

    可观测性

  12. 12

    持续演进

常见问题

常见问题

DevOps 与 DevSecOps 有什么区别?

DevOps 把开发与运维整合起来,使软件通过一条自动化、可重复的流水线交付。DevSecOps 则把安全控制放进同一条流水线:代码分析、依赖与镜像扫描、密钥检测、签名与策略执行,都在每一次变更时自动运行。实践中,一套构建得当的交付系统两者兼备,区别只在于侧重点。

加入安全扫描会拖慢我们的流水线吗?

设计得当的话,影响并不明显。增量静态分析与密钥检测在 pull request 上只需数秒;较重的扫描则与测试并行运行,或按计划定时运行。更大的风险是噪声,因此我们会调优规则集与阈值,直到发现的问题足够具体、可以据此采取行动。

你们能基于我们现有的 CI/CD 工具开展工作吗?

可以。这些原则与具体工具无关,而替换一套运转正常的 CI 系统很少是价值最高的改动。我们在你们现有的工具上改进结构、速度与安全性,只有当现有平台阻碍了你们所需的某项能力时,才会建议迁移。

采用 GitOps 一定需要 Kubernetes 吗?

以调谐控制器形式存在的 GitOps 是 Kubernetes 原生的,但其背后的实践在任何地方都适用:期望状态存放在 Git 中,变更通过 pull request 提出,自动应用并检测漂移。面向云资源的 Terraform 流水线和 serverless 部署,不需要集群也可以遵循同样的模型。

你们如何衡量交付是否得到了改善?

使用取自流水线与事故数据的四项 DORA 指标,并与起步时记录的基线对比。我们还会跟踪流水线耗时、不稳定测试的比例,以及工程师等待环境所花的时间,因为这些数据能解释核心指标为何变动。

有一套必须在生产环境中正常运行的系统?

告诉我们您正在构建什么。工程师会阅读您的留言,并在两个工作日内回复。