摘要: 无人值守部署依赖自动化持续交付流水线,通过代码审查、自动化测试、预生产验证、one-box 测试、分波次部署、指标监控、自动回滚和流水线即代码等机制,在提升软件交付效率的同时降低生产发布风险。本文将介绍一套安全自动化部署体系如何帮助开发团队减少人工干预,并更稳定地将代码变更发布到生产环境。

简介
当我参加海外某大型科技公司的工作面试时,曾重点问过一位面试官:“你们多久向生产环境部署一次?”
当时,我正在开发一款产品。这个产品每年会发布一到两个主要版本,但有时我也需要在主要版本之间发布一些小型修复补丁。每次发布补丁,我都要花几个小时谨慎地推进上线。部署之后,我还会紧张地查看日志和指标,确认这次发布是否破坏了什么功能,以及是否需要回滚。
我之前读到过,这家公司会实践持续部署。因此,在面试时,我很想知道,如果成为这里的开发人员,我需要花多少时间来管理和监控部署。面试官告诉我,代码变更会通过持续部署流水线每天多次自动部署到生产环境。
于是我又问他:每天需要花多少时间来小心管理每一次部署,并像我过去那样密切查看日志和指标,确认是否产生影响?他告诉我,通常不需要花任何时间。因为流水线会替他的团队完成这些工作,大多数部署并不需要任何人主动监控。
“哇!”我当时这样感叹。加入这家公司之后,我才真正体会到,这种“无人值守”的自动化部署有多令人兴奋。
安全的持续部署实践
后来,我亲眼看到这家公司如何通过持续部署流水线,帮助团队快速且安全地完成部署。我非常欣赏这里的持续部署安全实践,因为它们能把开发人员从繁重的部署工作中解放出来。
当我把生产代码推送到服务源代码仓库的主分支后,通常就可以把这件事放下,继续处理下一项任务。与此同时,我所在团队的流水线会替我把相关变更发布到生产环境。将代码变更发布到生产服务,完全由流水线自动完成。这意味着,我或其他开发人员最后一次修改或查看代码,通常就是代码变更被合并到源代码仓库的时候。
我们的团队在流水线中设置了自动化步骤,用来安全地将变更部署到生产环境,因此我们不需要监控每一次部署。流水线会让最新变更经过一系列测试和部署安全检查。这些自动化步骤能够阻止会影响客户的缺陷进入生产环境;即使缺陷真的进入了生产环境,也能限制它对客户造成的影响。
作为开发人员,我可以信任这条流水线。它会以谨慎且安全的方式,替我把变更部署到生产环境,而不需要我主动盯着整个过程。
持续交付之旅
这家公司并不是一开始就拥有这样的持续交付能力。过去,这里的开发人员也需要花几个小时,甚至几天时间,来管理代码部署到生产环境的过程。
后来,我们在整个公司范围内采用持续交付,用自动化、标准化的方式部署软件,并减少将变更发布到生产环境所需的时间。发布流程的改进并不是一蹴而就的,而是随着时间逐步积累起来的。
我们识别部署过程中的风险,并通过流水线中的新自动化安全措施来缓解这些风险。我们也会持续迭代发布流程,不断识别新的风险,并寻找新的方法来提高部署安全性。
如需进一步了解这类持续交付实践,以及相关团队如何持续改进,可以参考海外某技术文库中关于采用持续交付、加快交付进度的相关文章。
持续交付流水线的四个阶段
在本文中,我们将展示一次代码变更如何通过流水线进入生产环境。典型的持续交付流水线包括四个主要阶段:源代码、构建、测试和生产。
接下来,我们将详细介绍一个典型云服务在各个流水线阶段中会经历什么,并通过示例说明一个典型云服务团队如何设置自己的流水线。

源代码与构建
下面先简要介绍在典型云服务团队的流水线中,源代码和构建阶段通常包含哪些步骤。

流水线源代码
流水线会自动验证各种类型的源变更,并将其安全地部署到生产环境中。这些变更并不只包括应用程序代码,也包括网站静态资源、工具、测试、基础设施、配置,以及应用程序底层操作系统等内容。
所有这些变更都会在独立的源代码仓库中进行版本控制。源代码依赖项,例如库、编程语言,以及机器镜像 ID 等参数,至少每周会升级一次,并自动更新到最新版本。
这些源变更会通过独立流水线进行部署,并使用与应用程序代码部署相同的安全机制,例如自动回滚。举例来说,服务中可能在运行时变化的配置值,例如 API 速率限制提升和功能开关,会通过专门的配置流水线自动部署。如果源变更导致服务在生产环境中出现问题,例如配置文件无法解析,那么该源变更会被自动回滚。
一个典型微服务可能会拥有多条流水线,包括应用程序代码流水线、基础设施流水线、操作系统补丁流水线、配置或功能开关流水线,以及运维工具流水线。
同一个微服务拥有多条流水线,可以帮助我们更快地将不同类型的变更部署到生产环境。例如,一个应用程序代码变更如果没有通过集成测试,阻塞了应用程序流水线,它并不会影响其他流水线。也就是说,它不会阻止基础设施代码变更进入基础设施流水线的生产阶段。
同一个微服务的所有流水线通常看起来都非常相似。例如,功能开关流水线会使用与应用程序代码流水线相同的安全部署技术,因为错误的功能开关配置变更和错误的应用程序代码变更一样,都可能影响生产环境。
在企业落地这类持续交付实践时,流水线本身只是研发管理体系的一部分。比如 PingCode 这类智能化研发管理工具,可以将团队目标、客户反馈、需求清理、评审排期、开发、测试、发布上线和 Wiki 知识沉淀等环节串联起来,并打通研发过程中使用的其他工具,让需求、代码、测试、发布和经验数据在研发链路中顺畅流转,从而进一步提升研发效能。
代码审查
所有即将部署到生产环境的变更,都必须从代码审查开始。变更必须得到团队成员批准之后,才能合并到主线分支,也就是我们的“main”或“trunk”版本。合并到主线分支后,流水线会自动启动。
流水线会强制要求:所有合并到主线分支的提交都必须经过代码审查,并得到该流水线所属服务团队成员的批准。任何未经审查的提交,都会被流水线阻止部署。
对于完全自动化的流水线而言,代码审查是代码变更部署到生产环境前,最后一次接受工程师人工审查和批准。因此,这是一个关键步骤。
代码审查人员会评估代码的正确性,也会评估该变更是否能够安全地部署到生产环境。他们会判断代码是否经过充分测试,包括单元测试、集成测试和 Canary 测试;是否具备足够的监控能力,以便在部署期间观察;以及是否可以安全回滚。
有些团队会使用自定义检查清单,并自动将其添加到每次代码审查中,明确提醒审查人员检查部署安全性问题。下面是一个示例。
代码审查检查清单示例
测试
- 你是否为此次变更编写了新的单元测试?
- 你是否为此次变更编写了新的集成测试?
请列出你在本地运行过、用于测试此次变更的命令:mvn test && mvn verify
监控
- 现有监控是否能够覆盖此次变更?
- 是否不需要添加新的 Canary、指标、仪表盘或告警?
- 此次变更是否会对资源或限制产生影响,或者带来积极影响?
- 包括 CPU、内存、云资源、对其他服务的调用等。
- 此次变更是否可以在不触发任何告警的情况下部署到生产环境?
发布
- 此次变更在获批后,是否可以立即合并并进入流水线?
- 所有依赖变更是否已经部署到生产环境?
- 此次变更部署到生产环境后,是否可以无风险回滚?
构建测试和单元测试
代码会在构建阶段完成编译和单元测试。构建工具和构建逻辑会因编程语言不同而有所差异,甚至不同团队之间也会有所不同。
例如,团队可以选择最适合自己的单元测试框架、Linter 和静态分析工具。团队也可以自行配置这些工具,例如在单元测试框架中设置可接受的最低代码覆盖率。
流水线中运行的测试工具和测试类型,也会因部署代码的类型不同而不同。例如,应用程序代码会运行单元测试,而基础设施即代码模板则会运行 Linter。
所有构建在运行时都不会连接网络,这样可以隔离构建过程,并支持构建结果的可复现性。通常情况下,单元测试会模拟所有对依赖项的 API 调用,例如对其他云服务的调用。与真实、未模拟依赖项的集成,会在后续流水线的集成测试阶段进行测试。
与集成测试相比,基于模拟依赖项的单元测试更适合覆盖极端情况,例如 API 调用返回意外错误,并确保代码能够妥善处理这些错误。
构建完成后,编译后的代码会被打包并签名。
在预生产环境中测试部署
在部署到生产环境之前,流水线会将变更部署到多个预生产环境中进行验证,例如 Alpha、Beta 和 Gamma。
Alpha 和 Beta 通过运行功能 API 测试和端到端集成测试,验证最新代码是否按预期工作。Gamma 则用于验证代码既能正常工作,又能够安全部署到生产环境。
Gamma 与生产环境高度相似,包括相同的部署配置、相同的监控和告警,以及相同的持续 Canary 测试。Gamma 也会部署到多个云服务区域中,以捕获任何可能由区域差异造成的潜在影响。
集成测试
集成测试帮助我们在流水线中自动使用服务,就像客户使用服务一样。这些测试会在真实基础设施上运行,通过调用真实 API,在所有有意义的客户场景中对整个技术栈进行端到端测试。
集成测试的目标,是在部署到生产环境之前,捕获服务中所有意外或错误的行为。
虽然单元测试针对模拟依赖项运行,但集成测试针对调用真实依赖项的预生产系统运行,用于验证我们对这些依赖项行为方式的模拟假设是否正确。
集成测试会验证单个 API 对不同输入的行为,也会验证由多个 API 组成的完整工作流。例如,创建一个新资源、描述该资源,等待资源准备就绪,然后使用该资源。
集成测试既会运行正向测试用例,也会运行负向测试用例。例如,向 API 提供无效输入,并检查它是否按预期返回“输入无效”错误。
有些流水线还会运行模糊测试,生成多种可能的 API 输入,并验证这些输入不会导致服务出现内部故障。还有些流水线会在预生产阶段运行短时间负载测试,以确保最新变更不会在实际负载水平下导致延迟或吞吐量回退。
向后兼容性和 one-box 测试
在部署到生产环境之前,我们需要确保最新代码具有向后兼容性,并且能够安全地与当前代码一起部署。
例如,我们需要检测最新代码是否会使用当前代码无法解析的格式写入数据。Gamma 中的 one-box 阶段,会将最新代码部署到最小部署单元中,例如一台虚拟机、一个容器,或一小部分云函数调用。
在这个 one-box 部署阶段,Gamma 环境中的其余资源仍会运行当前代码一段时间,例如 30 分钟或 1 小时。流量不一定需要专门定向到这个 one-box。它可以被加入到与 Gamma 环境其余资源相同的负载均衡器中,也可以轮询同一个队列。
例如,在一个负载均衡器后面有 10 个容器的 Gamma 环境中,one-box 会接收持续 Canary 测试所生成的 10% Gamma 流量。one-box 部署会监控 Canary 测试成功率和服务指标,以检测由部署本身,或由新旧代码并排运行的“混合”队列所带来的任何影响。

我们还需要确保最新代码能够与依赖项保持向后兼容,例如某些变更是否需要在多个微服务之间按特定顺序发布。
预生产环境中的微服务通常会调用其他团队拥有服务的生产端点,例如对象存储服务或托管 NoSQL 数据库服务;但它们会调用同一团队其他微服务在相同阶段的预生产端点。例如,一个团队在 Gamma 中的微服务 A,会调用同一团队在 Gamma 中的微服务 B,但会调用对象存储服务的生产端点。
有些流水线还会在一个称为 Zeta 的单独向后兼容性阶段再次运行集成测试。Zeta 是一个独立环境,在这个环境中,每个微服务只调用生产端点,用来测试即将进入生产环境的变更,是否与当前已经部署在生产环境中的多个微服务代码兼容。
例如,Zeta 中的微服务 A 会调用微服务 B 的生产端点,以及对象存储服务的生产端点。
如需了解如何编写和部署向后兼容变更,可以参考海外某技术文库中关于确保部署期间回滚安全的相关文章。
生产部署
在进行生产部署时,我们的首要目标,是防止一次变更同时对多个区域,或同一区域中的多个可用区造成负面影响。
限制每次单独部署的范围,可以限制生产部署失败对客户造成的潜在影响,并防止它扩散到多个可用区或多个区域。
为了限制自动化部署范围,我们会将流水线的生产阶段拆分成多个阶段,并将部署拆分到单个区域中。团队还会通过部署到单个可用区,或服务的单个内部分区,也就是单元,来进一步缩小区域部署范围,从而进一步限制生产部署失败可能造成的影响。
交错部署:在安全性与交付速度之间取得平衡
每个团队都需要在小范围部署的安全性,与向所有区域客户交付变更的速度之间做权衡。
如果通过流水线一次性将变更部署到 24 个区域或 76 个可用区,造成广泛影响的风险最低,但流水线可能需要数周时间才能将变更交付给全球客户。我们发现,将部署分组成规模不断扩大的波次,也就是 wave,有助于在部署风险和速度之间取得良好平衡。
流水线中的每个 wave 阶段,都会把部署编排到一组区域中。变更会从一个 wave 推进到下一个 wave,不断扩大范围。新的变更可以随时进入流水线的生产阶段。
在 wave 1 中,当一组变更从第一步推进到第二步之后,下一组变更就可以从 Gamma 推进到 wave 1 的第一步。这样,我们就不会让大量变更一直等待部署到生产环境。
流水线中的前两个 wave 对建立变更信心最为关键。
第一个 wave 会部署到请求量较小的区域,以限制新变更首次进入生产环境时的潜在影响范围。在该区域内,wave 一次只部署到一个可用区或单元,以谨慎地在区域内推进变更。
第二个 wave 会一次部署到一个请求量较大的区域中的一个可用区或单元。客户很可能会在这里使用到所有新的代码路径,因此我们也可以在这里更充分地验证变更。
当初始部署 wave 已经推进,并且我们对变更安全性建立了更高信心后,就可以在同一 wave 中并行部署到更多区域。
例如,一个典型生产流水线可能在 wave 3 中部署到三个区域,在 wave 4 中部署到最多 12 个区域,然后在 wave 5 中部署到剩余区域。每个 wave 中具体包含哪些区域、包含多少区域,以及服务团队流水线中有多少个 wave,都取决于单个服务的使用模式和规模。
流水线后续的 wave 仍然有助于防止同一区域中的多个可用区同时受到负面影响。当一个 wave 并行部署到多个区域时,它会在每个区域中遵循与初始 wave 相同的谨慎部署方式。wave 中的每个步骤,都只会部署到该 wave 内每个区域的单个可用区或单元。
One-box 和滚动部署
每个生产 wave 的部署都会从 one-box 阶段开始。
与 Gamma 的 one-box 阶段类似,每个生产 one-box 阶段都会将最新代码部署到该 wave 中某个区域或可用区的一个实例中,例如一台虚拟机、一个容器,或一小部分云函数调用。
生产 one-box 部署会先限制该 wave 中由新代码处理的请求数量,从而最大限度降低变更对该 wave 的潜在影响。通常,一个 one-box 最多只服务该区域或可用区总请求量的 10%。
如果变更在 one-box 中造成负面影响,流水线会自动回滚该变更,并且不会将它扩展到生产环境的其余阶段。
在 one-box 阶段之后,大多数团队会使用滚动部署,将变更部署到该 wave 的主要生产队列中。滚动部署可以确保服务在整个部署过程中,仍然拥有足够容量来处理生产负载。它会控制新代码投入使用的速度,也就是新代码开始处理生产流量的速度,从而降低变更影响。
通常,在区域级滚动部署中,每次最多会将该区域中 33% 的服务实例替换为新代码。这些实例可能是容器、云函数调用,或运行在虚拟机上的软件。
部署过程中,部署系统会先选择第一批最多 33% 的实例,用新代码进行替换。在替换期间,至少有 66% 的总容量保持健康运行,并可以继续处理请求。所有服务都会按能够承受区域内失去一个可用区的情况进行容量规划,因此我们知道服务仍能以这部分容量处理生产负载。
当部署系统确认第一批实例中的某个实例已经通过健康检查后,剩余队列中的另一个实例就可以被新代码替换,以此类推。与此同时,我们始终保持至少 66% 的容量可用于处理请求。
为了进一步限制变更影响范围,有些团队的流水线一次只部署 5% 的实例。但它们随后会执行快速回滚:一旦需要回滚,系统会一次性用旧代码替换 33% 的实例,从而加快回滚速度。

指标监控和自动回滚
通常情况下,在流水线自动部署过程中,不会有开发人员主动监控每个生产部署、检查指标,并在发现问题时手动回滚。部署完全可以无人值守。
部署系统会主动监控告警,以确定是否需要自动回滚部署。回滚会将环境切换回之前部署的容器镜像、云函数部署包,或内部部署包。我们的内部部署包与容器镜像类似:它们都是不可变的,并使用校验和验证完整性。
每个区域中的每个微服务,通常都会配置一个高严重级别告警。这个告警会基于影响客户的指标触发,例如故障率和高延迟;也会基于系统健康指标触发,例如 CPU 利用率。下面是一个示例。
如果部署正在进行,这个高严重级别告警会同时用于通知值班工程师和自动回滚服务。通常,当值班工程师收到通知并开始处理时,回滚已经在进行了。
高严重级别微服务告警示例
ALARM(“FrontEndApiService_High_Fault_Rate”) OR ALARM(“FrontEndApiService_High_P50_Latency”) OR ALARM(“FrontEndApiService_High_P90_Latency”) OR ALARM(“FrontEndApiService_High_P99_Latency”) OR ALARM(“FrontEndApiService_High_Cpu_Usage”) OR ALARM(“FrontEndApiService_High_Memory_Usage”) OR ALARM(“FrontEndApiService_High_Disk_Usage”) OR ALARM(“FrontEndApiService_High_Errors_In_Logs”) OR ALARM(“FrontEndApiService_High_Failing_Health_Checks”)
部署引入的变更可能影响上游和下游微服务。因此,部署系统不仅需要监控正在部署的微服务的高严重级别告警,还需要监控该团队其他微服务的高严重级别告警,以决定何时回滚。
部署变更也可能影响持续运行的 Canary 测试指标,因此部署系统还需要监控失败的 Canary 测试。
为了能够自动回滚所有这些可能受到影响的领域,团队会创建一个高严重级别聚合告警,供部署系统监控。高严重级别聚合告警会将团队所有高严重级别单个微服务告警状态,以及 Canary 告警状态,汇总成一个聚合状态。下面是一个示例。
如果团队中任何微服务的高严重级别告警进入告警状态,那么该团队在该区域所有微服务中正在进行的所有部署都会自动回滚。
高严重级别聚合回滚告警示例
ALARM(“FrontEndApiService_High_Severity”) OR ALARM(“BackendApiService_High_Severity”) OR ALARM(“BackendWorkflows_High_Severity”) OR ALARM(“Canaries_High_Severity”)
one-box 阶段只承载总流量中的一小部分,因此 one-box 部署引入的问题可能不会触发该服务整体的高严重级别回滚告警。
为了及时捕获并回滚那些在 one-box 阶段导致问题、但尚未扩展到其他生产阶段的变更,one-box 阶段还会针对仅限于这一个实例的指标进行回滚判断。例如,它会监控专门由这个 one-box 处理的请求错误率,而这些请求只占总请求量的一小部分。
One-box 回滚告警示例
ALARM(“High_Severity_Aggregate_Rollback_Alarm”) OR ALARM(“FrontEndApiService_OneBox_High_Fault_Rate”) OR ALARM(“FrontEndApiService_OneBox_High_P50_Latency”) OR ALARM(“FrontEndApiService_OneBox_High_P90_Latency”) OR ALARM(“FrontEndApiService_OneBox_High_P99_Latency”) OR ALARM(“FrontEndApiService_OneBox_High_Cpu_Usage”) OR ALARM(“FrontEndApiService_OneBox_High_Memory_Usage”) OR ALARM(“FrontEndApiService_OneBox_High_Disk_Usage”) OR ALARM(“FrontEndApiService_OneBox_High_Errors_In_Logs”) OR ALARM(“FrontEndApiService_OneBox_Failing_Health_Checks”)
除了回滚服务团队定义的告警之外,我们的部署系统还可以检测并自动回滚内部 Web 服务框架发出的常见指标异常。
我们的大多数微服务都会以标准格式发出请求计数、请求延迟和故障计数等指标。借助这些标准指标,部署系统可以在部署过程中出现指标异常时自动回滚。例如,请求计数突然下降到零,或者延迟、故障数量显著高于正常水平。
观察期:识别慢热影响
部署造成的负面影响有时不会立即显现出来。这类影响可以称为“慢热影响”:影响不会在部署过程中马上出现,尤其是在服务当时负载较低的情况下。
如果完成部署后立即将变更推进到流水线的下一个阶段,那么当影响在第一个区域显现出来时,可能已经有多个区域受到影响。
因此,在将变更推进到下一个生产阶段之前,流水线中的每个生产阶段都会设置一段观察期,也就是 bake time。在这段时间内,流水线会在完成部署后、进入下一阶段之前,继续监控团队的高严重级别聚合告警,以确认是否存在任何慢热影响。
为了确定部署观察期的长度,我们需要权衡两类风险:一类风险是过快将变更推进到多个区域,从而造成更大范围影响;另一类风险是过长观察期会降低向全球客户交付变更的速度。
我们发现,一个较好的平衡方式是:在流水线较早的 wave 中设置较长观察期,等我们对变更安全性建立信心后,再在较晚的 wave 中缩短观察期。我们的目标,是最大限度降低多个区域同时受到影响的风险。
由于大多数部署不会由团队成员主动监控,典型流水线的默认观察期会比较保守。变更通常会在大约 4 到 5 个工作日内部署到所有区域。对于规模较大或至关重要的服务,观察期以及流水线在全球范围内部署变更所需的时间会更加保守。
典型流水线会在每个 one-box 阶段之后等待至少 1 小时,在第一个区域 wave 之后等待至少 12 小时,在其余区域 wave 之后等待至少 2 到 4 小时,并且会为单个区域、可用区以及每个 wave 中的单元留出额外观察时间。
观察期还可能包含特定数据点数量要求。例如,“等待至少 100 个 Create API 请求”。这样可以确保已经发生足够多的请求,使新代码得到充分执行。
在整个观察期内,如果团队的高严重级别聚合告警进入告警状态,部署就会自动回滚。
虽然这种情况很少见,但有时我们确实需要比正常观察和部署节奏更快地向客户交付紧急变更,例如安全修复,或缓解影响服务可用性的大型事件。
在这种情况下,我们可以缩短流水线观察期,以加快部署速度。但我们需要对这类变更进行严格审查。对于这种情况,我们要求组织内的首席工程师进行审查。团队必须与经验丰富、具备运行安全专业能力的开发人员合作,共同审查代码变更、紧迫性以及造成影响的风险。
这些变更仍然会遵循流水线中与平时相同的步骤,只是会更快推进到下一阶段。为了管理加速部署带来的风险,我们会限制这段时间内流水线中运行的变更,只允许解决当前问题所需的最小代码变更进入流水线。此外,我们还会主动监控部署。
告警和时间窗口拦截器
当负面影响风险较高时,流水线会阻止自动部署到生产环境。流水线使用一组“拦截器”来评估部署风险。
例如,当环境中存在尚未解决的问题时,如果自动将新变更部署到生产环境,可能会造成更严重或更持久的影响。因此,在开始任何生产阶段的新部署之前,流水线会检查团队的高严重级别聚合告警,以判断是否存在未解决的问题。
如果告警当前处于告警状态,流水线会阻止变更继续推进。流水线也可以检查整个组织范围内的告警,例如大型事件告警。这类告警可能表明另一个团队的系统存在广泛影响,因此流水线会阻止启动可能造成更多整体影响的新部署。
如果必须将某个变更部署到生产环境,以便从高严重级别问题中恢复,开发人员可以覆盖这些部署拦截器。
此外,我们也会为流水线配置一组时间窗口,用来定义何时允许开始部署。
配置时间窗口时,我们需要权衡两方面风险。一方面,如果时间窗口非常小,变更可能会在时间窗口关闭期间堆积在流水线中,从而增加下一次时间窗口打开时,大量变更一起部署并造成影响的可能性。另一方面,如果时间窗口非常大,覆盖了正常工作时间之外的时段,那么部署失败造成持续影响的风险就会增加。
在下班时间,与白天相比,联系值班工程师和其他团队成员通常需要更长时间。而在正常工作时间内,如果部署失败后需要执行任何手动恢复步骤,团队可以更快地被联系到。
大多数部署不会由团队成员主动监控。因此,如果自动回滚后仍然需要手动操作,我们会优化部署时间安排,尽可能缩短联系值班工程师所需的时间。
夜间、办公假期和周末通常不包含在部署时间窗口内,因为这些时间联系值班工程师往往更慢。根据服务的使用模式,有些问题可能在部署数小时后才显现出来。因此,许多团队的时间窗口还会排除周五和较晚的下午时段,以降低部署后需要在夜间或周末联系值班工程师的风险。
我们发现,即使在需要手动操作的情况下,这组时间窗口也能实现快速恢复,同时尽量减少工作时间之外对值班工程师的打扰,并确保在时间窗口关闭时,不会积累过多变更一起部署。
流水线即代码
典型的云服务团队会拥有许多流水线,用于部署团队的多个微服务和多种源类型,例如应用程序代码、基础设施代码、操作系统补丁等。
每条流水线又会针对不断增加的区域和可用区设置许多部署阶段。这意味着团队需要管理大量配置,包括流水线系统、部署系统和告警系统中的配置。此外,团队还需要投入大量精力,跟上技术演进,实施最新最佳实践,并及时支持新的区域和可用区。
过去几年里,我们一直在积极实践一种更简单、更一致的方法:流水线即代码。也就是说,以代码形式对配置建模,并由这些配置生成安全且最新的流水线。
我们的内部流水线即代码工具,会从区域和可用区的集中列表中拉取信息,使新的区域和可用区能够轻松添加到整个组织的流水线中。
这个工具还允许团队通过继承来对流水线建模。团队可以在父类中定义流水线的通用配置,例如哪些区域进入每个 wave、每个 wave 应该设置多长观察期;然后将所有微服务流水线配置定义为继承这些通用配置的子类。
结论:安全自动化部署需要流水线能力体系化
在这家海外大型科技公司,我们基于多种因素,逐步建立起自动化部署安全实践,以平衡部署安全性和部署速度。同时,我们也希望最大限度减少开发人员因为担心部署而投入的时间。
通过广泛的生产前测试、自动回滚和交错式生产部署,我们在发布流程中以自动化方式保障部署安全,从而尽可能降低部署对生产环境造成的影响。这意味着,开发人员无需主动监控生产部署。
借助完全自动化的流水线,开发人员可以通过代码审查来检查代码,并批准已经准备好进入生产环境的变更。变更合并到源代码仓库之后,开发人员就可以继续处理下一项任务,而不必再为部署操心。可信赖的流水线会以安全、谨慎的方式将变更推向生产环境。
这种自动化流水线能够在一天之内多次持续部署到生产环境,同时兼顾安全性和速度。云服务团队以代码形式对持续交付实践进行建模,从而能够以前所未有的简便方式设置流水线,并安全地自动部署代码变更。
了解更多内容
如需进一步了解这类大型科技公司如何在提高客户满意度和开发人员工作效率的同时,提高服务安全性和可用性,可以参考关于采用持续交付、加快交付进度的相关文章。
如需了解如何编写和部署向后兼容变更,可以参考海外某技术文库中关于确保部署期间回滚安全的相关文章。
文章包含AI辅助创作:如何实现安全的无人值守部署:自动化流水线、回滚与持续交付实践,发布者:shang,转载请注明出处:https://worktile.com/kb/p/3974276
微信扫一扫
支付宝扫一扫