Sägetstrasse 18, 3123 Belp, Switzerland +41 79 173 36 84 info@ict.technology

      Terraform @Scale - 第3b部分:Blast Radius 恢复策略

      尽管已经采取了精心设计的Blast Radius最小化措施、状态分段以及生命周期防护机制,但意外仍然可能发生:一次 terraform apply 意外删除了生产资源,或者一次 terraform destroy 删除的内容超出了预期范围。

      那么,当事情已经无法挽回时,我们该如何应对?

      在本系列的上一期文章中,我向您介绍了如何最小化Blast Radius。在这篇续篇中,我将展示一些用于恢复受损Terraform状态文件并在事故发生后减少损害的成熟技术。

      1. 心脏手术式急救:State Surgery

      如果资源仍然在物理上存在,但已不再在状态文件中正确引用,那就只能通过命令行进行“手术式”干预了。所谓State Surgery,是指手动清理Terraform状态并使其与现实中的基础设施状态重新对齐的操作方式。 Terraform at scale 8b

      ⚠️ 重要提示:这种做法需要对Terraform内部逻辑以及实际基础设施状态有深入了解。虽然它非常强大,但如果不加谨慎地使用,也非常危险。因此,在进行任何手动修改前,请务必完整备份当前的状态文件!

      您可以使用以下CLI命令备份当前状态:


      $> terraform state pull > state-backup-$(date +%Y%m%d-%H%M%S).json
      

      之后,您可以从状态文件中有选择地移除资源,而不会删除关联的云端资源。在下列示例中,受影响的资源名为aws_instance.problematic_instance


      $> terraform state rm aws_instance.problematic_instance

      接下来,请在Terraform配置文件中为恢复后的资源创建一个新的资源定义(这里我们使用名称aws_instance.recovered_instance)。这可以是一个空的资源块,也可以是旧资源的完整复制粘贴,具体取决于原有资源损坏的程度。
      随后,通过其唯一ID(例如i-1234567890abcdef0),将该资源以新的名称导入回来:


      $> terraform import aws_instance.recovered_instance i-1234567890abcdef0
      

      另一种方法是将状态文件中已存在的资源迁移到新的位置。这可以是基础设施的另一个部分,也可以是不同的Terraform模块:


      $> terraform state mv aws_instance.misplaced_resource aws_instance.correct_scope

      2. 逐步重建:Partial Import 策略

      在复杂场景中 - 例如大型状态文件中的局部故障 - 单纯地执行一次导入通常无法解决问题。在这种情况下,推荐采用结构化、逐步恢复的方式,即使用Partial Import Configurations(Terraform 1.5及以上版本提供)。

      执行流程

      a. 使用 -detailed-exitcode 标识受影响资源

      $> terraform plan -detailed-exitcode

      命令 terraform plan -detailed-exitcode 是 terraform plan 的一个变体,其返回更为详细的退出码,特别适合用于自动化和CI/CD流水线。

      工作原理:

      • terraform plan 通常会显示 Terraform 将对基础设施做出的变更,但并不会实际执行任何操作。
      • 使用 -detailed-exitcode 参数后,退出码的含义会有所改变,使得计划结果可以更细致地解读:
      退出码含义
      0 无任何更改;基础设施已与配置完全一致。
      1 出现错误(例如语法错误、Provider错误等)。
      2 检测到需要变更;计划将对基础设施进行修改。

      提示:退出码2表示存在变更资源,因此需要特别关注。

      这个功能在一些基础教程中未被提及,但在使用Terraform进行工作流自动化的团队中应用非常广泛,可实现更稳健且可预测的基础设施变更流程。

      b. 定义 Import 配置

      现在请为受影响的资源创建配置:


      import {
        to = aws_vpc.recovered_vpc
        id = "vpc-12345678"
      }
      
      import {
        to = aws_subnet.recovered_subnet[0]
        id = "subnet-12345678"
      }

      c. 使用 -generate-config-out 进行自动化导入与配置生成

      命令 terraform plan -generate-config-out=<file> 是一个从 Terraform v1.5 引入的实验性功能。它允许为配置中的 import 块中定义但尚未在当前配置中存在的资源生成 Terraform 配置文件(HCL 格式)。

      该功能在希望将现有基础设施导入 Terraform 时特别有用,它可根据资源的实际状态帮助您生成所需的配置代码。


      $> terraform plan -generate-config-out=generated.tf
      [...] $> terraform apply

       Terraform 执行以下操作:

      • 扫描配置中的 import 块。
      • 对于每个需要导入但尚无配置的资源,Terraform 将尽可能生成包含合适参数与值的 HCL 资源块。
      • 生成的配置将写入指定的文件中(本示例为 generated.tf)。您必须提供一个新的文件路径;若指定现有文件,将导致错误。
      • 命令执行完成后,Terraform 会显示资源导入计划并指出生成的配置文件存储位置。

      terraform plan -generate-config-out=<file> 是一个功能强大的实验工具,可根据 import 块中定义的现有资源生成 Terraform 配置。这使得将未受管理的基础设施纳入 Terraform 管理变得更为轻松。请务必在使用前仔细检查并调整生成的代码。

      d. 现实校验:使用 -refresh-only-refresh=true 进行状态对齐

      Terraform at scale 8d如果 Terraform 状态与实际情况出现偏差,但并无资源缺失,可以通过与实际基础设施的对比来校准状态。这种操作称为 Refresh,它可识别漂移,在某些情况下甚至可自动修复。


      # 状态刷新,但不实施变更
      $> terraform apply -refresh-only
      
      # 与实际基础设施进行比较
      $> terraform plan -refresh=true

      命令 terraform plan -refresh=true 会生成一个执行计划,并在计划生成前强制 Terraform 先更新其状态信息(即执行 refresh 操作)。

      行为细节

      • 默认情况下,Terraform 在执行 terraform plan 时会自动刷新状态文件,与实际基础设施对齐,然后再判断需要哪些变更。
      • 使用 -refresh=true 参数,是明确要求 Terraform 执行这一刷新步骤。虽然这通常是多余的(因为是默认行为),但能确保所有在 Terraform 之外进行的修改(如通过云控制台手动更改)能被发现并体现在计划中。
      • 在刷新过程中,Terraform 会查询所有受管资源的当前状态,并用这些数据更新状态文件。随后将其与配置文件进行比较,以指出需要执行哪些操作(添加、修改、删除)来使实际基础设施与期望配置保持一致。

      与 -refresh=false 的比较

      选项行为
      -refresh=true 状态在计划前与实际基础设施同步(默认行为)。
      -refresh=false 跳过状态同步,可提升执行速度,但可能忽略外部变更。
      e. 脚本中进行配置漂移检测:使用 -detailed-exitcode

      命令 terraform plan -detailed-exitcode 会创建 Terraform 的执行计划,并具有特殊的退出码行为。这种技术特别适合用于CI/CD流水线,或在正式执行 terraform apply 前作为预检查。


      #!/bin/bash
      terraform plan -detailed-exitcode
      if [ $? -eq 2 ]; then
          echo "Configuration drift detected – manual review required"
      fi

      退出码说明

      执行 terraform plan -detailed-exitcode 后,Terraform 将:

      • 显示为使基础设施匹配配置而需要执行的计划操作(添加、修改、删除),但不会进行任何实际更改。
      • 根据计划结果返回特定的退出码:
      退出码含义
      0 无更改;基础设施与配置一致。
      1 发生错误(例如语法错误、Provider 问题等)。
      2 有待执行的更改(将添加、修改或删除资源)。

      结语

      正如您在本文中所见,即便一次 terraform destroy 意外失控,也并非世界末日。
      相反,在 Terraform 出现之前的 IT 时代,通常后果更加严重,因为当时缺乏 Terraform 这样集成的恢复工具。那时常常意味着:“我们现在暂时下线,花上一两天手动重建服务,然后再来看看到底发生了什么。”

      但事实也同样表明,即便借助 Terraform,修复损坏的运行状态(State)以及被误配置或销毁的资源仍然是一项技术复杂度高的工作,且需要专业知识。

      在本系列文章的下一篇中,我们将进一步探讨 Terraform 提供的工具,如何帮助我们提前识别并避免由于 Blast Radius 过大所带来的风险。