如何使用Terraform向已存在的Azure虚拟机实例上传本地文件
解决方案
首先明确原因:Terraform 中定义在资源块内的 provisioner 属于资源首次创建时的一次性执行逻辑,新增/修改 provisioner 不会被判定为资源属性变更,因此terraform plan不会识别到相关改动,这是预期设计。
以下是可落地的实现方案:
方案1:使用null_resource配合触发器实现按需执行(推荐)
该方案不会影响原有虚拟机资源,仅在本地文件变更时自动触发文件上传,是最常用的轻量方案。
示例代码如下:
# 原有虚拟机资源保持不变 resource "azurerm_virtual_machine" "vm" { # 原有代码无需修改 } # 新增独立的文件上传逻辑 resource "null_resource" "upload_time_style_script" { # 触发器:本地文件内容变更时自动触发重新执行 triggers = { script_sha256 = filesha256("${path.module}/set_time_style.sh") } # 文件上传 provisioner provisioner "file" { source = "${path.module}/set_time_style.sh" destination = "/etc/profile.d/set_time_style.sh" # 连接配置,根据你的虚拟机认证方式填写,以SSH为例 connection { type = "ssh" host = azurerm_virtual_machine.vm.public_ip_address user = "你的虚拟机登录用户名" private_key = file("~/.ssh/your_private_key.pem") # 用密码认证的话替换为 password = "你的密码" } } }
执行terraform apply即可触发首次上传,后续本地脚本文件修改后,再次执行apply会自动识别变更并重新上传。
方案2:使用Azure原生虚拟机扩展(生产环境推荐)
Terraform官方更推荐优先使用云厂商原生能力替代provisioner,你可以通过azurerm_virtual_machine_extension资源的自定义脚本扩展实现文件下发,无需配置SSH/WinRM连接,可靠性更高。
示例代码如下:
resource "azurerm_virtual_machine_extension" "set_time_style" { name = "set-time-style-extension" virtual_machine_id = azurerm_virtual_machine.vm.id publisher = "Microsoft.Azure.Extensions" type = "CustomScript" type_handler_version = "2.1" # 直接写入文件内容,也可以通过file函数读取本地脚本内容 settings = <<SETTINGS { "commandToExecute": "echo '${base64encode(file("${path.module}/set_time_style.sh"))}' | base64 -d > /etc/profile.d/set_time_style.sh && chmod +x /etc/profile.d/set_time_style.sh" } SETTINGS }
不推荐方案:污点原有虚拟机
如果可以接受虚拟机被销毁重建,你可以执行terraform taint azurerm_virtual_machine.vm标记虚拟机为污点,下次apply时会重建虚拟机并执行新增的provisioner,该方案风险极高,仅测试环境可酌情使用。
内容的提问来源于stack exchange,提问作者bayerb
相关产品推荐
相关产品推荐

