2. Terraform配置静态检查入门
在 Terraform 工程中,很多问题并不需要真正执行 terraform apply 才能发现。缩进混乱、参数拼写错误、变量类型不匹配、资源属性缺失、Provider 版本约束不合理,这些问题都可以在“静态阶段”被拦截。所谓静态检查,就是在不访问真实云资源、不产生任何基础设施变更的前提下,对配置文件的格式、语法、类型和规范进行校验。本节围绕三个最常用的本地工具展开:terraform fmt、terraform validate 和 tflint,并说明如何把它们组合成本地质量门禁。
三个工具各自解决什么问题
这三个工具并不是互相替代的关系,而是覆盖了从“外观”到“语义”再到“规范”的三层检查。理解它们的边界,才能合理编排执行顺序。
- terraform fmt:只负责代码格式。它会按照 HCL 官方风格调整缩进、对齐等号、规范空格,不检查语义是否正确。它回答的问题是“代码写得整不整齐”。
- terraform validate:负责语法与内部一致性。它会解析配置、检查资源类型是否存在、必填参数是否缺失、变量引用是否合法、表达式类型是否匹配。它回答的问题是“这份配置在 Terraform 看来是否自洽”。
- tflint:负责规范与最佳实践。它能发现 Provider 相关的非法实例规格、未使用的变量、过时的语法、命名不规范等问题。它回答的问题是“这份配置是否符合团队和云厂商的规范”。
三者的检查深度是递进的:格式问题最表层,语法问题居中,规范问题最贴近真实工程约束。因此本地门禁的推荐顺序也是 fmt → validate → tflint,前一层不通过就没有必要进入下一层。
terraform fmt:统一格式,消除无意义差异
terraform fmt 是最轻量的检查。它按照 HCL 官方风格重写文件,主要动作包括:把缩进统一为两个空格、把属性赋值中的等号对齐、规范块之间的空行。它不会改变任何语义,因此可以放心地让它自动修改文件。
在本地使用时,有两种典型模式。第一种是直接修复:
terraform fmt -recursive
加上 -recursive 后,它会递归处理当前目录下所有子目录中的 .tf 和 .tfvars 文件。第二种是只检查不修改,用于门禁场景:
terraform fmt -check -recursive
当存在格式不一致的文件时,该命令会列出文件名并以非零状态码退出。这正是 CI 中需要的“失败信号”。如果团队希望看到具体差异,可以再加 -diff 参数,它会输出类似 git diff 的对比内容,便于快速定位。
terraform validate:语法与内部一致性校验
terraform validate 需要先执行 terraform init,因为它要加载 Provider 的 schema 才能判断资源类型和参数是否合法。它的检查范围包括:HCL 语法是否正确、资源类型是否被 Provider 支持、必填参数是否缺失、变量和输出引用是否指向已声明对象、表达式类型是否匹配。
例如下面这段配置中,instance_type 被写成了 instance_typ,同时 ami 缺失:
resource "aws_instance" "web" {
instance_typ = "t3.micro"
tags = {
Name = "web-server"
}
}
执行 terraform validate 后,会得到类似下面的报错(示例输出,具体措辞随版本略有差异):
Error: Unsupported argument
on main.tf line 2, in resource "aws_instance" "web":
2: instance_typ = "t3.micro"
An argument named "instance_typ" is not expected here.
Error: Missing required argument
on main.tf line 1, in resource "aws_instance" "web":
The argument "ami" is required, but no definition was found.
这两条报错分别对应“参数名拼写错误”和“必填参数缺失”,都是 validate 能稳定捕获的典型问题。修正后再次执行,输出 Success! The configuration is valid. 即表示通过。
terraform validate 不会访问云 API,也不会校验参数取值是否真实存在。例如把 instance_type 写成 t3.microx,validate 可能通过,但 apply 时会失败。这类问题需要交给 tflint 或 plan 阶段处理。
tflint:把规范问题挡在本地
tflint 是第三方静态检查工具,它通过插件机制接入各云厂商的规则集。安装后需要先初始化插件:
tflint --init
然后执行检查:
tflint --recursive
以 AWS 为例,启用 tflint-ruleset-aws 后,它能发现诸如“实例类型不存在”“可用区名称不合法”“未使用的变量声明”“过时的 aws_instance 参数”等问题。下面是一个典型输出示例:
1 issue(s) found:
Warning: "t3.microx" is an invalid EC2 instance type. (aws_instance_invalid_type)
on main.tf line 2:
2: instance_type = "t3.microx"
可以看到,tflint 捕获的正是 validate 无法发现的“取值合法性”问题。此外,tflint 还支持通过 .tflint.hcl 配置文件启用或禁用规则、设置变量值、指定 Provider 版本,使检查结果更贴合项目实际。
组合成本地质量门禁
把三个工具串起来,就形成了一条本地质量门禁。推荐在项目根目录放置一个脚本或 Makefile 目标,按固定顺序执行:
#!/usr/bin/env bash
set -euo pipefail
echo "==> 1/3 格式检查"
terraform fmt -check -recursive
echo "==> 2/3 语法与一致性检查"
terraform init -backend=false
terraform validate
echo "==> 3/3 规范检查"
tflint --init
tflint --recursive
echo "全部静态检查通过"
这里有两个细节值得注意。第一,terraform init 使用了 -backend=false,表示只初始化 Provider 而不连接远程后端,适合在本地和 CI 中快速执行。第二,set -euo pipefail 保证任一命令失败即中断,避免后续检查在错误状态下继续运行。
如果团队使用 Git,可以把这套检查接入 pre-commit 钩子,在提交前自动运行;如果使用 CI,则把它作为流水线的第一个 Job,只有通过后才允许进入 plan 和 apply 阶段。这样,格式、语法和规范问题都会在最早的时间点被拦截,而不是等到部署失败才回头排查。