Terraform部署Azure VM后修改custom_data脚本未触发实例重建问题
问题描述
通过Terraform部署Azure虚拟机时,使用custom_data字段传入bash脚本以安装kubectl和Azure CLI,首次部署可正常完成安装。但修改该bash脚本后执行terraform apply,Terraform未检测到变更,虚拟机也不会重建。
相关Terraform代码片段:
locals { admin_username = "myjumphost" admin_password = "mypassword!610542" } resource "azurerm_virtual_machine" "vm" { name = var.vm_name location = var.location resource_group_name = var.rg_name network_interface_ids = var.nic_id vm_size = var.vm_size delete_os_disk_on_termination = true delete_data_disks_on_termination = true storage_image_reference { publisher = var.storage_image_reference.publisher offer = var.storage_image_reference.offer sku = var.storage_image_reference.sku version = var.storage_image_reference.version } storage_os_disk { name = var.storage_os_disk.name caching = var.storage_os_disk.caching create_option = var.storage_os_disk.create_option managed_disk_type = var.storage_os_disk.managed_disk_type } os_profile { computer_name = var.vm_name admin_username = local.admin_username admin_password = local.admin_password custom_data = file("${path.module}/${var.custom_data_script}") } os_profile_linux_config { disable_password_authentication = true ssh_keys { key_data = file("${path.module}/${var.ssh_public_key}") path = "/home/${local.admin_username}/.ssh/authorized_keys" } } tags = merge(var.common_tags) }
对应的install.sh脚本:
#!/bin/bash # install Kubectl curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" curl -LO "https://dl.k8s.io/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl.sha256" sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl kubectl version --client --output=yaml > /tmp/kubectl_version.yaml # Install Azure CLI curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
问题原因与解决方案
原因
Azure虚拟机的custom_data属于初始化注入内容,仅在VM首次创建时生效。Terraform默认不会将custom_data的内容变更视为需要重建VM的触发条件——因为该字段修改后,Azure本身允许更新但不会自动重建VM,Terraform也无法通过常规属性跟踪判断需要替换资源。
解决方案
通过添加触发器,让Terraform检测到脚本文件变化时自动重建VM,有两种常用实现方式:
方式1:使用replace_triggered_by参数
在azurerm_virtual_machine资源块中添加replace_triggered_by,将脚本文件的哈希值作为触发条件。当脚本内容修改时,哈希值变化,Terraform会标记VM需要重建。
修改后的资源块示例:
resource "azurerm_virtual_machine" "vm" { name = var.vm_name location = var.location resource_group_name = var.rg_name network_interface_ids = var.nic_id vm_size = var.vm_size # 添加此行,监听脚本文件的哈希变化 replace_triggered_by = [filehash("${path.module}/${var.custom_data_script}")] delete_os_disk_on_termination = true delete_data_disks_on_termination = true # 其余原有代码保持不变... }
方式2:将脚本哈希作为tags的一部分
把脚本的哈希值添加到VM的标签中,当脚本修改时标签值变化,触发Terraform更新并重建VM(需配合lifecycle块的create_before_destroy确保平滑替换)。
示例代码:
resource "azurerm_virtual_machine" "vm" { name = var.vm_name location = var.location resource_group_name = var.rg_name network_interface_ids = var.nic_id vm_size = var.vm_size delete_os_disk_on_termination = true delete_data_disks_on_termination = true # 其余原有代码保持不变... tags = merge( var.common_tags, { script_hash = filehash("${path.module}/${var.custom_data_script}") } ) lifecycle { create_before_destroy = true } }
说明
filehash函数会计算文件的SHA-256哈希值,相比旧的filemd5更安全,且是Terraform推荐的用法。- 两种方式都会在脚本内容变更时触发VM重建,确保新的
custom_data脚本被执行。
内容的提问来源于stack exchange,提问作者Jananath Banuka
相关产品推荐
相关产品推荐

