Terraform - Azure 上的静态 IP 地址

Terraform - Static ip addresses on Azure

我们需要为通过 Terraform 部署在 Azure 中的虚拟机配置静态私有 IP。原因是我们需要通过一个 ansible 管道在 Ansible 中使用这些。

我在这里找到的一个解决方案是先创建一个带有“动态”地址的网卡,然后在 Terraform 的下一步中将其转换为“静态”IP。

# Create network interfaces with Private IP's
resource "azurerm_network_interface" "nic" {
  for_each = { for vm in var.vms : vm.hostname => vm }
  name                = "${each.value.hostname}-NIC"
  location            = var.network_location
  resource_group_name = var.vm_resource_group
  ip_configuration {
    name                          = "monitoringConfg"
    subnet_id                     = data.azurerm_subnet.vm_subnet.id
    private_ip_address_allocation = "dynamic"
  }
  tags = each.value.extra_tag
}

#Convert Dynamic Private IP's to Static
resource "azurerm_network_interface" "staticnic" {
  for_each = { for vm in var.vms : vm.hostname => vm }
  name                = "${each.value.hostname}-NIC"
  location            = var.network_location
  resource_group_name = var.vm_resource_group
  ip_configuration {
    name                          = "monitoringConfg"
    subnet_id                     = data.azurerm_subnet.vm_subnet.id
    private_ip_address_allocation = "static"
    private_ip_address            = azurerm_network_interface.nic[each.key].private_ip_address    
  }
  tags = each.value.extra_tag

但是当我运行这个时,我得到以下错误:

ID 为“/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/xxxxxxxxxxxxxxxx/providers/Microsoft.Network/networkInterfaces/xxxxxxxxxxxxxxxxxxx-NIC”的资源已存在 - 要通过 Terraform 管理此资源,需要将其导入国家。请参阅“azurerm_network_interface”的资源文档以获取更多信息。 在 ../../modules/main.tf 第 58 行,资源“azurerm_network_interface”“staticnic”中: 58:资源“azurerm_network_interface”“staticnic”{

有没有人知道我做错了什么或有更好的方法来处理这个问题?

亲切的问候, RB

Azure 不会分配动态 IP 地址,直到网络接口附加到 运行 虚拟机(或其他资源),请参阅 this.所以我认为我们不能在创建VM之前将动态IP转换为静态IP,因为IP地址暂时不存在。

相反,我们可以通过在该子网范围内分配一些 IP 地址,直接将一些静态 IP 地址关联到 Azure VM。阅读private IP分配方法。

Azure reserves the first four addresses in each subnet address range. The addresses can't be assigned to resources. For example, if the subnet's address range is 10.0.0.0/16, addresses 10.0.0.0-10.0.0.3 and 10.0.255.255 are unavailable.

例如,您可以参考此模板为 vms 配置静态私有 ip:

variable "vmlist" {
  type = map(object({
    hostname = string
    IP_address = string
  }))
  default = {
    vm1 ={
    hostname = "vma"
    IP_address = "10.0.2.4"
    },
    vm2 = {
    hostname = "vmb"
    IP_address = "10.0.2.5"
    }
  }
}

#...

resource "azurerm_network_interface" "staticnic" {
  for_each = var.vmlist
  name                = "${each.value.hostname}-nic"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name

  ip_configuration {
    name                          = "testconfiguration1"
    subnet_id                     = azurerm_subnet.internal.id
    private_ip_address_allocation = "Static"
    private_ip_address            = each.value.IP_address
  }
}

 #...

resource "azurerm_virtual_machine" "main" {
  for_each = var.vmlist
  name                  = each.value.hostname
  location              = azurerm_resource_group.main.location
  resource_group_name   = azurerm_resource_group.main.name
  network_interface_ids = [azurerm_network_interface.staticnic[each.key].id]
  vm_size               = "Standard_DS1_v2"

  # Uncomment this line to delete the OS disk automatically when deleting the VM
  # delete_os_disk_on_termination = true

  # Uncomment this line to delete the data disks automatically when deleting the VM
  # delete_data_disks_on_termination = true

  storage_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2016-Datacenter"
    version   = "latest"
  }

  storage_os_disk {
    name              = "${each.value.hostname}-osdisk"
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Standard_LRS"
  }
  os_profile {
    computer_name  = each.value.hostname
    admin_username = "testadmin"
    admin_password = "Password1234!"
  }

   os_profile_windows_config {
    provision_vm_agent = "true"
  }

}

我正在使用

Terraform v0.14.7
+ provider registry.terraform.io/hashicorp/azurerm v2.52.0

更新

如果要让Azure分配动态IP,然后将其转换为静态IP,可以使用local-exec Provisioner在创建资源后调用本地可执行文件。

resource "null_resource" "example" {

  for_each = var.vmlist
    provisioner "local-exec" {

   command = <<EOT

      $Nic = Get-AzNetworkInterface -ResourceGroupName ${azurerm_resource_group.main.name} -Name ${azurerm_network_interface.nic[each.key].name}
      $Nic.IpConfigurations[0].PrivateIpAllocationMethod = "Static"
      Set-AzNetworkInterface -NetworkInterface $Nic
   EOT
   
   interpreter = ["PowerShell", "-Command"]
  
  }
}

为了便于阅读,我们这样做了。

首先,我使用此处列出的步骤在 Azure 中创建了一个服务原则 Creating a Service Principal

variables.TF

命令输出已添加到 variables.TF 作为

variable APP_ID {
  default = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx"
}
variable SP_PASSWORD {
  default = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
variable TENANT_ID {
  default = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

此服务主体变量将用于在 运行 az network 命令之前执行 az login windows工人代理。

Main.TF

resource "azurerm_network_interface" "nic" {
  for_each = { for vm in var.vms : vm.hostname => vm }
  name                = "${each.value.hostname}-NIC"
  location            = var.network_location
  resource_group_name = var.vm_resource_group
  ip_configuration {
    name                          = var.nic_ip_config
    subnet_id                     = data.azurerm_subnet.vm_subnet.id
    private_ip_address_allocation = "dynamic"
  }
  tags = each.value.extra_tag
}

将上述动态ip的tp静态化

# Convert All Private IP's from Dynamic to Static using powershell
resource "null_resource" "StaticIPsPrivateVMs" {
  for_each = { for vm in var.vms : vm.hostname => vm }
    provisioner "local-exec" {
      command = <<EOT
      az login --service-principal --username ${var.APP_ID} --password ${var.SP_PASSWORD} --tenant ${var.TENANT_ID}
      az network nic ip-config update -g ${var.vm_resource_group} --nic-name ${azurerm_network_interface.nic[each.key].name} --name ${var.nic_ip_config} --set privateIpAllocationMethod="Static"
      EOT
    interpreter = ["powershell", "-Command"]
  }
  depends_on = [
    azurerm_virtual_machine.vm
  ]
}

#AZ logout
resource "null_resource" "AzLogout" {
    provisioner "local-exec" {
      command = <<EOT
      az logout
      EOT
    interpreter = ["powershell", "-Command"]
  }
  depends_on = [
    null_resource.StaticIPsPrivateVMs
  ]
}

Azure-pipelines.yml

我在 validatedeploy[=42] 的顶部添加了 vmImage: 'windows-latest' =] 阶段,这样我们就不会最终使用 linux 代理,这将抛出 powershell not found 错误:

  - stage: validate
    jobs:
    - job: validate
      pool:
        vmImage: 'windows-latest'
      continueOnError: false
      steps:
- stage: deploy
    jobs:
    - deployment: deploy
      pool:
        vmImage: 'windows-latest'
      continueOnError: false

所以这似乎是对 Azure 中私有 IP 的“动态”含义的误解。在 Azure 中使用“动态”专用 ip 创建 NIC 意味着 IP 在创建接口时分配,并且仅在删除接口时释放。

这意味着它的行为与“静态”接口完全一样。

唯一的区别是“静态”接口有一个用户分配的(如输入参数)IP,“动态”接口自动从子网分配一个空闲 IP。我已经发送了一个 PR 来更新 tf 文档 https://github.com/hashicorp/terraform-provider-azurerm/pull/15264

(来自 )