【问题标题】:Can Terraform resolve Azure interdependency issues, like renaming a resource?Terraform 能否解决 Azure 相互依赖问题,例如重命名资源?
【发布时间】:2020-04-07 10:30:20
【问题描述】:

今天我使用 Terraform 部署了一个 Azure 环境。它是一个简单的资源集合 - 资源组、VNET、VM、NIC、公共 IP 和基本 NSG。

完成部署后,我注意到我错误地命名了我的公共 IP 和我的 NSG。

我修改了我的 Terraform 配置,执行了 terraform plan,然后执行了 terraform apply 以应用我的更改,但由于以下与正在使用的资源相关的错误而未能这样做,并且无法删除为结果。

我的问题是——

  1. 期望 Terraform 能够正确处理依赖关系并采取必要的措施来启用这样的场景是否合理?
  2. 我的配置有问题吗?
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # azurerm_network_interface.nic will be updated in-place
  ~ resource "azurerm_network_interface" "nic" {
        applied_dns_servers           = []
        dns_servers                   = []
        enable_accelerated_networking = false
        enable_ip_forwarding          = false
        id                            = "/subscriptions/xxxxxxxxxxxxxxxxxxxxx/resourceGroups/app505-jmd-terraform-rg/providers/Microsoft.Network/networkInterfaces/app505-jmd-terraform-vm01-nic"
        location                      = "eastus2"
        mac_address                   = "00-0D-3A-7B-B9-EC"
        name                          = "app505-jmd-terraform-vm01-nic"
      ~ network_security_group_id     = "/subscriptions/xxxxxxxxxxxxxxxxxxxxx/resourceGroups/app505-jmd-terraform-rg/providers/Microsoft.Network/networkSecurityGroups/app505-jmd-terraform" -> (known after apply)
        private_ip_address            = "10.0.1.4"
        private_ip_addresses          = [
            "10.0.1.4",
        ]
        resource_group_name           = "app505-jmd-terraform-rg"
        tags                          = {}
        virtual_machine_id            = "/subscriptions/xxxxxxxxxxxxxxxxxxxxx/resourceGroups/app505-jmd-terraform-rg/providers/Microsoft.Compute/virtualMachines/app505-jmd-terraform-vm01"

      ~ ip_configuration {
            application_gateway_backend_address_pools_ids = []
            application_security_group_ids                = []
            load_balancer_backend_address_pools_ids       = []
            load_balancer_inbound_nat_rules_ids           = []
            name                                          = "myNicConfiguration"
            primary                                       = true
            private_ip_address                            = "10.0.1.4"
            private_ip_address_allocation                 = "dynamic"
            private_ip_address_version                    = "IPv4"
          ~ public_ip_address_id                          = "/subscriptions/xxxxxxxxxxxxxxxxxxxxx/resourceGroups/app505-jmd-terraform-rg/providers/Microsoft.Network/publicIPAddresses/app505-jmd-terraform" -> (known after apply)
            subnet_id                                     = "/subscriptions/xxxxxxxxxxxxxxxxxxxxx/resourceGroups/app505-jmd-terraform-rg/providers/Microsoft.Network/virtualNetworks/app505-jmd-terraform-vnet/subnets/Internal"
        }
    }

  # azurerm_network_security_group.nsg must be replaced
-/+ resource "azurerm_network_security_group" "nsg" {
      ~ id                  = "/subscriptions/xxxxxxxxxxxxxxxxxxxxx/resourceGroups/app505-jmd-terraform-rg/providers/Microsoft.Network/networkSecurityGroups/app505-jmd-terraform" -> (known after apply)
        location            = "eastus2"
      ~ name                = "app505-jmd-terraform" -> "app505-jmd-terraform-nsg" # forces replacement
        resource_group_name = "app505-jmd-terraform-rg"
        security_rule       = [
            {
                access                                     = "Allow"
                description                                = ""
                destination_address_prefix                 = "*"
                destination_address_prefixes               = []
                destination_application_security_group_ids = []
                destination_port_range                     = "22"
                destination_port_ranges                    = []
                direction                                  = "Inbound"
                name                                       = "SSH"
                priority                                   = 1001
                protocol                                   = "Tcp"
                source_address_prefix                      = "*"
                source_address_prefixes                    = []
                source_application_security_group_ids      = []
                source_port_range                          = "*"
                source_port_ranges                         = []
            },
        ]
      ~ tags                = {} -> (known after apply)
    }

  # azurerm_public_ip.pip must be replaced
-/+ resource "azurerm_public_ip" "pip" {
        allocation_method            = "Dynamic"
      + fqdn                         = (known after apply)
      ~ id                           = "/subscriptions/xxxxxxxxxxxxxxxxxxxxx/resourceGroups/app505-jmd-terraform-rg/providers/Microsoft.Network/publicIPAddresses/app505-jmd-terraform" -> (known after apply)
        idle_timeout_in_minutes      = 4
      ~ ip_address                   = "13.68.114.233" -> (known after apply)
        ip_version                   = "IPv4"
        location                     = "eastus2"
      ~ name                         = "app505-jmd-terraform" -> "app505-jmd-terraform-pip" # forces replacement
      ~ public_ip_address_allocation = "Dynamic" -> (known after apply)
        resource_group_name          = "app505-jmd-terraform-rg"
        sku                          = "Basic"
      ~ tags                         = {} -> (known after apply)
      - zones                        = [] -> null
    }

Plan: 2 to add, 1 to change, 2 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

azurerm_public_ip.pip: Destroying... [id=/subscriptions/xxxxxxxxxxxxxxxxxxxxx/resourceGroups/app505-jmd-terraform-rg/providers/Microsoft.Network/publicIPAddresses/app505-jmd-terraform]
azurerm_network_security_group.nsg: Destroying... [id=/subscriptions/xxxxxxxxxxxxxxxxxxxxx/resourceGroups/app505-jmd-terraform-rg/providers/Microsoft.Network/networkSecurityGroups/app505-jmd-terraform]

Error: Error deleting Network Security Group "app505-jmd-terraform" (Resource Group "app505-jmd-terraform-rg"): network.SecurityGroupsClient#Delete: Failure sending request: StatusCode=400 -- Original Error: Code="InUseNetworkSecurityGroupCannotBeDeleted" Message="Network security group /subscriptions/xxxxxxxxxxxxxxxxxxxxx/resourceGroups/app505-jmd-terraform-rg/providers/Microsoft.Network/networkSecurityGroups/app505-jmd-terraform cannot be deleted because it is in use by the following resources: /subscriptions/xxxxxxxxxxxxxxxxxxxxx/resourceGroups/app505-jmd-terraform-rg/providers/Microsoft.Network/networkInterfaces/app505-jmd-terraform-vm01-nic. In order to delete the Network security group, remove the association with the resource(s). To learn how to do this, see aka.ms/deletensg." Details=[]



Error: Error deleting Public IP "app505-jmd-terraform" (Resource Group "app505-jmd-terraform-rg"): network.PublicIPAddressesClient#Delete: Failure sending request: StatusCode=400 -- Original Error: Code="PublicIPAddressCannotBeDeleted" Message="Public IP address /subscriptions/xxxxxxxxxxxxxxxxxxxxx/resourceGroups/app505-jmd-terraform-rg/providers/Microsoft.Network/publicIPAddresses/app505-jmd-terraform can not be deleted since it is still allocated to resource /subscriptions/xxxxxxxxxxxxxxxxxxxxx/resourceGroups/app505-jmd-terraform-rg/providers/Microsoft.Network/networkInterfaces/app505-jmd-terraform-vm01-nic/ipConfigurations/myNicConfiguration. In order to delete the public IP, disassociate/detach the Public IP address from the resource.  To learn how to do this, see aka.ms/deletepublicip." Details=[]



C:\Users\jdeli\OneDrive\Documents\Code\Terraform\terraform>

最后,我的配置:

# Configure the Microsoft Azure Provider
provider "azurerm" {
    subscription_id = "aaaaaaaaaaaaaaaa"
    client_id       = "bbbbbbbbbbbbbbbb"
    client_secret   = "cccccccccccccccc"
    tenant_id       = "dddddddddddddddd"
    skip_provider_registration = true
}

# Create a resource group if it doesn’t exist
resource "azurerm_resource_group" "main" {
    name     = "${var.prefix}-rg"
    location = var.location
}

# Create virtual network
resource "azurerm_virtual_network" "network" {
    name                = "${var.prefix}-vnet"
    address_space       = ["10.0.0.0/16"]
    location            = var.location
    resource_group_name = azurerm_resource_group.main.name

}

# Create subnet
resource "azurerm_subnet" "subnet" {
    name                 = "Internal"
    resource_group_name  = azurerm_resource_group.main.name
    virtual_network_name = azurerm_virtual_network.network.name
    address_prefix       = "10.0.1.0/24"
}

# Create public IPs
resource "azurerm_public_ip" "pip" {
    name                         = "${var.prefix}-pip"
    location                     = var.location
    resource_group_name          = azurerm_resource_group.main.name
    allocation_method            = "Dynamic"
}

# Create Network Security Group and rule
resource "azurerm_network_security_group" "nsg" {
    name                = "${var.prefix}-nsg"
    location            = var.location
    resource_group_name = azurerm_resource_group.main.name

    security_rule {
        name                       = "SSH"
        priority                   = 1001
        direction                  = "Inbound"
        access                     = "Allow"
        protocol                   = "Tcp"
        source_port_range          = "*"
        destination_port_range     = "22"
        source_address_prefix      = "*"
        destination_address_prefix = "*"
    }
}

# Create network interface
resource "azurerm_network_interface" "nic" {
    name                      = "${var.prefix}-vm01-nic"
    location                  = var.location
    resource_group_name       = azurerm_resource_group.main.name
    network_security_group_id = azurerm_network_security_group.nsg.id

    ip_configuration {
        name                          = "myNicConfiguration"
        subnet_id                     = azurerm_subnet.subnet.id
        private_ip_address_allocation = "Dynamic"
        public_ip_address_id          = azurerm_public_ip.pip.id
    }

}

# Generate random text for a unique storage account name
resource "random_id" "randomId" {
    keepers = {
        # Generate a new ID only when a new resource group is defined
        resource_group = azurerm_resource_group.main.name
    }
    byte_length = 8
}

# Create storage account for boot diagnostics
resource "azurerm_storage_account" "diagstorage" {
    name                        = "diag${random_id.randomId.hex}"
    resource_group_name         = azurerm_resource_group.main.name
    location                    = var.location
    account_tier                = "Standard"
    account_replication_type    = "LRS"
}

# Create virtual machine
resource "azurerm_virtual_machine" "vm" {

    name                  = "${var.prefix}-"
    location              = var.location
    resource_group_name   = azurerm_resource_group.main.name
    network_interface_ids = [azurerm_network_interface.nic.id]
    vm_size               = "Standard_DS1_v2"

    storage_os_disk {
        name              = "${var.prefix}-vm01-disk0"
        caching           = "ReadWrite"
        create_option     = "FromImage"
        managed_disk_type = "Premium_LRS"
    }

    storage_image_reference {
        publisher = "Canonical"
        offer     = "UbuntuServer"
        sku       = "16.04.0-LTS"
        version   = "latest"
    }

    os_profile {
        computer_name  = "${var.prefix}-vm01"
        admin_username = "azureuser"
    }

    os_profile_linux_config {
        disable_password_authentication = true
        ssh_keys {
            path     = "/home/azureuser/.ssh/authorized_keys"
            key_data = "ssh-rsa xxxxxxxx"
        }
    }

    boot_diagnostics {
        enabled = "true"
        storage_uri = azurerm_storage_account.diagstorage.primary_blob_endpoint
    }
}

重现步骤:

  1. 部署以上配置
  2. 重命名 NSG 和公共 IP 地址(“名称”属性)
  3. 再次部署,出现错误。

【问题讨论】:

    标签: azure terraform rename


    【解决方案1】:

    我怀疑这适用于“顶级”资源(因此资源没有依赖于这些资源的资源)。 TF 会从头开始删除和创建这些资源(你不能在 Azure 中真正重命名)。

    对于具有依赖关系的资源,这将不起作用,因为这意味着必须首先删除所有依赖资源(或删除依赖关系),然后才能重命名您的资源(因此删除\使用新名称创建),然后所有依赖的资源都必须重新创建\重新配置

    【讨论】:

    • 让我感到困惑/充满希望的是 Terraform 似乎“知道”它需要销毁和重新创建公共 IP 和 NSG(无法重命名),并相应地更新 NIC。这当然是必要的,但它遗漏了一些依赖项,例如首先解除公共 IP 与 NIC 的关联,以及 NIC 与 NSG 的关联。就像 Terraform 对影响这种变化的依赖性和复杂性半知半解。我想要做的是否超出了 Terraform 的预期用途范围?或者我应该向 Terraform 团队提出一个错误?谢谢!
    • 我不会知道更多细节,我避免像瘟疫一样的地形。
    • 我很好奇为什么!它有什么不好的,你用什么代替?
    • hcl 是其中最糟糕的部分,tbh。我用arm模板,ansible,pulumi
    猜你喜欢
    • 2021-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-05
    • 1970-01-01
    • 2019-01-24
    相关资源
    最近更新 更多