You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 03:15:38