Terraform同一代码块内如何引用前序行定义的变量?
问题原因
Terraform 是声明式语言,同一个块(module/resource/locals等)内部的平级参数不存在块内局部作用域,解析参数时不会将同块内其他手动赋值的参数识别为可引用对象。
你在块内写${foo}或者${domain}时,Terraform 只会去全局可引用的命名空间(变量var.*、本地值local.*、其他资源/模块输出、数据源返回值)里查找匹配的对象,根本不会扫描当前块内的其他入参,自然会报引用不存在的错误。
这种设计本质是为了从解析层面避免块内出现循环赋值(比如a = b、b = a这类无解的循环依赖),和过程式语言逐行执行、逐行赋值变量的逻辑完全不同。
符合DRY原则的写法
不要试图在同个块内做参数复用,把需要复用的公共值提前抽到块外的全局可引用位置即可,常用方案有两种:
- 用
locals块定义块级/文件级复用的临时值
这是最通用的方案,不管是module块还是resource块都适用,示例如下:
后续要修改域名只需要改# 提前把要复用的值定义为本地值 locals { domain = "example.com" } module "example" { # 实际使用时替换为你的模块源地址 source = "./modules/your_module" domain = local.domain uri = "https://${local.domain}" }locals里的一处定义,所有引用的地方会自动同步,完全避免重复写死值。 - 用全局输入变量
variable定义跨模块/跨环境复用的固定值
如果这个重复值要在多个资源、多个模块里统一使用(比如环境统一域名、云资源所属区域这类全局配置),可以直接定义为输入变量:variable "main_domain" { type = string default = "example.com" } module "example" { source = "./modules/your_module" domain = var.main_domain uri = "https://${var.main_domain}" }
注意误区
不要把资源/模块创建完成后返回的属性引用,和你手动传入的入参搞混:
你可以在resource块内引用当前资源创建完成后由云厂商返回的属性(比如ECS实例创建完成后返回的公网IP、实例ID),但绝对不能引用自己在同个块内手动传入的入参值,这类入参不会被注册到可引用的命名空间里。
内容的提问来源于stack exchange,提问作者steve
相关产品推荐
相关产品推荐

