Terraform部署Azure虚拟机时使用旧公网IP导致remote-exec执行异常问题求助
我现在遇到一个Terraform部署Azure虚拟机的棘手问题,想请各位大佬帮忙排查下:
我写了azure.tf用来部署Azure虚拟机,之后通过SSH连接到机器上运行Ansible playbook。但每次执行terraform apply时,remote-exec和local-exec总是会用上之前已销毁虚拟机的旧公网IP,可我在Azure门户里查看新创建的NIC、公网IP和虚拟机,明明都是新分配的正确IP地址。
我的配置细节如下:
outputs.tf用来输出公网IP:
output "public_ip_address" { value = data.azurerm_public_ip.my_terraform_public_ip.ip_address }
- 公网IP的资源和数据块配置:
# Create public IPs resource "azurerm_public_ip" "my_terraform_public_ip" { name = "testpublicIP" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name allocation_method = "Dynamic" } data "azurerm_public_ip" "my_terraform_public_ip" { name = azurerm_public_ip.my_terraform_public_ip.name resource_group_name = azurerm_public_ip.my_terraform_public_ip.resource_group_name }
- 虚拟机的provisioner部分:
provisioner "remote-exec" { inline = ["echo 'Wait until SSH is ready'"] connection { type = "ssh" user = "ubuntu" private_key = file(local.private_key_path_Azure) host = data.azurerm_public_ip.my_terraform_public_ip.ip_address } } provisioner "local-exec" { command = "ansible-playbook -i ${data.azurerm_public_ip.my_terraform_public_ip.ip_address}, --private-key ${local.private_key_path_Azure} docker.yaml" }
我实在搞不懂为什么provisioner会执着于旧IP,明明新资源的IP是对的,有没有人能指点一下问题出在哪?
问题原因分析
你这里的核心问题出在多余的data块使用上。Terraform的data块是在**计划阶段(plan)**就会读取资源状态,而不是等到资源实际创建/更新后的应用阶段(apply)。
当你销毁旧虚拟机后重新执行terraform apply,计划阶段时新的公网IP资源还未创建,data块会从Terraform本地状态文件里读取之前旧的公网IP记录,导致后续provisioner直接复用了这个旧值。而Azure门户里显示的是新创建的资源,所以IP是正确的,但Terraform的provisioner用的是计划阶段提前读取的旧数据。
解决方案
直接去掉多余的data块,直接引用公网IP资源的属性即可,不需要通过data间接获取:
- 删除这个冗余的
data块:
data "azurerm_public_ip" "my_terraform_public_ip" { name = azurerm_public_ip.my_terraform_public_ip.name resource_group_name = azurerm_public_ip.my_terraform_public_ip.resource_group_name }
- 修改所有引用公网IP的地方,直接用
azurerm_public_ip.my_terraform_public_ip.ip_address:
- 调整
outputs.tf:
output "public_ip_address" { value = azurerm_public_ip.my_terraform_public_ip.ip_address }
- 修改
remote-exec的host配置:
host = azurerm_public_ip.my_terraform_public_ip.ip_address
- 修改
local-exec的命令:
command = "ansible-playbook -i ${azurerm_public_ip.my_terraform_public_ip.ip_address}, --private-key ${local.private_key_path_Azure} docker.yaml"
这样修改后,Terraform会在公网IP资源创建完成后,直接引用它的实时属性值,而不是在计划阶段读取旧状态,就能保证provisioner使用的是最新的IP地址了。
另外还有个小细节提醒:你的os_profile里设置的管理员用户名是testadmin,但remote-exec里用的是ubuntu,这里要确保用户名一致,否则可能会出现SSH连接失败的额外问题哦。
备注:内容来源于stack exchange,提问作者brokkosnarf

