如何让Terraform data external在plan和apply阶段均执行脚本
问题分析与解决方案
核心问题拆解
你遇到的问题本质是Terraform执行阶段的特性冲突:
data.external仅在plan阶段执行,生成plan文件后,apply tf.plan时会复用plan中固化的data结果,不会重新运行脚本null_resource的local-exec仅在资源变更时触发,且执行时机晚于Provider初始化,无法满足postgresql/kubernetes等Provider操作前创建隧道的需求- Provider依赖模块输出失效,是因为Terraform初始化Provider时,模块输出还未计算,依赖关系无法传递到初始化阶段
可行解决方案:用terraform_data实现双阶段触发
Terraform 1.3+引入的terraform_data资源,支持在plan和apply阶段都执行脚本,配合triggers_replace和Provider级depends_on,可以完美解决你的需求。
1. 重构隧道脚本模块(my_script/main.tf)
variable "environment" { description = "运行环境标识" type = string } # Plan阶段触发隧道创建 terraform_data "plan_tunnel" { triggers_replace = { # 用时间戳确保每次plan都触发脚本 plan_timestamp = timestamp() } provisioner "local-exec" { command = "bash ${path.module}/my_script.sh ${var.environment}" } } # Apply阶段触发隧道创建(包括使用plan文件的场景) terraform_data "apply_tunnel" { triggers_replace = { # 依赖plan阶段的触发值,确保执行顺序 apply_timestamp = timestamp() plan_trigger = terraform_data.plan_tunnel.triggers_replace.plan_timestamp } provisioner "local-exec" { command = "bash ${path.module}/my_script.sh ${var.environment}" } } output "tunnel_ready" { value = terraform_data.apply_tunnel.id }
2. 完善隧道脚本(my_script/my_script.sh)
#!/bin/bash environment="$1" # 替换为你的实际隧道创建逻辑,比如SSM端口转发 echo "创建${environment}环境的隧道..." # 示例:aws ssm start-session --target i-xxxxxx --document-name AWS-StartPortForwardingSession --parameters '{"portNumber": ["5432"], "localPortNumber": ["5432"]}' & # 记录隧道PID,方便后续清理 echo $$ > /tmp/tunnel_${environment}.pid # 返回JSON格式结果(可选,给Terraform输出用) echo "{\"environment\": \"$environment\", \"tunnel_pid\": $$}"
3. 主模块中绑定Provider依赖
让postgresql/kubernetes等Provider明确依赖隧道模块的输出,确保Provider初始化前隧道已就绪:
module "ssm_tunnel" { source = "../my_script" environment = "production" } # PostgreSQL Provider依赖隧道 provider "postgresql" { host = "localhost" port = 5432 username = "admin" password = var.db_password database = "app_db" # 强制Provider在隧道创建后再初始化 depends_on = [module.ssm_tunnel.tunnel_ready] } # Kubernetes Provider同理 provider "kubernetes" { config_path = "~/.kube/config" depends_on = [module.ssm_tunnel.tunnel_ready] }
关键说明
triggers_replace:通过时间戳或动态值,强制每次plan/apply都重新执行terraform_data的脚本- Provider级
depends_on:Terraform 0.13+支持该特性,确保Provider初始化前隧道脚本已执行完成 - 隧道生命周期:脚本中记录PID后,可在
terraform_data中添加destroy-time的local-exec,实现Terraform销毁时自动关闭隧道
验证效果
- 执行
terraform plan -out tf.plan:plan_tunnel会触发脚本创建隧道 - 执行
terraform apply tf.plan:apply_tunnel会再次触发脚本,且Provider依赖隧道输出,确保操作前隧道就绪 - 直接执行
terraform apply:两个阶段的脚本都会正常触发
内容的提问来源于stack exchange,提问作者Dustin
相关产品推荐
相关产品推荐

