Sdílet prostřednictvím


Vytvořte škálovací sadu virtuálních počítačů Azure ze speciálního image vytvořeného nástrojem Packer pomocí Terraformu.

Terraform umožňuje definovat, prohlížet a nasazovat cloudovou infrastrukturu. Pomocí Terraformu vytvoříte konfigurační soubory pomocí syntaxe HCL. Syntaxe seznamu HCL umožňuje zadat poskytovatele cloudu , například Azure, a prvky, které tvoří vaši cloudovou infrastrukturu. Po vytvoření konfiguračních souborů vytvoříte plán provádění, který vám umožní zobrazit náhled změn infrastruktury před jejich nasazením. Jakmile ověříte změny, použijete plán provádění k nasazení infrastruktury.

Škálovací sady virtuálních počítačů Azure umožňují konfigurovat stejné virtuální počítače. Počet instancí virtuálních počítačů se může upravit na základě poptávky nebo plánu. Další informace najdete v tématu Automatické škálování škálovací sady virtuálních počítačů na webu Azure Portal.

V tomto článku se naučíte:

  • Nastavení nasazení Terraformu
  • Použití proměnných a výstupů pro nasazení Terraformu
  • Vytvoření a nasazení síťové infrastruktury
  • Vytvoření vlastní image virtuálního počítače pomocí Packeru
  • Vytvořte a nasazte škálovací sadu virtuálních počítačů pomocí vlastního obrazu
  • Vytvoření a nasazení jumpboxu

1. Konfigurace prostředí

  • Předplatné Azure: Pokud ještě nemáte předplatné Azure, vytvořte si bezplatný účet před tím, než začnete.

2. Vytvořte Packer obraz

  1. Nainstalujte packer.

    klíčové body:

    • Pokud chcete ověřit, že máte přístup ke spustitelnému souboru Packeru, spusťte následující příkaz: packer -v.
    • V závislosti na vašem prostředí možná budete muset nastavit cestu a znovu otevřít příkazový řádek.
  2. Spusťte az group create a vytvořte skupinu prostředků pro uchování obrazu Packeru.

    az group create -n myPackerImages -l eastus
    
  3. Spuštěním az ad sp create-for-rbac umožněte Packeru autentizaci v Azure pomocí aplikačního účtu.

    az ad sp create-for-rbac --role Contributor --scopes /subscriptions/<subscription_id> --query "{ client_id: appId, client_secret: password, tenant_id: tenant }"
    

    klíčové body:

    • Poznamenejte si výstupní hodnoty (appId, client_secret, tenant_id).
  4. Spuštěním příkazu az account show zobrazte aktuální předplatné Azure.

    az account show --query "{ subscription_id: id }"
    
  5. Vytvořte soubor proměnných šablony Packeru s názvem ubuntu.pkr.hcl a vložte následující kód. Aktualizujte zvýrazněné řádky s pomocí informací o představiteli služby a předplatném Azure.

    packer {
      required_plugins {
        azure = {
          source  = "github.com/hashicorp/azure"
          version = "~> 2"
        }
      }
    }
    
    variable client_id {
      type    = string
      default = null
    }
    variable client_secret {
      type    = string
      default = null
    }
    
    variable subscription_id {
      type    = string
      default = null
    }
    
    variable tenant_id {
      type    = string
      default = null
    }
    
    variable location {
      default = "eastus"
    }
    
    variable "image_resource_group_name" {
      description = "Name of the resource group in which the Packer image will be created"
      default     = "myPackerImages"
    }
    
    variable "oidc_request_url" {
      default = null
    }
    
    variable "oidc_request_token" {
      default = null
    }
    
    # arm builder
    source "azure-arm" "builder" {
      client_id                         = var.client_id
      client_secret                     = var.client_secret
      image_offer                       = "UbuntuServer"
      image_publisher                   = "canonical"
      image_sku                         = "16.04-LTS"
      location                          = var.location
      managed_image_name                = "myPackerImage"
      managed_image_resource_group_name = var.image_resource_group_name
      os_type                           = "Linux"
      subscription_id                   = var.subscription_id
      tenant_id                         = var.tenant_id
      oidc_request_url                  = var.oidc_request_url
      oidc_request_token                = var.oidc_request_token
      vm_size                           = "Standard_DS2_v2"
      azure_tags = {
        "dept" : "Engineering",
        "task" : "Image deployment",
      }
    }
    
    build {
      sources = ["source.azure-arm.builder"]
      provisioner "shell" {
        execute_command = "chmod +x {{ .Path }}; {{ .Vars }} sudo -E sh '{{ .Path }}'"
        inline = [
          "apt-get update",
          "apt-get upgrade -y",
          "apt-get -y install nginx",
          "/usr/sbin/waagent -force -deprovision+user && export HISTSIZE=0 && sync",
        ]
      }
    }
    

    klíčové body:

    • Nastavte pole client_id, client_secret a tenant_id na odpovídající hodnoty ze svého služebního hlavního objektu.
    • subscription_id Nastavte pole na ID předplatného Azure.
  6. Sestavte obraz Packeru.

    packer build ubuntu.json
    

3. Implementace kódu Terraformu

  1. Vytvořte adresář, ve kterém otestujete ukázkový kód Terraformu a nastavíte ho jako aktuální adresář.

  2. Vytvořte soubor s názvem main.tf a vložte následující kód:

    terraform {
    
      required_version = ">=0.12"
    
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "~>3.0"
        }
        azapi = {
          source  = "Azure/azapi"
          version = "~> 1.0"
        }
        local = {
          source  = "hashicorp/local"
          version = "2.4.0"
        }
        random = {
          source  = "hashicorp/random"
          version = "3.5.1"
        }
        tls = {
          source  = "hashicorp/tls"
          version = "4.0.4"
        }
      }
    }
    
    provider "azurerm" {
      features {
        resource_group {
          prevent_deletion_if_contains_resources = false
        }
      }
    }
    
    resource "random_pet" "id" {}
    
    resource "azurerm_resource_group" "vmss" {
      name     = coalesce(var.resource_group_name, "201-vmss-packer-jumpbox-${random_pet.id.id}")
      location = var.location
      tags     = var.tags
    }
    
    resource "random_string" "fqdn" {
      length  = 6
      special = false
      upper   = false
      numeric = false
    }
    
    resource "azurerm_virtual_network" "vmss" {
      name                = "vmss-vnet"
      address_space       = ["10.0.0.0/16"]
      location            = var.location
      resource_group_name = azurerm_resource_group.vmss.name
      tags                = var.tags
    }
    
    resource "azurerm_subnet" "vmss" {
      name                 = "vmss-subnet"
      resource_group_name  = azurerm_resource_group.vmss.name
      virtual_network_name = azurerm_virtual_network.vmss.name
      address_prefixes     = ["10.0.2.0/24"]
    }
    
    resource "azurerm_public_ip" "vmss" {
      name                = "vmss-public-ip"
      location            = var.location
      resource_group_name = azurerm_resource_group.vmss.name
      allocation_method   = "Static"
      domain_name_label   = random_string.fqdn.result
      tags                = var.tags
    }
    
    resource "azurerm_lb" "vmss" {
      name                = "vmss-lb"
      location            = var.location
      resource_group_name = azurerm_resource_group.vmss.name
    
      frontend_ip_configuration {
        name                 = "PublicIPAddress"
        public_ip_address_id = azurerm_public_ip.vmss.id
      }
    
      tags = var.tags
    }
    
    resource "azurerm_lb_backend_address_pool" "bpepool" {
      loadbalancer_id = azurerm_lb.vmss.id
      name            = "BackEndAddressPool"
    }
    
    resource "azurerm_lb_probe" "vmss" {
      loadbalancer_id = azurerm_lb.vmss.id
      name            = "ssh-running-probe"
      port            = var.application_port
    }
    
    resource "azurerm_lb_rule" "lbnatrule" {
      loadbalancer_id                = azurerm_lb.vmss.id
      name                           = "http"
      protocol                       = "Tcp"
      frontend_port                  = var.application_port
      backend_port                   = var.application_port
      backend_address_pool_ids       = [azurerm_lb_backend_address_pool.bpepool.id]
      frontend_ip_configuration_name = "PublicIPAddress"
      probe_id                       = azurerm_lb_probe.vmss.id
    }
    
    data "azurerm_resource_group" "image" {
      name = var.packer_resource_group_name
    }
    
    data "azurerm_image" "image" {
      name                = var.packer_image_name
      resource_group_name = data.azurerm_resource_group.image.name
    }
    
    resource "azapi_resource" "ssh_public_key" {
      type      = "Microsoft.Compute/sshPublicKeys@2022-11-01"
      name      = random_pet.id.id
      location  = azurerm_resource_group.vmss.location
      parent_id = azurerm_resource_group.vmss.id
    }
    
    resource "azapi_resource_action" "ssh_public_key_gen" {
      type        = "Microsoft.Compute/sshPublicKeys@2022-11-01"
      resource_id = azapi_resource.ssh_public_key.id
      action      = "generateKeyPair"
      method      = "POST"
    
      response_export_values = ["publicKey", "privateKey"]
    }
    
    resource "random_password" "password" {
      count  = var.admin_password == null ? 1 : 0
      length = 20
    }
    
    locals {
      admin_password = try(random_password.password[0].result, var.admin_password)
    }
    
    resource "azurerm_virtual_machine_scale_set" "vmss" {
      name                = "vmscaleset"
      location            = var.location
      resource_group_name = azurerm_resource_group.vmss.name
      upgrade_policy_mode = "Manual"
    
      sku {
        name     = "Standard_DS1_v2"
        tier     = "Standard"
        capacity = 2
      }
    
      storage_profile_image_reference {
        id = data.azurerm_image.image.id
      }
    
      storage_profile_os_disk {
        name              = ""
        caching           = "ReadWrite"
        create_option     = "FromImage"
        managed_disk_type = "Standard_LRS"
      }
    
      storage_profile_data_disk {
        lun           = 0
        caching       = "ReadWrite"
        create_option = "Empty"
        disk_size_gb  = 10
      }
    
      os_profile {
        computer_name_prefix = "vmlab"
        admin_username       = var.admin_user
        admin_password       = local.admin_password
      }
    
      os_profile_linux_config {
        disable_password_authentication = true
    
        ssh_keys {
          path     = "/home/azureuser/.ssh/authorized_keys"
          key_data = azapi_resource_action.ssh_public_key_gen.output.publicKey
        }
      }
    
      network_profile {
        name    = "terraformnetworkprofile"
        primary = true
    
        ip_configuration {
          name                                   = "IPConfiguration"
          subnet_id                              = azurerm_subnet.vmss.id
          load_balancer_backend_address_pool_ids = [azurerm_lb_backend_address_pool.bpepool.id]
          primary                                = true
        }
      }
    
      tags = var.tags
    }
    
    resource "azurerm_public_ip" "jumpbox" {
      name                = "jumpbox-public-ip"
      location            = var.location
      resource_group_name = azurerm_resource_group.vmss.name
      allocation_method   = "Static"
      domain_name_label   = "${random_string.fqdn.result}-ssh"
      tags                = var.tags
    }
    
    resource "azurerm_network_interface" "jumpbox" {
      name                = "jumpbox-nic"
      location            = var.location
      resource_group_name = azurerm_resource_group.vmss.name
    
      ip_configuration {
        name                          = "IPConfiguration"
        subnet_id                     = azurerm_subnet.vmss.id
        private_ip_address_allocation = "Dynamic"
        public_ip_address_id          = azurerm_public_ip.jumpbox.id
      }
    
      tags = var.tags
    }
    
    resource "azurerm_virtual_machine" "jumpbox" {
      name                  = "jumpbox"
      location              = var.location
      resource_group_name   = azurerm_resource_group.vmss.name
      network_interface_ids = [azurerm_network_interface.jumpbox.id]
      vm_size               = "Standard_DS1_v2"
    
      storage_image_reference {
        publisher = "Canonical"
        offer     = "UbuntuServer"
        sku       = "16.04-LTS"
        version   = "latest"
      }
    
      storage_os_disk {
        name              = "jumpbox-osdisk"
        caching           = "ReadWrite"
        create_option     = "FromImage"
        managed_disk_type = "Standard_LRS"
      }
    
      os_profile {
        computer_name  = "jumpbox"
        admin_username = var.admin_user
        admin_password = local.admin_password
      }
    
      os_profile_linux_config {
        disable_password_authentication = true
    
        ssh_keys {
          path     = "/home/azureuser/.ssh/authorized_keys"
          key_data = azapi_resource_action.ssh_public_key_gen.output.publicKey
        }
      }
    
      tags = var.tags
    }
    
  3. Vytvořte soubor s názvem variables.tf , který bude obsahovat proměnné projektu, a vložte následující kód:

    variable "packer_resource_group_name" {
      description = "Name of the resource group in which the Packer image will be created"
      default     = "myPackerImages"
    }
    
    variable "packer_image_name" {
      description = "Name of the Packer image"
      default     = "myPackerImage"
    }
    
    variable "resource_group_name" {
      description = "Name of the resource group in which the Packer image  will be created"
      default     = null
    }
    
    variable "location" {
      default     = "eastus"
      description = "Location where resources will be created"
    }
    
    variable "tags" {
      description = "Map of the tags to use for the resources that are deployed"
      type        = map(string)
      default = {
        environment = "codelab"
      }
    }
    
    variable "application_port" {
      description = "Port that you want to expose to the external load balancer"
      default     = 80
    }
    
    variable "admin_user" {
      description = "User name to use as the admin account on the VMs that will be part of the VM scale set"
      default     = "azureuser"
    }
    
    variable "admin_password" {
      description = "Default password for admin account"
      default     = null
    }
    
  4. Vytvořte soubor s názvem output.tf , který určuje, jaké hodnoty Terraform zobrazí, a vložte následující kód:

    output "vmss_public_ip_fqdn" {
      value = azurerm_public_ip.vmss.fqdn
    }
    
    output "jumpbox_public_ip_fqdn" {
      value = azurerm_public_ip.jumpbox.fqdn
    }
    
    output "jumpbox_public_ip" {
      value = azurerm_public_ip.jumpbox.ip_address
    }
    

4. Inicializujte Terraform

Spusťte terraform init a inicializujte nasazení Terraformu. Tento příkaz stáhne poskytovatele Azure potřebného ke správě prostředků Azure.

terraform init -upgrade

klíčové body:

  • Parametr -upgrade aktualizuje potřebné pluginy poskytovatele na nejnovější verzi, která odpovídá verzním omezením konfigurace.

5. Vytvoření plánu provádění Terraformu

Spusťte terraform plan pro vytvoření plánu provedení.

terraform plan -out main.tfplan

klíčové body:

  • Příkaz terraform plan vytvoří plán provádění, ale nespustí ho. Místo toho určuje, jaké akce jsou nezbytné k vytvoření konfigurace zadané v konfiguračních souborech. Tento model umožňuje ověřit, jestli plán provádění odpovídá vašim očekáváním, než provede jakékoli změny skutečných prostředků.
  • Volitelný -out parametr umožňuje zadat výstupní soubor pro plán. Použití parametru -out zajišťuje, že vámi zkontrolovaný plán je přesně tím, co bude aplikován.

6. Použijte plán provádění Terraformu

Spusťte terraform apply, abyste aplikovali plán provádění na vaši cloudovou infrastrukturu.

terraform apply main.tfplan

klíčové body:

  • terraform apply Ukázkový příkaz předpokládá, že jste dříve spustili terraform plan -out main.tfplan.
  • Pokud jste pro -out parametr zadali jiný název souboru, použijte stejný název souboru při volání terraform apply.
  • Pokud jste parametr nepoužíli -out , zavolejte terraform apply bez parametrů.

7. Ověření výsledků

  1. Ve výstupu terraform apply příkazu se zobrazí následující hodnoty:

    • Plně kvalifikovaný název domény virtuálního počítače
    • Plně kvalifikovaný název domény pro jumpbox
    • IP adresa jumpboxu
  2. Přejděte na adresu URL virtuálního počítače a potvrďte výchozí stránku s textem Vítá vás nginx!.

  3. Pomocí SSH se připojte k virtuálnímu počítači jumpbox pomocí uživatelského jména definovaného v souboru proměnných a hesla, které jste zadali při spuštění terraform apply. Například: ssh azureuser@<ip_address>.

8. Vyčištění prostředků

Odstranění škálovací sady virtuálních počítačů

Pokud už prostředky vytvořené přes Terraform nepotřebujete, proveďte následující kroky:

  1. Spusťte terraform plan a zadejte parametr destroy.

    terraform plan -destroy -out main.destroy.tfplan
    

    klíčové body:

    • Příkaz terraform plan vytvoří plán provádění, ale nespustí ho. Místo toho určuje, jaké akce jsou nezbytné k vytvoření konfigurace zadané v konfiguračních souborech. Tento model umožňuje ověřit, jestli plán provádění odpovídá vašim očekáváním, než provede jakékoli změny skutečných prostředků.
    • Volitelný -out parametr umožňuje zadat výstupní soubor pro plán. Použití parametru -out zajišťuje, že vámi zkontrolovaný plán je přesně tím, co bude aplikován.
  2. Spusťte terraform apply pro aplikaci prováděcího plánu.

    terraform apply main.destroy.tfplan
    

Odstranit image Packeru a skupinu prostředků

Spusťte az group delete a odstraňte skupinu prostředků použitou k zahrnutí obrazu Packer. Image Packeru je také odstraněna.

az group delete --name myPackerImages --yes

Řešení potíží s Terraformem v Azure

Řešení běžných problémů při používání Terraformu v Azure

Další kroky