持续部署的一个反例

持续部署的一个反例

sjmyuan 29 2023-04-30

部署了什么?

我们已经有三个月没有进行过生产环境部署了,这次要部署五个系统,总共41张故事卡。在这五个系统中,有一个是第一次部署。

发生了什么?

9:00 - 10:00 手动确认部署内容

在部署之前,我们需要先确认这41张故事卡在五个系统中对应的版本号和配置变更。这一步的主要目的是

  1. 确认没有遗漏故事卡
  2. 确认没有引入无关的故事卡
  3. 确认没有遗漏配置变更
  4. 确认没有引入无关的配置变更

版本号的对比确认需要手动进行。我们通常是通过对比生产环境当前版本和待部署版本之间的代码修改来判断版本号是否正确。代码修改的内容则是通过注释中的故事卡号来判断。GitHub提供的版本对比功能可以帮助我们完成该操作。

配置变更的确认比较麻烦,没有工具可以使用。我们需要对故事卡进行逐个检查,确认其是否有配置变更。

10:00 - 10:20 第一次部署失败

在版本号和配置变更确认完成后,我们需要将其更新到一个专门的配置库,部署工具会读取该配置库进行部署。触发部署的流程如下

  1. 在部署工具中点击刷新按钮加载最新的部署配置
  2. 手动对比当前生产环境配置和最新配置的差别
  3. 在确认最新配置没有问题后,点击部署按钮进行部署

我们有两套生产环境互为备份,上述操作需要执行两次。通常我们会在一个环境部署成功后再部署另外一个环境,这样就可以始终保证有一个环境正常工作。

不幸的是,在点击部署按钮后,部署失败了,显示配置错误。

10:20 - 10:25 修复部署工具配置问题

在查看配置错误信息后,我们发现是部署工具无法找到新系统的配置文件。部署工具本身的配置在一个单独的配置库中,我们在确认配置变更时并没有发现有故事卡对其进行了变更。初步判断,原因是团队没有权限修改该配置库,而有权限的人员在收到团队请求后又忘记了修改。

我们临时提交了配置变更,将新系统添加到了部署工具的支持列表中。

10:25 - 10:30 第二次部署失败

在修复了部署工具的配置问题后,我们需要先部署部署工具本身,然后再部署业务系统。 部署工具本身的部署步骤和业务系统一样,也需要在两个生产环境上各部署一次。

幸运并没有降临,在部署工具本身部署成功后,业务系统的部署又失败了。

10:30 - 11:00 修复权限配置问题

错误信息显示新系统的权限有问题。我们有一个单独的配置库来管理系统权限,每个新系统都需要在该配置库中新增其权限配置。我们在确认配置变更时漏掉了新系统的权限配置,原因是机器人把这个配置变更给关掉了,因为它在60天内没有任何操作。

我们重新打开了这个配置变更,配置了新系统的权限,但它并不会自动生效。我们需要触发一条独立的流水线来让权限生效,触发时我们还需要填入一些底层命令的参数。而且如果涉及到生产环境,我们还需要运维人员在流水线上点击批准按钮才能继续运行。

我们触发了流水线,花了 2 分钟联系运维人员批准,又花了 5 分钟等待可用节点,最后花了 5 分钟等待权限生效。然而它失败了,因为我们给的底层命令参数不对。

我们再一次触发了流水线,给了错误中提示的命令参数,又等了 10 分钟后,权限终于生效了。

11:00 - 11:10 部署成功

在权限生效后,我们开始部署系统。在第一个生产环境点击部署后,还是提示相同的失败。这时有人提议可以在第二个生产环境试一下,然后就在第二个生产环境点击了部署,这个环境并没有提示错误,部署开始执行。而执行第一个生产环境部署的人员还在思考失败原因,就又试了一次部署,这次没有错误了,第一个生产环境也开始部署了。

现在我们两个生产环境在同时进行部署,大家只能祈祷不要出问题,否则我们就没有可用的生产环境了。

我们还是幸运的,两个环境都部署成功了,但第一个生产环境的失败原因始终没有找到。

11:10 - 12:30 回归测试

在部署成功后,测试人员开始对生产环境进行手动的回归测试。测试发现了两个问题

  1. 有一个新增功能无法正常工作
  2. 新系统在不断的重启

这5个系统是一起部署的,要回滚只能一起回滚。如果回滚,整个部署就失败了,下次还得把上面的流程重来一遍。所以我们需要立即定位问题原因和影响范围,然后决定是否需要回滚。

定位结果是

  1. 生产环境没有符合条件的数据,无法触发新功能,不需要采取任何措施。
  2. 新系统的内存管理有问题,需要立即修复。但考虑到它是后台定时任务,影响较小,我们可以先通过增加内存的方式降低其重启概率,然后在第二天提交新的版本进行修复,可以不用回滚。

虽然不完美,这次部署总算是完成了,大家又投入到了内存管理问题的修复中,为第二天的部署做准备。

有哪些痛点?

部署时间太长

整个部署花费了三个半小时,部署结束后的第一个感觉就是累。如果再出现其他问题,我们可能不得不回滚这次部署,而下次部署大概率会比这次花费的时间更长。

部署频率太低

低部署频率意味着两次部署的之间的时间间隔很长,在部署时很容易出现配置,权限或部署顺序等问题。这时问题的解决速度也会很慢,因为团队很难回忆起来几个月前的上下文。

在本次部署中就出现了部署工具配置和权限配置问题。

手动操作太多

我们需要手动做下面的事情

  1. 确认版本号
  2. 确认配置变更
  3. 更新版本号和配置变更
  4. 触发两次系统部署
  5. 触发两次部署工具本身的部署
  6. 触发权限部署
  7. 回归测试

在这次部署中,仅前三步就花费了一个小时。

部署流水线太多

我们有三条部署流水线

  1. 系统部署
  2. 部署工具本身的部署
  3. 权限部署

按修改频率排序,由高到低依次为系统部署,权限部署和部署工具本身的部署。

在本次部署中,一次失败是因为遗漏了权限部署,一次失败是因为遗漏了部署工具本身的部署。

权限部署的流水线太慢

在本次部署中,修复权限配置问题占用了半个小时,而我们只改了一行配置。耗时的步骤如下

  1. 等待运维人员批准
  2. 等待可用的执行节点
  3. 等待部署完成

其中第二步最为耗时,可能是因为节点资源分配不足。

各个系统没有独立的水线

在本次部署中,所有系统共享一个部署流水线。在部署时我们将所有系统的版本号和配置变更都更新到系统部署流水线,然后进行部署。如果部署失败,就需要将所有系统进行回滚,增加了部署失败的风险。

可能的解决方案

提高部署频率(Deployment Frequency)

在不改变当前基础设施的情况下,最简单有效的方法就是将不定期的部署转变为按周部署。这样做有下面几个好处

  1. 部署的内容会减少
  2. 部署的时间会缩短
  3. 部署的系统数量会减少,大概率只有一个
  4. 部署风险会降低

缩短交付周期(Lead Time)

按周部署并不能保证每张故事卡都是在完成后的下一周进行部署,这就有可能出现某些故事卡在很长时间后才被部署,还是避免不了部署时间间隔过长的问题。

如果我们可以在每张故事卡完成后的下一周进行部署,有下面几个好处

  1. 遗漏配置的可能性会降低
  2. 出现问题的修复速度会提升
  3. 集成问题的发现时间会提前

引入Feature Toggle

很多时候,我们不希望将开发中的功能呈现给客户,而我们又希望尽早部署故事卡。这时我们可以引入Feature Toggle,隐藏开发中的功能,直到我们决定将其呈现给客户。

引入Feature Toggle后,我们可以

  1. 快速并安全的进行部署
  2. 更灵活的进行部署,例如A/B测试,金丝雀部署等
  3. 快速关闭有问题的功能

一键化部署

将所有与部署相关的步骤放在一条流水线,避免让部署人员输入任何参数,部署人员唯一需要做的就是找到和版本对应的流水线,然后点击一个部署按钮。这样做可以大大降低出错概率,降低部署人员的认知负载。

独立流水线

每个系统都应该有独立的流水线,这样即便有某个系统出现问题也能单独回滚。

提升流水线的性能

流水线的性能包括速度和稳定性,我们应该把提升流水线性能作为技术债进行跟踪管理。快速的流水线可以给我们及时的反馈,减少我们无谓的等待。稳定的流水线可以增加我们部署的信心,减少玄学问题(例如有时成功有时失败)。

总结

持续部署一直是我们团队的目标,但很明显,我们的现状很不乐观。不过,这是一个持续改善的过程,前期我们往往可以找到一些工作量小但效果明显的措施。关键是每一个措施都要能够解决团队的痛点,否则它很难被团队所接受。