Guida introduttiva: Usare Terraform per creare una macchina virtuale Windows

Si applica a: ✔️ macchine virtuali di Windows

Questo articolo illustra come creare un ambiente Windows completo e le risorse di supporto con Terraform. Tali risorse includono una rete virtuale, una subnet, un indirizzo IP pubblico e altro ancora.

Terraform consente di definire, visualizzare in anteprima e distribuire l'infrastruttura cloud. Con Terraform è possibile creare file di configurazione usando la sintassi HCL. La sintassi HCL consente di specificare il provider di servizi cloud, ad esempio Azure, e gli elementi che costituiscono l'infrastruttura cloud. Dopo aver creato i file di configurazione, è necessario creare un piano di esecuzione che consenta di visualizzare in anteprima le modifiche apportate all'infrastruttura prima che vengano distribuite. Dopo aver verificato le modifiche, è possibile applicare il piano di esecuzione per distribuire l'infrastruttura.

In questo articolo vengono illustrate le operazioni seguenti:

Prerequisiti

  • Sottoscrizione di Azure: se non si ha una sottoscrizione di Azure, creare un account gratuito prima di iniziare.

Implementare il codice Terraform

  1. Creare una directory in cui testare il codice Terraform di esempio e impostarla come directory corrente.

  2. Creare un file denominato providers.tf e inserire il codice seguente:

    terraform {
      required_version = ">=1.0"
    
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "~>3.0"
        }
        random = {
          source  = "hashicorp/random"
          version = "~>3.0"
        }
      }
    }
    
    provider "azurerm" {
      features {}
    }
    
  3. Creare un file denominato main.tf e inserire il codice seguente:

    resource "azurerm_resource_group" "rg" {
      location = var.resource_group_location
      name     = "${random_pet.prefix.id}-rg"
    }
    
    # Create virtual network
    resource "azurerm_virtual_network" "my_terraform_network" {
      name                = "${random_pet.prefix.id}-vnet"
      address_space       = ["10.0.0.0/16"]
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
    }
    
    # Create subnet
    resource "azurerm_subnet" "my_terraform_subnet" {
      name                 = "${random_pet.prefix.id}-subnet"
      resource_group_name  = azurerm_resource_group.rg.name
      virtual_network_name = azurerm_virtual_network.my_terraform_network.name
      address_prefixes     = ["10.0.1.0/24"]
    }
    
    # Create public IPs
    resource "azurerm_public_ip" "my_terraform_public_ip" {
      name                = "${random_pet.prefix.id}-public-ip"
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
      allocation_method   = "Dynamic"
    }
    
    # Create Network Security Group and rules
    resource "azurerm_network_security_group" "my_terraform_nsg" {
      name                = "${random_pet.prefix.id}-nsg"
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
    
      security_rule {
        name                       = "RDP"
        priority                   = 1000
        direction                  = "Inbound"
        access                     = "Allow"
        protocol                   = "*"
        source_port_range          = "*"
        destination_port_range     = "3389"
        source_address_prefix      = "*"
        destination_address_prefix = "*"
      }
      security_rule {
        name                       = "web"
        priority                   = 1001
        direction                  = "Inbound"
        access                     = "Allow"
        protocol                   = "Tcp"
        source_port_range          = "*"
        destination_port_range     = "80"
        source_address_prefix      = "*"
        destination_address_prefix = "*"
      }
    }
    
    # Create network interface
    resource "azurerm_network_interface" "my_terraform_nic" {
      name                = "${random_pet.prefix.id}-nic"
      location            = azurerm_resource_group.rg.location
      resource_group_name = azurerm_resource_group.rg.name
    
      ip_configuration {
        name                          = "my_nic_configuration"
        subnet_id                     = azurerm_subnet.my_terraform_subnet.id
        private_ip_address_allocation = "Dynamic"
        public_ip_address_id          = azurerm_public_ip.my_terraform_public_ip.id
      }
    }
    
    # Connect the security group to the network interface
    resource "azurerm_network_interface_security_group_association" "example" {
      network_interface_id      = azurerm_network_interface.my_terraform_nic.id
      network_security_group_id = azurerm_network_security_group.my_terraform_nsg.id
    }
    
    # Create storage account for boot diagnostics
    resource "azurerm_storage_account" "my_storage_account" {
      name                     = "diag${random_id.random_id.hex}"
      location                 = azurerm_resource_group.rg.location
      resource_group_name      = azurerm_resource_group.rg.name
      account_tier             = "Standard"
      account_replication_type = "LRS"
    }
    
    
    # Create virtual machine
    resource "azurerm_windows_virtual_machine" "main" {
      name                  = "${var.prefix}-vm"
      admin_username        = "azureuser"
      admin_password        = random_password.password.result
      location              = azurerm_resource_group.rg.location
      resource_group_name   = azurerm_resource_group.rg.name
      network_interface_ids = [azurerm_network_interface.my_terraform_nic.id]
      size                  = "Standard_DS1_v2"
    
      os_disk {
        name                 = "myOsDisk"
        caching              = "ReadWrite"
        storage_account_type = "Premium_LRS"
      }
    
      source_image_reference {
        publisher = "MicrosoftWindowsServer"
        offer     = "WindowsServer"
        sku       = "2022-datacenter-azure-edition"
        version   = "latest"
      }
    
    
      boot_diagnostics {
        storage_account_uri = azurerm_storage_account.my_storage_account.primary_blob_endpoint
      }
    }
    
    # Install IIS web server to the virtual machine
    resource "azurerm_virtual_machine_extension" "web_server_install" {
      name                       = "${random_pet.prefix.id}-wsi"
      virtual_machine_id         = azurerm_windows_virtual_machine.main.id
      publisher                  = "Microsoft.Compute"
      type                       = "CustomScriptExtension"
      type_handler_version       = "1.8"
      auto_upgrade_minor_version = true
    
      settings = <<SETTINGS
        {
          "commandToExecute": "powershell -ExecutionPolicy Unrestricted Install-WindowsFeature -Name Web-Server -IncludeAllSubFeature -IncludeManagementTools"
        }
      SETTINGS
    }
    
    # Generate random text for a unique storage account name
    resource "random_id" "random_id" {
      keepers = {
        # Generate a new ID only when a new resource group is defined
        resource_group = azurerm_resource_group.rg.name
      }
    
      byte_length = 8
    }
    
    resource "random_password" "password" {
      length      = 20
      min_lower   = 1
      min_upper   = 1
      min_numeric = 1
      min_special = 1
      special     = true
    }
    
    resource "random_pet" "prefix" {
      prefix = var.prefix
      length = 1
    }
    
  4. Creare un file denominato variables.tf e inserire il codice seguente:

    variable "resource_group_location" {
      default     = "eastus"
      description = "Location of the resource group."
    }
    
    variable "prefix" {
      type        = string
      default     = "win-vm-iis"
      description = "Prefix of the resource name"
    }
    
  5. Creare un file denominato outputs.tf e inserire il codice seguente:

    output "resource_group_name" {
      value = azurerm_resource_group.rg.name
    }
    
    output "public_ip_address" {
      value = azurerm_windows_virtual_machine.main.public_ip_address
    }
    
    output "admin_password" {
      sensitive = true
      value     = azurerm_windows_virtual_machine.main.admin_password
    }
    

Inizializzare Terraform

Per inizializzare la distribuzione di Terraform, eseguire terraform init. Questo comando scarica il provider di Azure necessario per gestire le risorse di Azure.

terraform init -upgrade

Punti principali:

  • Il parametro -upgrade aggiorna i plug-in del provider necessari alla versione più recente conforme ai vincoli di versione della configurazione.

Creare un piano di esecuzione Terraform

Eseguire terraform plan per creare un piano di esecuzione.

terraform plan -out main.tfplan

Punti principali:

  • Il comando terraform plan consente di creare un piano di esecuzione, ma non di eseguirlo. Determina invece le azioni necessarie per creare la configurazione specificata nei file di configurazione. Questo modello consente di verificare se il piano di esecuzione corrisponde alle aspettative prima di apportare modifiche alle risorse effettive.
  • Il parametro -out facoltativo consente di specificare un file di output per il piano. L'uso del parametro -out garantisce che il piano esaminato sia esattamente quello che viene applicato.

Applicare un piano di esecuzione Terraform

Eseguire terraform apply per applicare il piano di esecuzione all'infrastruttura cloud.

terraform apply main.tfplan

Punti principali:

  • Il comando terraform apply di esempio presuppone che in precedenza sia stato eseguito terraform plan -out main.tfplan.
  • Se è stato specificato un nome file diverso per il parametro -out, usare lo stesso nome file nella chiamata a terraform apply.
  • Se non è stato usato il parametro -out, chiamare terraform apply senza parametri.

Le informazioni sui costi non vengono visualizzate durante il processo di creazione della macchina virtuale per Terraform come avviene per il portale di Azure. Per altre informazioni sul funzionamento dei costi per le macchine virtuali, vedere la pagina Panoramica dell'ottimizzazione dei costi.

Verificare i risultati

  1. Eseguire il comando seguente per ottenere l'indirizzo IP pubblico della macchina virtuale e prenderne nota:

    echo $(terraform output -raw public_ip_address)
    
  2. Dopo l'installazione di IIS e l'apertura della porta 80 nella macchina virtuale da Internet, usare un Web browser preferito per visualizzare la home page predefinita di IIS. Usare l'indirizzo IP pubblico della macchina virtuale ottenuto dal comando precedente. L'esempio seguente mostra il sito Web predefinito di IIS:

    Screenshot che mostra il sito predefinito di IIS.

Pulire le risorse

Quando le risorse create tramite Terraform non sono più necessarie, eseguire i passaggi seguenti:

  1. Eseguire terraform plan e specificare il flag destroy.

    terraform plan -destroy -out main.destroy.tfplan
    

    Punti principali:

    • Il comando terraform plan consente di creare un piano di esecuzione, ma non di eseguirlo. Determina invece le azioni necessarie per creare la configurazione specificata nei file di configurazione. Questo modello consente di verificare se il piano di esecuzione corrisponde alle aspettative prima di apportare modifiche alle risorse effettive.
    • Il parametro -out facoltativo consente di specificare un file di output per il piano. L'uso del parametro -out garantisce che il piano esaminato sia esattamente quello che viene applicato.
  2. Eseguire terraform apply per applicare il piano di esecuzione.

    terraform apply main.destroy.tfplan
    

Risolvere i problemi di Terraform in Azure

Risolvere i problemi comuni relativi all'uso di Terraform in Azure

Passaggi successivi

In questa guida introduttiva è stata distribuita una semplice macchina virtuale usando Terraform. Per altre informazioni sulle macchine virtuali di Azure, passare all'esercitazione per le VM di Linux.