使用Terraform template_file传递数组至脚本时渲染失败求助
问题:Terraform传递数组至EC2用户数据脚本报错及正确实现
问题场景
尝试通过Terraform的template_file将数组传递到EC2实例的用户数据脚本中,相关代码及执行terraform plan时的报错如下:
Terraform代码
variable "services" { type = list(string) default = ["Service1", "Service2", "service3"] } variable "passwords" { type = list(string) default = ["Password1", "Password2", "Password3"] } data "template_file" "configure" { template = "${file("${path.module}/init/configure")}" vars = { services = join(",",var.services) passwords = join(",",var.passwords) } } resource "aws_instance" "grafana_nodes" { ... user_data = data.template_file.config ... }
用户数据脚本(init/configure)
#!/bin/bash declare -a services_array services_array=($(echo "${services}" | tr "," " ")) declare -a passwords_array passwords_array=($(echo "${passwords}" | tr "," " ")) sudo echo "${services_array[@]}" >> /tmp/isp_services_array.txt sudo echo "${passwords_array[@]}" >> /tmp/influx_db_passwords_array.txt
报错信息
Error: failed to render : <template_file>:8,29-30: Invalid character; This character is not used within the language., and 2 other diagnostic(s) │ │ with module.mymodule.data.template_file.configure, │ on modules/mymodule/main.tf line 417, in data "template_file" "configure": │ 417: data "template_file" "configure" {
错误原因
- 模板语法错误:
template = "${file("${path.module}/init/configure")}"中嵌套的双引号导致Terraform解析失败。Terraform 0.12+版本中,file()函数本身已是插值表达式,无需再嵌套${}。 template_file已被弃用:Terraform官方推荐使用内置的templatefile()函数替代data "template_file",后者属于旧版资源,语法限制更多。- 资源引用错误:
aws_instance中user_data引用的data.template_file.config是错误的,template_file资源的正确输出字段为rendered。
正确实现方式
方式一:修复现有template_file配置
修改data "template_file"的语法错误及资源引用:
data "template_file" "configure" { template = file("${path.module}/init/configure") # 移除外层多余的${} vars = { services = join(",",var.services) passwords = join(",",var.passwords) } } resource "aws_instance" "grafana_nodes" { ... user_data = data.template_file.configure.rendered # 修正为正确的输出字段 ... }
方式二:使用推荐的templatefile()函数(更健壮)
直接用templatefile()替代旧的template_file资源,同时优化数组传递逻辑,避免脚本中手动分割字符串的潜在问题:
- 修改Terraform代码:
variable "services" { type = list(string) default = ["Service1", "Service2", "service3"] } variable "passwords" { type = list(string) default = ["Password1", "Password2", "Password3"] } resource "aws_instance" "grafana_nodes" { ... user_data = templatefile("${path.module}/init/configure", { services = var.services passwords = var.passwords }) ... }
- 修改用户数据脚本(通过Terraform模板直接生成bash数组):
#!/bin/bash # 直接由Terraform模板生成bash数组,无需手动分割字符串 declare -a services_array=( %{ for s in services ~} "${s}" %{ endfor ~} ) declare -a passwords_array=( %{ for p in passwords ~} "${p}" %{ endfor ~} ) sudo echo "${services_array[@]}" >> /tmp/isp_services_array.txt sudo echo "${passwords_array[@]}" >> /tmp/influx_db_passwords_array.txt
这种方式的优势:
- 避免了字符串分割可能带来的问题(比如元素包含空格、逗号等特殊字符)
- 代码更简洁,符合Terraform最新最佳实践
额外注意事项
- 若数组元素包含特殊字符(如空格、引号),方式二的模板生成逻辑会自动处理,确保bash数组解析正确;而方式一中的
join(",", ...)会在元素含逗号时失效,因此方式二更健壮。 - 确保用户数据脚本包含
#!/bin/bashshebang,保证EC2实例能正确识别脚本类型。
内容的提问来源于stack exchange,提问作者Marco Ferrara
相关产品推荐
相关产品推荐

