Een virtuele-machineschaalset in Azure maken op basis van een aangepaste Packer-afbeelding met behulp van Terraform

Met virtuele-machineschaalsets van Azure kunt u identieke VM's configureren. Het aantal VM-exemplaren kan worden aangepast op basis van de vraag of een planning. Zie Een virtuele-machineschaalset automatisch schalen in de Azure Portal voor meer Azure Portal.

In dit artikel leert u het volgende:

  • Een Terraform-implementatie instellen
  • Variabelen en uitvoer voor Terraform-implementatie gebruiken
  • Een netwerkinfrastructuur maken en implementeren
  • Een aangepaste virtuele-machine-afbeelding maken met Packer
  • Een virtuele-machineschaalset maken en implementeren met behulp van de aangepaste afbeelding
  • Een jumpbox maken en implementeren

1. Uw omgeving configureren

  • Azure-abonnement: Als u nog geen abonnement op Azure hebt, maak dan een gratis account aan voordat u begint.

2. Een Packer-afbeelding maken

  1. Installeer Packer.

    Belangrijkste punten:

    • Voer de volgende opdracht uit om te bevestigen dat u toegang hebt tot het uitvoerbare Packer-bestand: packer -v .
    • Afhankelijk van uw omgeving moet u mogelijk uw pad instellen en de opdrachtregel opnieuw openen.
  2. Voer az group create uit om een resourcegroep te maken voor de Packer-afbeelding.

    az group create -n myPackerImages -l eastus
    
  3. Voer az ad sp create-for-rbac uit om Packer in staat te stellen zich te verifiëren bij Azure met behulp van een service-principal.

    az ad sp create-for-rbac --role Contributor --query "{ client_id: appId, client_secret: password, tenant_id: tenant }"
    

    Belangrijkste punten:

    • Noteer de uitvoerwaarden ( appId , client_secret , tenant_id ).
  4. Voer az account show uit om het huidige Azure-abonnement weer te geven.

    az account show --query "{ subscription_id: id }"
    
  5. Maak een Packer-sjabloonbestand met de ubuntu.json naam en voeg de volgende code in:

    {
        "builders": [{
          "type": "azure-arm",
      
          "client_id": "0bfc2293-4d69-49b5-83f7-bf0d60d20c45",
          "client_secret": "G3.6ytCh44Kcla~_JRPBDLkzsXLOa3edDL",
          "tenant_id": "c3fd441d-b8ad-487e-aa27-453079018fca",
          "subscription_id": "b162117f-53fa-4f42-8c77-6a65ca966c40",
      
          "managed_image_resource_group_name": "myPackerImages",
          "managed_image_name": "myPackerImage",
      
          "os_type": "Linux",
          "image_publisher": "Canonical",
          "image_offer": "UbuntuServer",
          "image_sku": "16.04-LTS",
      
          "azure_tags": {
              "dept": "Engineering",
              "task": "Image deployment"
          },
      
          "location": "East US",
          "vm_size": "Standard_DS2_v2"
        }],
        "provisioners": [{
          "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"
          ],
          "inline_shebang": "/bin/sh -x",
          "type": "shell"
        }]
      }
    

    Belangrijkste punten:

    • Stel de client_id velden , en in op de respectieve waarden van uw client_secrettenant_id service-principal.
    • Stel het subscription_id veld in op de id van het Azure-abonnement.
  6. Bouw de Packer-afbeelding.

    packer build ubuntu.json
    

3. De Terraform-code implementeren

  1. Maak een map waarin u de Terraform-voorbeeldcode wilt testen en van deze de huidige map wilt maken.

  2. Maak een bestand met de main.tf naam en voeg de volgende code in:

    terraform {
    
      required_version = ">=0.12"
    
      required_providers {
        azurerm = {
          source = "hashicorp/azurerm"
          version = "~>2.0"
        }
      }
    }
    
    provider "azurerm" {
      features {}
    }
    
    resource "azurerm_resource_group" "vmss" {
      name     = var.resource_group_name
      location = var.location
      tags = var.tags
    }
    
    resource "random_string" "fqdn" {
     length  = 6
     special = false
     upper   = false
     number  = 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" {
      resource_group_name = azurerm_resource_group.vmss.name
      loadbalancer_id     = azurerm_lb.vmss.id
      name                = "ssh-running-probe"
      port                = var.application_port
    }
    
    resource "azurerm_lb_rule" "lbnatrule" {
      resource_group_name            = azurerm_resource_group.vmss.name
      loadbalancer_id                = azurerm_lb.vmss.id
      name                           = "http"
      protocol                       = "Tcp"
      frontend_port                  = var.application_port
      backend_port                   = var.application_port
      backend_address_pool_id        = 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 "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       = var.admin_password
      }
    
      os_profile_linux_config {
        disable_password_authentication = true
    
        ssh_keys {
          path     = "/home/azureuser/.ssh/authorized_keys"
          key_data = file("~/.ssh/id_rsa.pub")
        }
      }
    
      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 = var.admin_password
      }
    
      os_profile_linux_config {
        disable_password_authentication = true
    
        ssh_keys {
          path     = "/home/azureuser/.ssh/authorized_keys"
          key_data = file("~/.ssh/id_rsa.pub")
        }
      }
    
      tags = var.tags
    }
    
    
  3. Maak een bestand met de variables.tf naam dat de projectvariabelen bevat en voeg de volgende code in:

    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     = "myPackerImages"
    }
    
    variable "resource_group_name" {
       description = "Name of the resource group in which the resources will be created"
       default     = "myResourceGroup"
    }
    
    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"
    }
    
  4. Maak een bestand met de output.tf naam om op te geven welke waarden Terraform we zien en voeg de volgende code in:

    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. Terraform initialiseren

Voer terraform init uit om de Terraform-implementatie te initialiseren.

terraform init

Belangrijkste punten:

  • Met deze opdracht worden de Azure-modules gedownload die nodig zijn om een Azure-resourcegroep te maken.

5. Een Terraform-uitvoeringsplan maken

Voer terraform plan uit om een uitvoeringsplan te maken.

terraform plan -out main.tfplan

Belangrijkste punten:

  • Met terraform plan de opdracht wordt een uitvoeringsplan gemaakt, maar niet uitgevoerd. In plaats daarvan wordt bepaald welke acties nodig zijn om de configuratie te maken die is opgegeven in uw configuratiebestanden. Met dit patroon kunt u controleren of het uitvoeringsplan overeenkomt met uw verwachtingen voordat u wijzigingen aan werkelijke resources aantreft.
  • Met de -out optionele parameter kunt u een uitvoerbestand voor het plan opgeven. Door de parameter te gebruiken, zorgt u ervoor dat het plan dat -out u hebt gecontroleerd, precies is wat er wordt toegepast.
  • Zie de sectie beveiligingswaarschuwing voor meer informatie over persistente uitvoeringsplannen en beveiliging.

6. Een Terraform-uitvoeringsplan toepassen

Voer terraform apply uit om het uitvoeringsplan toe te passen op uw cloudinfrastructuur.

terraform apply main.tfplan

Belangrijkste punten:

  • Met terraform apply de bovenstaande opdracht wordt ervan uitgenomen dat u eerder hebt terraform plan -out main.tfplan gebruikt.
  • Als u een andere bestandsnaam voor de parameter hebt -out opgegeven, gebruikt u dezelfde bestandsnaam in de aanroep naar terraform apply .
  • Als u de parameter niet hebt -out gebruikt, roept u gewoon terraform apply aan zonder parameters.

7. De resultaten controleren

  1. In de uitvoer van de terraform apply opdracht ziet u waarden voor het volgende:

    • FQDN van virtuele machine
    • Jumpbox-FQDN
    • IP-adres van jumpbox
  2. Blader naar de URL van de virtuele machine om een standaardpagina te bevestigen met de tekst Welkom bij nginx!.

  3. Gebruik SSH om verbinding te maken met de jumpbox-VM met behulp van de gebruikersnaam die is gedefinieerd in het variabelenbestand en het wachtwoord dat u hebt opgegeven tijdens het gebruik terraform apply van . Bijvoorbeeld: ssh azureuser@<ip_address>.

8. Resources opschonen

Virtuele-machineschaalset verwijderen

Wanneer u de resources die via Terraform zijn gemaakt niet meer nodig hebt, moet u de volgende stappen volgen:

  1. Voer terraform plan uit en geef de vlag op.

    terraform plan -destroy -out main.destroy.tfplan
    

    Belangrijkste punten:

    • Met terraform plan de opdracht wordt een uitvoeringsplan gemaakt, maar niet uitgevoerd. In plaats daarvan wordt bepaald welke acties nodig zijn om de configuratie te maken die is opgegeven in uw configuratiebestanden. Met dit patroon kunt u controleren of het uitvoeringsplan overeenkomt met uw verwachtingen voordat u wijzigingen aan werkelijke resources aantreft.
    • Met de -out optionele parameter kunt u een uitvoerbestand voor het plan opgeven. Door de parameter te gebruiken, zorgt u ervoor dat het plan dat -out u hebt gecontroleerd, precies is wat er wordt toegepast.
    • Zie de sectie beveiligingswaarschuwing voor meer informatie over persistente uitvoeringsplannen en beveiliging.
  2. Voer terraform apply uit om het uitvoeringsplan toe te passen.

    terraform apply main.destroy.tfplan
    

Packer-afbeelding en resourcegroep verwijderen

Voer az group delete uit om de resourcegroep te verwijderen die de Packer-afbeelding bevat. De Packer-afbeelding wordt ook verwijderd.

az group delete --name myPackerImages --yes

Problemen met Terraform in Azure oplossen

Veelvoorkomende problemen bij het gebruik van Terraform in Azure oplossen

Volgende stappen