🚀 何时使用 terraform apply? — 迁移 vs 漂移修正,两者都正确

Terraform 是一个声明式工具。然而,’何时 apply’ 是一个比想象中复杂得多的问题。

🎯 本文涵盖内容

  • terraform apply 的确切工作原理
  • 迁移场景下 apply 的使用方法
  • 漂移(Drift)发生时 apply 的作用和注意事项
  • 两种情况的区别和共同原则
  • 容易出错的模式和推荐的工作流程

📌 引言: “不就是直接 apply 吗?”

初学 Terraform 时,每个人都会这么想。编写代码,查看 plan,然后 apply — 简单。但在实际运营环境中工作时,就会产生疑问。

“我在控制台直接添加了一条安全组规则… 还能 apply 吗?”

“我想用 Terraform 管理现有基础设施,该从何开始?”

这两个问题正是我们今天要讨论的核心。迁移漂移修正乍一看相似,但性质完全不同,各自有适合的 apply 策略。

🔍 首先需要了解:Terraform 的状态(State)

Terraform 将基础设施的当前状态记录在 .tfstate 文件中。执行 apply 时,它会比较以下三项来决定操作:

比较 对象说明
代码(HCL) 我期望的状态 (desired state)
State 文件 Terraform 已知的状态 (known state)
实际基础设施 云中实际存在的状态 (actual state)

如果这三者一致,apply 将不执行任何操作。当出现不一致时,就需要 apply。


🧳 案例 1: 迁移 — 将现有基础设施导入 Terraform

何时属于此案例?

  • 已存在通过控制台或 CLI 手动创建的基础设施
  • 现在想用 Terraform 将其代码化(IaC化)
  • State 文件中没有该资源

错误方法:编写代码后立即 apply

# ❌ 危险方法
terraform apply

如果为已存在的 S3 存储桶、EC2 实例编写代码后直接 apply,Terraform 会尝试创建新的。如果已存在同名资源,会报错;如果运气不好,现有资源可能会被删除后重新创建,导致事故发生。

正确方法:先 terraform import

# ✅ 正确方法: 先用 import 注册到 State
terraform import aws_s3_bucket.my_bucket my-existing-bucket-name

import 命令将实际基础设施资源注册到 State 文件中。之后运行 plan 检查代码和 State 是否一致,只有在没有差异时才能安全地进行管理。

Terraform 1.5+ : 使用 import 块进行声明式迁移

从 Terraform 1.5 开始,可以直接在 HCL 代码中编写 import 块。

# import.tf
import {
  to = aws_s3_bucket.my_bucket
  id = "my-existing-bucket-name"
}

resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-existing-bucket-name"
  # ... 其他属性
}
# 用 plan 提前确认 import 结果
terraform plan

# 如果没有问题则 apply
terraform apply

在这种方式下,apply 会一次性处理导入 + 代码同步。迁移完成后,import 块可以删除。

迁移中 apply 的推荐时机总结

  1. ✅ terraform import 完成 State 注册后
  2. ✅ terraform plan 显示 No changes 或仅显示预期变更时
  3. ✅ 使用 import 块方式,审查 plan 结果后

🔄 案例 2: 漂移(Drift) — State 与实际基础设施不一致时

什么是漂移?

配置漂移(Configuration Drift)是指 Terraform 管理的资源在代码或 State 之外被更改时发生的情况。

常见原因:

  • 👤 有人直接在控制台修改了安全组规则
  • 🔧 其他团队成员通过 AWS CLI 更改了标签
  • ☁️ 云服务自动更新属性 (例如:EKS 节点组)
현재 상태:
코드(HCL)    →  포트 443만 허용
State 파일   →  포트 443만 허용  (apply 시점 기록)
실제 AWS     →  포트 443 + 8080 허용  ← 누군가 콘솔에서 추가!

在这种状态下运行 terraform plan 会怎样?

terraform plan
# ~ aws_security_group_rule.allow_https will be updated in-place
#   - from_port = 8080  (待删除)

Terraform 将根据代码(HCL)尝试删除 8080 规则

apply 前必须做的事:检测漂移

# 将 State 与实际基础设施同步以检测漂移
terraform refresh

# 或与 plan 一起
terraform plan -refresh-only

-refresh-only 标志只将实际基础设施状态反映到 State 中,而不更改基础设施。这对于了解漂移发生在哪里以及如何发生非常有帮助。

漂移处理策略:两种选择

策略 A: 更新代码以符合实际 (接受漂移)

如果控制台中添加的更改是故意的,则更新代码并 apply。

# 在代码中添加 8080 规则
resource "aws_security_group_rule" "allow_8080" {
  type        = "ingress"
  from_port   = 8080
  to_port     = 8080
  protocol    = "tcp"
  cidr_blocks = ["10.0.0.0/8"]
  security_group_id = aws_security_group.main.id
}
terraform plan   # 确认
terraform apply  # 使代码与实际状态一致

策略 B: 将基础设施恢复到代码基准 (消除漂移)

如果是未经授权的更改,则通过 apply 恢复到基于代码的状态。

# 不修改代码直接 apply
terraform apply
# → 8080 规则被移除并恢复到代码状态

漂移场景中 apply 的推荐时机总结

  1. ✅ 使用 terraform plan -refresh-only 了解漂移范围后
  2. ✅ 判断漂移是故意的还是未经授权的更改后
  3. ✅ 决定采用策略 A (更新代码) 或策略 B (恢复原状) 后
  4. ❌ 不了解漂移原因就盲目 apply 是不可取的

⚠️ 注意事项: apply 前务必检查的事项

1. 没有 plan 的 apply 是事故的捷径

# ❌ 绝对禁止模式
terraform apply -auto-approve

即使在 CI/CD 自动化中,也必须包含人工审查 plan 结果的步骤。

2. 绝不能手动编辑 State 文件

如果发生漂移,直接修改 .tfstate 文件会导致更大的问题。务必使用 terraform state 命令。

# 从 State 中移除特定资源 (保留基础设施)
terraform state rm aws_s3_bucket.old_bucket

# 在 State 中查看资源列表
terraform state list

3. 使用远程 State 是必需而非可选

在团队环境中,使用本地 State 会使漂移和冲突成为常态。

# 使用 S3 + DynamoDB 配置远程 State
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "ap-northeast-2"
    dynamodb_table = "terraform-lock"
    encrypt        = true
  }
}

4. 在生产环境中尽量减少使用 target 标志

# ⚠️ 除非紧急情况,否则避免使用
terraform apply -target=aws_instance.web

只选择特定资源进行 apply 可能会导致依赖关系混乱。


✅ 总结: 迁移 vs 漂移,有何不同?

区分 迁移 漂移修正

区分 迁移 漂移修正
情况 将现有基础设施纳入 Terraform 管理 管理中的基础设施在外部被更改
State 状态 该资源没有 State State 与实际基础设施不一致
apply 前操作 terraform import 或 import 块 terraform plan -refresh-only
apply 目的 同步代码和 State 恢复到代码基准或更新代码后同步
风险等级 高 (可能误删/重建) 中 (可能应用非预期更改)

结论:两者都使用 apply。但流程不同。

terraform apply 只是一个工具。无论是迁移还是漂移修正,核心都是在 apply 之前查看 plan,并在理解将发生何种更改的情况下执行。Terraform 的真正威力并非来自 apply 命令的一行,而是来自之前执行的 plan 和 refresh。



Comments

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注