\ /
cloud  Automation  Cloud Native  Metodologies  Azure  Terraform  IaC  Azure Virtual Desktop 

Azure Virtual Desktop - Deploy with Terraform

Benvenuti in questo articolo del blog, in cui esploreremo l'implementazione di un'infrastruttura Azure Virtual Desktop senza utilizzare la classica console di amministrazione grafica a cui siamo abituati in Azure bensì tramite codice per mezzo di Terraform.

Terraform è uno strumento open-source per la gestione dell'infrastruttura come codice (IaC), il che significa che potremo creare e modificare l'infrastruttura in modo dichiarativo, prevedibile e intuitivo.

L'idea alla base di IaC è quella di codificare l'intero processo di creazione dell'infrastruttura. Terraform ci permette di definire le risorse utilizzando un linguaggio ad alto livello, rendendolo leggibile anche per chi non è un esperto di programmazione. Questo linguaggio è chiamato HCL (HashiCorp Configuration Language).

Nel corso di questo articolo, vi guideremo attraverso le seguenti configurazioni utilizzando Terraform:

  • Creazione di un Gruppo di Risorse Azure
  • Configurazione di risorse di rete in Azure
  • Implementazione dei componenti principali di Azure Virtual Desktop
  • Creazione di Session Host di Azure Virtual Desktop (con Azure AD Join)

Per ora, non affronteremo dettagli più avanzati, come l'utilizzo di un service principal con autorizzazioni API per la connessione ad Azure, l'uso di un account di archiviazione per ospitare le condivisioni necessarie per i profili FSLogix, la creazione di macchine virtuali personalizzate da un'immagine tramite Azure Compute Gallery e l'assegnazione di ruoli RBAC Azure AD alle risorse.

azure-terraform-github-devops-integration-flow-01.png

Principali usi di Terraform

Terraform viene solitamente utilizzato per:

  • Gestione amministrativa delle risorse e dell'infrastruttura
  • Deploy infrastrutturale
  • Automazione dell'infrastruttura

E' importante sottolineare che Terraform di solito non viene utilizzato come piano di Disaster Recovery (DR) per una seria di considerazioni poco vantaggiose.

Di solito, quando si decide di utilizzare Terraform, la possibilità di creare risorse e oggetti in cloud tramite il portale viene disabilitata. Ciò è dovuto al fatto che Terraform si occupa dell'intero ciclo di vita, partendo dalla fase di provisioning, passando per la configurazione e, infine, arrivando alla fase di decommissioning, rendendo inutile la gestione manuale delle risorse attraverso il portale.

Basi di Terraform

Per distribuire le risorse su Azure è necessario definire il provider nei file terraform.

Per ogni risorsa che si vuole distribuire usando Terraform c'è una sintassi specifica da usare. Nell'esempio seguente si può vedere la sintassi per la creazione di uno account di archiviazione.

resource "azurerm_storage_account" "example" {
  name                     = "storageaccountname"
  resource_group_name      = azurerm_resource_group.example.name
  location                 = azurerm_resource_group.example.location
  account_tier             = "Standard"
  account_replication_type = "GRS"

  tags = {
    environment = "staging"
  }
}

Prima dichiariamo cosa vogliamo creare con il "resource type" e subito dopo si inserisce un nome per fare riferimento a questo oggetto.

Struttura di Terraform

Questa è la struttura di cartelle per il codice Terraform:

azure-lab-avd-terraform-folder-structure-modules-vsc-01.png

Per l'utilizzo e la gestione del codice si consiglia un editor come Visual Studio Code con le seguenti estensioni installate:

  1. Azure Terraform
  2. HashiCorp Terraform

azure-lab-avd-terraform-vsc-extensions-recommended-01.png

Files di Terraform

Terraform é basato su provider e ognuno di essi ci consente di effettuare diverse operazioni, in questo andremo ad utilizzare azurerm e azuread.

In questo caso, "azurerm" e "azuread" si riferiscono rispettivamente a Azure Resource Manager e Azure Active Directory. "hashicorp/azurerm" e "hashicorp/azuread" utilizzano i repository di HashiCorp per i file necessari per entrambi gli elementi.

Al seguente link è possibile trovare una lista con tutti i providers supportati: https://registry.terraform.io/browse/providers

In terraform i file hanno estensione .tf, per iniziare a scrivere una configurazione sono necessari i seguenti:

  • provider.tf - contiene il blocco terraform, le configurazioni del provider e gli alias
  • main.tf - contenente i blocchi delle risorse che definiscono le risorse da creare nella piattaforma di destinazione
  • variables.tf - contenente le dichiarazioni delle variabili utilizzate nei blocchi di risorse
  • output.tf - contenente l'output che deve essere generato al completamento dell'operazione "apply"
  • *.tfvars - contenente i valori predefiniti delle variabili specifiche dell'ambiente

Non è necessario che i file abbiano esattamente gli stessi nomi elencati sopra o che vengano utilizzati tutti, tuttavia si tratta di convenzioni generali utilizzate nei progetti.

Moduli in Terraform

I moduli sono un ottimo modo per seguire il principio DRY quando si lavora con Terraform. I moduli incapsulano un insieme di file di configurazione di Terraform creati per servire uno scopo specifico, possiamo suddividere e raggruppare l'infrastruttura in base al tipo di componenti o al servizio che supportano.

Nel nostro caso andremo a usare vari moduli, così da settorializzare il processo di distribuzione dell'infrastruttura in varie fasi e rendere il codice più semplice da interpretare oltre che da eseguire.

E' stata creata partendo da Visual Studio Code che ci aiuterà nella scrittura del codice:

azure-lab-avd-terraform-folder-structure-modules-vsc-02.png

La cartella principale del progetto contiene il suo insieme di file di configurazione, oltre ai blocchi di risorse generali, in questi file di configurazione vengono dichiarati anche i blocchi dei moduli.

I blocchi di moduli fanno riferimento alla fonte di questi moduli, che può essere un repository git remoto, un registro Terraform o un modulo sviluppato localmente (cartella).

Riportiamo un esempio, il blocco modulo qui sotto utilizza un modulo memorizzato remotamente:

module "terraform_test_module" {
 source  = "sorint.com/your-org/terraform_test_module"
 version = "1.0.0"

 argument_1                     = var.test_1
 argument_2                     = var.test_2
 argument_3                     = var.test_3
}

Terraform state

Terraform registra le informazioni sulle risorse create in un file di stato. Ciò consente a Terraform stesso di sapere quali risorse sono sotto il suo controllo e quando aggiornarle e distruggerle. Il file di stato, per impostazione predefinita, si chiama terraform.tfstate e si trova nella stessa directory in cui viene eseguito Terraform, viene creato dopo aver eseguito terraform apply.

Il contenuto effettivo di questo file è una mappatura in formato JSON delle risorse definite nella configurazione e di quelle esistenti nell'infrastruttura. Quando Terraform viene eseguito, può utilizzare questa mappatura per confrontare l'infrastruttura con il codice e apportare le modifiche necessarie.

Suggerimenti per la scrittura del codice

Gli step necessari per la buona riuscita del codice sono:

  • Identificazione di ció che va creato e relative configurazioni
  • Identificazione dei provider Terraform necessari per ottenere l’obbiettivo
  • Inserire i provider nel file provider.tf
  • Scrivere il codice nel file main.tf aggiornando il file variables.tf, dopo ogni risorsa scritta, con le variabili utilizzate
  • Assegnare un valore alle variabili scritte in variables.tf nel file variables.tfvars

L’esecuzione di Terraform non é sequenziale, di conseguenza non é necessario seguire un pattern di scrittura dei componenti, essa in oltre lavora con 10 stream paralleli che garantiscono l’esecuzione di piú attivitá in parallelo.

La sequenza di esecuzione del codice viene definita con delle dipendenze in base ai seguenti scenari:

  • Nessuna dipendenza
  • Dipendenze implicite
  • Dipendenze esplicite

File providers.tf

Il file providers.tf è presente in ogni modulo ed è così configurato:

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>3.74"
    }
    azuread = {
      source = "hashicorp/azuread"
    }
  }
}
provider "azurerm" {
  features {}
}

Resource Group module

Partiamo dal modulo relativo alla creazione del Resource Group perchè, oltre a essere quello più semplice, è anche quello su cui poi andremo a inserire tutte le risorse.

Nel file main.tf andiamo a scrivere il codice per la creazione della risorsa:

# Resource group name is output when execution plan is applied
resource "azurerm_resource_group" "resource-group" {
  name     = var.rg-name
  location = var.resource-location
  tags = var.tags
}

Il file variables.tf contiene le variabili richiamati nei parametri di configurazioni:

variable "rg-name" {
  type = string
}
variable "resource-location" {
  type = string
}
variable "tags" {
  type = map(string)
}

Essendo il nome del Resource Group richiamato in vari moduli si renderà necessario anche in altri file main.tf. Output.tf contiene le definizioni di output per il nostro modulo, utilizzate per passare informazioni sulle parti dell'infrastruttura definite da questo modulo ad altre parti della configurazione:

output "rg-name" {
  value = azurerm_resource_group.resource-group.name
}

Tornando al file delle varibili, abbiamo preferito indicare la "resource-location" e i "tags" nel file variables.tf principale in radice perchè sia i tag che la region in cui andremo a distribuire le risorse saranno sempre gli stessi. Tramite il main.tf principale dove poi andremo a richiamare i moduli passeremo i valori desiderati.

Network resources module

Questo modulo andrà a contenere tutte le risorse network di base necessarie come:

  • Virtual Network
  • Subnet
  • Network Security Group

In questo main.tf si potrebbero anche configurare i peering nel caso in cui il progetto preveda il collegamento della vNet di spoke con l'Hub principale.

# Create virtual network for spoke
resource "azurerm_virtual_network" "vnet" {
  name                = var.vnet-name
  location            = var.resource-location
  resource_group_name = var.rg-name
  address_space       = ["10.10.0.0/16"]
}

# Create subnet for avd
resource "azurerm_subnet" "snet" {
  name                 = var.snet-name
  resource_group_name  = var.rg-name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.10.0.0/24"]
}

# Create Network Security Group
resource "azurerm_network_security_group" "nsg" {
  name                = var.ngs-name
  location            = var.resource-location
  resource_group_name = var.rg-name
  security_rule {
    name                       = "allow-rdp"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = 3389
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }
}

# Associate Network Security Group to Subnet
resource "azurerm_subnet_network_security_group_association" "nsg-association" {
  subnet_id                 = azurerm_subnet.snet.id
  network_security_group_id = azurerm_network_security_group.nsg.id
}

I file variables.tf in questo caso è il seguente:

variable "rg-name" {
  type = string
}

variable "resource-location" {
  type = string
}

variable "vnet-name" {
  type = string
}

variable "snet-name" {
  type = string
}

variable "ngs-name" {
  type = string
}

In output andiamo a riportare la l'ID della subnet perchè sarà necessario quando si andrà a fare la creazione delle schede di rete delle macchine virtuali.

output "avd-snet" {
  value = azurerm_subnet.snet.id
}

Azure Virtual Desktop module

Questo modulo è molto importante perchè andrà a contenere tutto quello che è il back-plane di gestione di Azure Virtual Desktop, quindi: Workspace, Host Pool e Application Group.

# Create AVD workspace
resource "azurerm_virtual_desktop_workspace" "avd-workspace" {
  name                = var.avd-workspace-name
  resource_group_name = var.rg-name
  location            = var.resource-location
  friendly_name       = "${var.avd-vm-prefix} Workspace"
  description         = "${var.avd-vm-prefix} Workspace"
}

# Create AVD host pool
resource "azurerm_virtual_desktop_host_pool" "avd-hostpool" {
  resource_group_name      = var.rg-name
  location                 = var.resource-location
  name                     = var.avd-hostpool-name
  friendly_name            = var.avd-hostpool-name
  validate_environment     = var.avd-hostpool-validate-env
  start_vm_on_connect      = var.avd-hostpool-start-vm
  # custom_rdp_properties  = "targetisaadjoined:i:1;drivestoredirect:s:*;audiomode:i:0;videoplaybackmode:i:1;redirectclipboard:i:1;redirectprinters:i:1;devicestoredirect:s:*;redirectcomports:i:1;redirectsmartcards:i:1;usbdevicestoredirect:s:*;enablecredsspsupport:i:1;redirectwebauthn:i:1;use multimon:i:1;enablerdsaadauth:i:1;"
  description              = "${var.avd-vm-prefix} Terraform HostPool"
  type                     = var.avd-hostpool-type
  maximum_sessions_allowed = 15
  load_balancer_type       = var.avd-hostpool-load-balancer-type
  scheduled_agent_updates {
    enabled = true
    timezone = "Central European Standard Time"
    schedule {
      day_of_week = "Sunday"
      hour_of_day = 4
    }
  }
}

resource "time_rotating" "avd_registration_expiration" {
  # Must be between 1 hour and 30 days
  rotation_days = 29
}

# Create the registration information for the host pool, information includes host pool ID and an expiration date specified in var.rfc3339
resource "azurerm_virtual_desktop_host_pool_registration_info" "registrationinfo" {
  hostpool_id     = azurerm_virtual_desktop_host_pool.avd-hostpool.id
  expiration_date = time_rotating.avd_registration_expiration.rotation_rfc3339
}

# Create AVD Desktop Application Group
resource "azurerm_virtual_desktop_application_group" "avd-dag" {
  resource_group_name = var.rg-name
  host_pool_id        = azurerm_virtual_desktop_host_pool.avd-hostpool.id
  location            = var.resource-location
  type                = "Desktop"
  name                = "${var.avd-vm-prefix}-dag"
  friendly_name       = "Desktop AppGroup"
  description         = "AVD application group"
  depends_on          = [
                          azurerm_virtual_desktop_host_pool.avd-hostpool, 
                          azurerm_virtual_desktop_workspace.avd-workspace
                        ]
}

# Associate Workspace and Application Group
resource "azurerm_virtual_desktop_workspace_application_group_association" "ws-dag" {
  application_group_id = azurerm_virtual_desktop_application_group.avd-dag.id
  workspace_id         = azurerm_virtual_desktop_workspace.avd-workspace.id
}

Riporto anche in questo caso il file delle variabili:

variable "rg-name" {
type        = string
description = "Name of the Resource group in which to deploy service objects"
}

variable "resource-location" {
  type = string
}

variable "avd-workspace-name" {
type        = string
default     = "AVD TF Workspace"
}

variable "avd-hostpool-name" {
type        = string
default     = "AVD-TF-HP"
}

variable "avd-hostpool-validate-env" {
  type = bool
}

variable "avd-hostpool-start-vm" {
  type = bool
}

variable "avd-hostpool-type" {
  type = string
}

variable "avd-hostpool-load-balancer-type" {
  type = string
}

variable "avd-vm-prefix" {
type        = string
description = "Prefix of the name of the AVD machine(s)"
}

In output dobbiamo riportarci un pò di valori (principalmente relativi all'Host Pool) necessari quando andremo a creare i Session Hosts:

output "avd-host-pool-id" {
  value = azurerm_virtual_desktop_host_pool.avd-hostpool.id
}

output "avd-host-pool-name" {
  value = azurerm_virtual_desktop_host_pool.avd-hostpool.name
}

output "avd-host-pool-reg-token" {
  value = azurerm_virtual_desktop_host_pool_registration_info.registrationinfo.token
}

output "avd-application-group-id" {
  value = azurerm_virtual_desktop_application_group.avd-dag.id
}

Dopo aver creato l'Host Pool che conterrà le configurazioni di Azure Virtual Desktop possiamo procedere con la creazione dei Session Hosts, ovvero le macchine che si andranno a registrare al pool e ospiteranno le sessioni degli utenti.

Session Host module

E' sicuramente il modulo più "complesso" in quanto è quello che contiene anche più righe.

Inizialmente vengono create le schede di rete per le macchine virtuali, successivamente vengono create le macchine con l'aggiunta delle estensioni necessarie per il Join con Azure AD e la registrazione con il pool di Azure Virtual Desktop.

Viene fatto uso del count per andare a creare un numero di macchine scelto tramite la valorizzazione di una variabile.

# Create NIC for sessions hosts
resource "azurerm_network_interface" "avd-nic" {
  count               = var.avd-host-pool-size
  # name                = "${var.avd-vm-prefix}-${count.index + 1}-nic"
  name                = "${var.avd-vm-prefix}-${format("%02d",count.index+1)}-nic"
  resource_group_name = var.rg-name
  location            = var.resource-location

  ip_configuration {
    name                          = "nic${count.index + 1}_config"
    subnet_id                     = var.avd-snet
    private_ip_address_allocation = "Dynamic"
  }
}

# Function to generate random passowrd to use for local admin account
resource "random_password" "avd-local-admin" {
  length           = 16
  special          = true
  min_special      = 2
  override_special = "*!@#?"
}

# Save the result of the function in a local variable
locals {
  avd-local-admin-password = random_password.avd-local-admin.result
}

# Print the output as a string at the end of the terraform cycle
output "avd-local-admin-password" {
  value = "${local.avd-local-admin-password}"
}

# Virtual Machine creation
resource "azurerm_windows_virtual_machine" "avd-vm" {
  count                 = var.avd-host-pool-size
  name                  = "${var.avd-vm-prefix}-${count.index + 1}"
  resource_group_name   = var.rg-name
  location              = var.resource-location
  size                  = "Standard_D4s_v4"
  license_type          = "Windows_Client"
  network_interface_ids = ["${azurerm_network_interface.avd-nic.*.id[count.index]}"]
  provision_vm_agent    = true
  admin_username        = "avd-local-admin"
  admin_password        = local.avd-local-admin-password

  additional_capabilities {
  }
  identity {
    type = "SystemAssigned"
  }

  os_disk {
    name                 = "${lower(var.avd-vm-prefix)}-${count.index + 1}"
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }

  source_image_reference {
    publisher = "MicrosoftWindowsDesktop"
    offer     = "Windows-10"
    sku       = "20h2-evd"
    version   = "latest"
  }
}

# Add VM extension for Azure AD join
resource "azurerm_virtual_machine_extension" "avd-azuread-join" {
  count                      = var.avd-host-pool-size
  name                       = "AADLoginForWindows"
  virtual_machine_id         = azurerm_windows_virtual_machine.avd-vm[count.index].id
  publisher                  = "Microsoft.Azure.ActiveDirectory"
  type                       = "AADLoginForWindows"
  type_handler_version       = "2.0"
  auto_upgrade_minor_version = true

  depends_on = [
    azurerm_windows_virtual_machine.avd-vm
  ]
}

# Register the session host to Azure Virtual Desktop
resource "azurerm_virtual_machine_extension" "avd_register_session_host" {
  count                = var.avd-host-pool-size
  name                 = "register-session-host-to-avd"
  virtual_machine_id   = azurerm_windows_virtual_machine.avd-vm[count.index].id
  publisher            = "Microsoft.Powershell"
  type                 = "DSC"
  type_handler_version = "2.73"

  settings = <<-SETTINGS
    {
      "modulesUrl": "${var.avd_register_session_host_modules_url}",
      "configurationFunction": "Configuration.ps1\\AddSessionHost",
      "properties": {
        "hostPoolName": "${var.avd-host-pool-name}",
        "aadJoin": true,
        "UseAgentDownloadEndpoint": true,
        "aadJoinPreview": false,
        "mdmId": "",
        "sessionHostConfigurationLastUpdateTime": ""
      }
    }
  SETTINGS

  protected_settings = <<-PROTECTED_SETTINGS
    {
      "properties": {
        "registrationInfoToken": "${var.avd-host-pool-reg-token}"
      }
    }
    PROTECTED_SETTINGS

  lifecycle {
    ignore_changes = [settings, protected_settings]
  }

  depends_on = [azurerm_virtual_machine_extension.avd-azuread-join]
}

Il file variables in questo caso è così composto:

variable "avd-host-pool-size" {
  type        = number
  description = "Number of session hosts to add to the AVD host pool."
}

variable "avd-host-pool-id" {
  type = string
}

variable "avd-host-pool-name" {
  type = string
}

variable "avd-host-pool-reg-token" {
  type = string
}

variable "resource-location" {
  type = string
}

variable "rg-name" {
  type = string
}

variable "avd-vm-prefix" {
type        = string
description = "Prefix of the name of the AVD machine(s)"
}

variable "avd-snet" {
  type = string
}

variable "avd_register_session_host_modules_url" {
  type        = string
  description = "URL to .zip file containing DSC configuration to register AVD session hosts to AVD host pool"
  default     = "https://wvdportalstorageblob.blob.core.windows.net/galleryartifacts/Configuration_09-08-2022.zip"
}

Richiamare i moduli

Ora che abbiamo i moduli pronti possiamo procedere richiamando ogni modulo all'interno del file main.tf principale:

module "ResourceGroup" {
  source = "./ResourceGroup"
  rg-name = "rg-lab-terraform-001"
  resource-location = var.resource-location
  tags = var.tags
}

module "NetworkResources" {
  source = "./NetworkResources"
  rg-name = module.ResourceGroup.rg-name
  resource-location = var.resource-location
  vnet-name = "vnet-avd"
  snet-name = "snet-avd"
  ngs-name = "nsg-avd"
}

module "AzureVirtualDesktop" {
  source = "./AzureVirtualDesktop"
  rg-name = module.ResourceGroup.rg-name 
  resource-location = var.resource-location
  avd-hostpool-validate-env = false
  avd-vm-prefix = "vmavdterraform"
  avd-hostpool-load-balancer-type = "BreadthFirst" #[BreadthFirst, DepthFirst]
  avd-hostpool-type = "Pooled" #[Pooled, Personal]
  avd-hostpool-start-vm = true
}

module "SessionHost" {
  source = "./SessionHost"
  rg-name = module.ResourceGroup.rg-name
  resource-location = var.resource-location
  avd-host-pool-name = module.AzureVirtualDesktop.avd-host-pool-name
  avd-host-pool-id = module.AzureVirtualDesktop.avd-host-pool-id
  avd-host-pool-size = 2
  avd-host-pool-reg-token = module.AzureVirtualDesktop.avd-host-pool-reg-token
  avd-vm-prefix = "Terraform"
  avd-snet = module.NetworkResources.avd-snet
}

Per richiamare un modulo è sufficiente indicarlo nel source, successivamente per passare i valori di output derivanti da un altro modulo si deve scrivere il nome della variabile e valorizzarla richiamando l'output: module.modulosorgente.output

Preparazione dell'ambiente

Per installare molto velocemente Terraform in Windows potete lanciare il seguente comando da un prompt amministrativo:

choco install terraform

Dopo aver installato Terraform e predisposto i file possiamo iniziare il processo di distribuzione vero e proprio.

Per lanciare il codice avremo bisogno di un utente che abbia i permessi per effettuare le operazioni descritte nel codice.

  • Aprire una sessione terminal
  • Navigare nella sessione fino ad arrivare sotto la cartella radice dei file Terraform
  • Lanciare il comando az login e loggarsi con l’utenza
  • Lanciare il comando terraform init per permettere a Terraform di creare in autonomia i file necessari all’esecuzione
  • Lanciare il comando terraform plan in modo che Terraform verifichi che non vi siano errori nel codice
  • Lanciare il comando terraform apply per eseguire il codice
  • Una volta eseguito l’apply controllare su portale che le risorse create siano correttamente configurate e funzionanti

Durante il terraform apply vi verra richiesto di accettare o rifiutare le azioni che eseguirá terraform, questo vi consentirá di visualizzare un recap delle azioni che sta per eseguire in modo da ponderare se continuare l’esecuzione oppure interromperla.

Il comando terraform init inizierà il download dei moduli Azure necessari per gestire le risorse Azure definite nei file .tf e inizializza una directory di lavoro contenente i file di configurazione di Terraform

azure-lab-avd-terraform-cli-init-command-example-01.png

Andiamo ora ad eseguire il comando terraform plan. Questo valuterà la nostra configurazione di Terraform per determinare lo stato desiderato di tutte le risorse dichiarate, confronta lo stato desiderato con gli oggetti dell'infrastruttura effettivamente gestiti all'interno della directory di lavoro e dello spazio di lavoro corrente. Crea un piano di esecuzione, ma non lo esegue.

azure-lab-avd-terraform-cli-plan-command-example-01.png

L'output del comando terraform plan può essere lungo, ma controllarlo diligentemente assicura che non ci si impegni a fare il provisioning di risorse che non si intende fare.

azure-lab-avd-terraform-cli-plan-command-example-02.png

Infine, eseguire terraform apply, questo comando applica le modifiche necessarie per raggiungere lo stato desiderato della configurazione, cioè l'insieme di azioni generate dall'esecuzione di terraform plan.

Quando eseguito, si vedrà una revisione del piano che Terraform intende applicare un'ultima volta e verrà richiesto di confermare l'esecuzione digitando "yes".

azure-lab-avd-terraform-cli-apply-command-confirm-02.png

Validazione dell'ambiente

Accedere al portale Azure e selezionare "Azure Virtual Desktop" e verificare che l'infrastruttura sia presente.

azure-lab-avd-terraform-portal-checks-deploy-hostpool-01.png

Controllare anche il Resource Group e le singole risorse contenute al suo interno.

azure-lab-avd-terraform-portal-checks-deploy-rg-01.png

Clean-up delle risorse

Se si desidera eliminare tutte le risorse di cui sopra, è possibile utilizzare il comando terraform destroy.

azure-lab-avd-terraform-cli-destroy-command-example-01.png

Riferimenti

comments powered by Disqus