3. 现有基础设施的发现与导入策略

把已经运行多年的云上资源纳入 Terraform 管理,难点从来不在“写一条 import 命令”,而在于先搞清楚“现在到底有什么、它们之间是什么关系、哪些该纳管、纳管后配置长什么样”。如果跳过发现阶段直接 import,往往会得到一份与真实资源严重脱节的 state,后续 plan 出现大量意外 diff,反而增加风险。因此本节按“发现 → 生成配置 → 导入 → 校验”的顺序展开,重点讲清每一步的实际做法与判断依据。

一、发现阶段:先建立资源清单,而不是先写代码

发现的目标是得到一份可核对的资源台账,至少包含:资源类型、资源 ID、所属区域/可用区、名称标签、创建时间、依赖关系(如 ECS 属于哪个 VPC/子网、EIP 绑定了哪台实例)。获取方式主要有三类:

  • 云厂商 CLI/SDK 扫描:例如阿里云 aliyun ecs DescribeInstances、AWS aws ec2 describe-instances,可按 region 与 tag 过滤,输出 JSON 后转换为清单。
  • 资源中心/配置审计服务:如阿里云配置审计、AWS Config、Azure Resource Graph,能跨区域、跨产品聚合,适合做全量盘点。
  • 第三方扫描工具:如 terraformer、former2、terracognita,可直接把扫描结果转成 HCL 与 import 脚本。

扫描时建议先按“环境 + 业务系统”打标签过滤,避免把测试、临时、已废弃资源一并纳入。下面是一段以标签筛选并导出实例清单的示例(示例参数,非实测结果):

# 按标签筛选生产环境 ECS,输出精简清单
aliyun ecs DescribeInstances \
  --RegionId cn-hangzhou \
  --Tag.1.Key Env --Tag.1.Value prod \
  --PageSize 100 \
  | jq -r '.Instances.Instance[] | [.InstanceId, .InstanceName, .Status, .VpcAttributes.VpcId] | @tsv'

输出形如 i-bp1xxxx order-api Running vpc-bp1yyyy,即可作为后续导入的输入清单。判断依据很直接:状态为 Running 且带 prod 标签的才进入纳管范围;Stopped 超过 30 天或标签缺失的,先标记为“待确认”,不急于导入。

二、生成配置:让 HCL 与真实资源对齐

terraform import 只把资源写入 state,不会生成 .tf 配置。因此导入前必须先有配置骨架,否则 import 后 plan 会提示“资源已存在但配置缺失”。生成配置有三种常见路径:

  1. 工具自动生成:terraformer 可按资源类型批量生成 HCL 与 import 脚本,适合资源量大、结构规整的场景。
  2. 手工编写 + 占位:先写最小可用配置(仅必填参数),import 后再用 terraform plan 的 diff 反推缺失字段。
  3. 混合方式:自动生成主体,人工修正命名、变量抽取与模块划分,这是生产环境最稳妥的做法。

无论哪种方式,生成后都要做一次“配置与真实资源对齐”检查:把扫描清单中的关键属性(实例规格、镜像 ID、安全组、磁盘类型)与 HCL 逐项比对。若不一致,import 后第一次 plan 就会显示大量变更,说明配置没有反映真实状态。

存量资源纳管:发现 → 生成配置 → 导入 → 校验 ① 发现 云 CLI / SDK 扫描 配置审计 / 资源中心 terraformer 扫描 输出:资源台账 + 依赖关系 ② 生成配置 自动生成 HCL 骨架 变量抽取 / 模块划分 属性与真实资源比对 输出:可 import 的 .tf 配置 ③ 导入 terraform import 批量 import 脚本 state 写入与锁定 输出:state 中的资源映射 ④ 校验 terraform plan 空 diff state list 核对数量 关键属性抽查 输出:纳管完成确认 导入命令示例(单资源) terraform import \ aliyun_instance.order_api \ i-bp1xxxx 导入前:确认 .tf 中已声明该资源块 导入后:立即执行 plan,观察 diff 是否为空 若 diff 非空:回查配置属性,而非直接 apply 禁止:未核对配置就 apply,可能触发重建 导入结果判断路径 plan 输出 diff? 空 diff → 纳管成功 有 diff → 配置偏差 修正 HCL 属性 重新 plan 直至为空 判断依据:plan 无变更 = 配置与真实资源一致 state list 数量应与台账纳管数量一致

三、导入:单资源与批量脚本

单资源导入最直接:先在 .tf 中写好资源块,再执行 import。以阿里云 ECS 为例:

resource "alicloud_instance" "order_api" {
  instance_name        = "order-api"
  instance_type        = "ecs.c6.large"
  image_id             = "centos_7_9_x64_20G_alibase_20220828.vhd"
  security_groups      = ["sg-bp1zzzz"]
  vswitch_id           = "vsw-bp1aaaa"
  availability_zone    = "cn-hangzhou-h"
}

terraform import alicloud_instance.order_api i-bp1xxxx

资源数量多时,手工逐条 import 不现实。可基于扫描清单生成批量脚本,例如把清单转成 import.sh:

#!/usr/bin/env bash
set -euo pipefail
while IFS=$'\t' read -r id name; do
  addr="alicloud_instance.${name//-/_}"
  echo "importing ${addr} <= ${id}"
  terraform import "${addr}" "${id}"
done < instances.tsv

批量导入时要注意两点:一是 state 的并发写入,建议串行执行或使用远程后端加锁;二是导入顺序,先导入 VPC、子网、安全组等被依赖资源,再导入 ECS、RDS 等上层资源,避免引用地址找不到。

四、校验:用 plan 空 diff 作为纳管完成的判据

导入完成后,执行 terraform plan。如果输出 No changes. Your infrastructure matches the configuration.,说明配置与真实资源一致,纳管成功。若出现 diff,不要直接 apply,而应逐项核对:

  • 属性缺失:HCL 中未声明的字段被云上默认值填充,需补全或显式忽略。
  • 属性不一致:如磁盘类型、带宽峰值与真实值不同,需修正 HCL。
  • 只读字段:部分属性由云平台生成,应通过 lifecycle { ignore_changes = [...] } 处理。

最后用 terraform state list 核对资源数量,并与发现阶段的台账逐项比对。建议把“台账数量 = state 数量 = plan 无变更”作为纳管完成的验收标准,形成可复查的闭环。

实践建议:先在一个非核心业务系统上完整走一遍“扫描 → 生成 → 导入 → 校验”,把工具参数、命名规范、模块划分方式固化下来,再推广到核心系统。这样能把风险控制在可回滚的范围内。