次の方法で共有


クイックスタート:Terraform を使用して VM の内部トラフィックを負荷分散するための内部ロードバランサーを作成する

このクイックスタートでは、Terraformを使用して標準的な内部ロードバランサーと2台の仮想マシンをデプロイする方法を紹介します。 追加のリソースには、Azure Bastion、NAT Gateway、仮想ネットワーク、および必要なサブネットが含まれます。

Terraformはクラウドインフラストラクチャの定義、プレビュー、そしてデプロイメントを可能にします。 Terraform を使用する際は、HCL 構文を使って構成ファイルを作成します。 HCL 構文では、Azure などのクラウド プロバイダーと、クラウド インフラストラクチャを構成する要素を指定できます。 あなたの設定ファイルを作成した後、実行計画を作成します。これにより、インフラストラクチャの変更をデプロイする前にプレビューすることができます。 変更を確認したら、実行プランを適用してインフラストラクチャをデプロイします。

[前提条件]

Terraformコードを実装する

この記事のサンプル コードは、Azure Terraform GitHub リポジトリにあります。 Terraform の現在および以前のバージョンからのテスト結果を含むログ ファイルを表示できます。 Terraform を使用して Azure リソースを管理する方法を示す 記事とサンプル コード

  1. サンプル Terraform コードをテストして実行するディレクトリを作成し、それを現在のディレクトリにします。

  2. providers.tf という名前のファイルを作成し、次のコードを挿入します。

    terraform {
      required_providers {
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "~>4.0"
        }
        random = {
          source  = "hashicorp/random"
          version = "~>3.0"
        }
      }
    }
    
    provider "azurerm" {
      features {}
    }
    
  3. main.tf という名前のファイルを作成し、次のコードを挿入します。

    # Create a random name for the resource group
    resource "random_pet" "rg" {
      prefix = var.resource_group_name_prefix
    }
    
    # Create a resource group using the generated random name
    resource "azurerm_resource_group" "example" {
      location = var.resource_group_location
      name     = random_pet.rg.id
    }
    
    # Create a Virtual Network to host the Virtual Machines 
    # in the Backend Pool of the Load Balancer
    resource "azurerm_virtual_network" "example" {
      name                = var.virtual_network_name
      address_space       = ["10.0.0.0/16"]
      location            = azurerm_resource_group.example.location
      resource_group_name = azurerm_resource_group.example.name
    }
    
    # Create a subnet in the Virtual Network to host the Virtual Machines
    # in the Backend Pool of the Load Balancer
    resource "azurerm_subnet" "example" {
      name                 = var.subnet_name
      resource_group_name  = azurerm_resource_group.example.name
      virtual_network_name = azurerm_virtual_network.example.name
      address_prefixes     = ["10.0.1.0/24"]
    }
    
    # Create a subnet in the Virtual Network for creating Azure Bastion
    # This subnet is required for Azure Bastion to work properly
    resource "azurerm_subnet" "bastion" {
      name                 = "AzureBastionSubnet"
      resource_group_name  = azurerm_resource_group.example.name
      virtual_network_name = azurerm_virtual_network.example.name
      address_prefixes     = ["10.0.2.0/24"]
    }
    
    # Create Network Security Group and rules to control the traffic
    # to and from the Virtual Machines in the Backend Pool
    resource "azurerm_network_security_group" "example" {
      name                = var.network_security_group_name
      location            = azurerm_resource_group.example.location
      resource_group_name = azurerm_resource_group.example.name
    
      security_rule {
        name                       = "ssh"
        priority                   = 1022
        direction                  = "Inbound"
        access                     = "Allow"
        protocol                   = "Tcp"
        source_port_range          = "*"
        destination_port_range     = "22"
        source_address_prefix      = "*"
        destination_address_prefix = "10.0.1.0/24"
      }
    
      security_rule {
        name                       = "web"
        priority                   = 1080
        direction                  = "Inbound"
        access                     = "Allow"
        protocol                   = "Tcp"
        source_port_range          = "*"
        destination_port_range     = "80"
        source_address_prefix      = "*"
        destination_address_prefix = "10.0.1.0/24"
      }
    }
    
    # Associate the Network Security Group to the subnet to allow the
    # Network Security Group to control the traffic to and from the subnet
    resource "azurerm_subnet_network_security_group_association" "example" {
      subnet_id                 = azurerm_subnet.example.id
      network_security_group_id = azurerm_network_security_group.example.id
    }
    
    # Create Public IPs to route traffic from the Load Balancer
    # to the Virtual Machines in the Backend Pool
    resource "azurerm_public_ip" "example" {
      count               = 2
      name                = "${var.public_ip_name}-${count.index}"
      location            = azurerm_resource_group.example.location
      resource_group_name = azurerm_resource_group.example.name
      allocation_method   = "Static"
      sku                 = "Standard"
    }
    
    # Create a NAT Gateway for outbound internet access of the 
    # Virtual Machines in the Backend Pool of the Load Balancer
    resource "azurerm_nat_gateway" "example" {
      name                = var.nat_gateway
      location            = azurerm_resource_group.example.location
      resource_group_name = azurerm_resource_group.example.name
      sku_name            = "Standard"
    }
    
    # Associate one of the Public IPs to the NAT Gateway to route
    # traffic from the Virtual Machines to the internet
    resource "azurerm_nat_gateway_public_ip_association" "example" {
      nat_gateway_id       = azurerm_nat_gateway.example.id
      public_ip_address_id = azurerm_public_ip.example[0].id
    }
    
    # Associate the NAT Gateway to subnet to route 
    # traffic from the Virtual Machines to the internet
    resource "azurerm_subnet_nat_gateway_association" "example" {
      subnet_id      = azurerm_subnet.example.id
      nat_gateway_id = azurerm_nat_gateway.example.id
    }
    
    # Create Network Interfaces
    # The Network Interfaces will be associated with the
    # Virtual Machines created later
    resource "azurerm_network_interface" "example" {
      count               = 3
      name                = "${var.network_interface_name}-${count.index}"
      location            = azurerm_resource_group.example.location
      resource_group_name = azurerm_resource_group.example.name
    
      ip_configuration {
        name                          = "ipconfig-${count.index}"
        subnet_id                     = azurerm_subnet.example.id
        private_ip_address_allocation = "Dynamic"
        primary                       = true
      }
    }
    
    # Create Azure Bastion for accessing the Virtual Machines
    # The Bastion Host will be used to access the Virtual 
    # Machines in the Backend Pool of the Load Balancer
    resource "azurerm_bastion_host" "example" {
      name                = var.bastion_name
      location            = azurerm_resource_group.example.location
      resource_group_name = azurerm_resource_group.example.name
      sku                 = "Standard"
    
      ip_configuration {
        name                 = "ipconfig"
        subnet_id            = azurerm_subnet.bastion.id
        public_ip_address_id = azurerm_public_ip.example[1].id
      }
    }
    
    # Associate Network Interface to the Backend Pool of the Load Balancer
    # The Network Interface will be used to route traffic to the Virtual
    # Machines in the Backend Pool
    resource "azurerm_network_interface_backend_address_pool_association" "example" {
      count                   = 2
      network_interface_id    = azurerm_network_interface.example[count.index].id
      ip_configuration_name   = "ipconfig-${count.index}"
      backend_address_pool_id = azurerm_lb_backend_address_pool.example.id
    }
    
    # Generate a random password for the VM admin users
    resource "random_password" "example" {
      length  = 16
      special = true
      lower   = true
      upper   = true
      numeric = true
    }
    
    # Create three Virtual Machines in the Backend Pool of the Load Balancer 
    resource "azurerm_linux_virtual_machine" "example" {
      count                 = 3
      name                  = "${var.virtual_machine_name}-${count.index}"
      location              = azurerm_resource_group.example.location
      resource_group_name   = azurerm_resource_group.example.name
      network_interface_ids = [azurerm_network_interface.example[count.index].id]
      size                  = var.virtual_machine_size
    
      os_disk {
        name                 = "${var.disk_name}-${count.index}"
        caching              = "ReadWrite"
        storage_account_type = var.redundancy_type
      }
    
      source_image_reference {
        publisher = "Canonical"
        offer     = "0001-com-ubuntu-server-jammy"
        sku       = "22_04-lts-gen2"
        version   = "latest"
      }
    
      admin_username                  = var.username
      admin_password                  = coalesce(var.password, random_password.example.result)
      disable_password_authentication = false
    
    }
    
    # Enable virtual machine extension and install Nginx
    # The script will update the package list, install Nginx,
    # and create a simple HTML page
    resource "azurerm_virtual_machine_extension" "example" {
      count                = 2
      name                 = "Nginx"
      virtual_machine_id   = azurerm_linux_virtual_machine.example[count.index].id
      publisher            = "Microsoft.Azure.Extensions"
      type                 = "CustomScript"
      type_handler_version = "2.0"
    
      settings = <<SETTINGS
    {
     "commandToExecute": "sudo apt-get update && sudo apt-get install nginx -y && echo \"Hello World from $(hostname)\" > /var/www/html/index.html && sudo systemctl restart nginx"
    }
    SETTINGS
    
    }
    
    # Create an Internal Load Balancer to distribute traffic to the
    # Virtual Machines in the Backend Pool
    resource "azurerm_lb" "example" {
      name                = var.load_balancer_name
      location            = azurerm_resource_group.example.location
      resource_group_name = azurerm_resource_group.example.name
      sku                 = "Standard"
    
      frontend_ip_configuration {
        name                          = "frontend-ip"
        subnet_id                     = azurerm_subnet.example.id
        private_ip_address_allocation = "Dynamic"
      }
    }
    
    # Create a Backend Address Pool for the Load Balancer
    resource "azurerm_lb_backend_address_pool" "example" {
      loadbalancer_id = azurerm_lb.example.id
      name            = "test-pool"
    }
    
    # Create a Load Balancer Probe to check the health of the 
    # Virtual Machines in the Backend Pool
    resource "azurerm_lb_probe" "example" {
      loadbalancer_id = azurerm_lb.example.id
      name            = "test-probe"
      port            = 80
    }
    
    # Create a Load Balancer Rule to define how traffic will be
    # distributed to the Virtual Machines in the Backend Pool
    resource "azurerm_lb_rule" "example" {
      loadbalancer_id                = azurerm_lb.example.id
      name                           = "test-rule"
      protocol                       = "Tcp"
      frontend_port                  = 80
      backend_port                   = 80
      disable_outbound_snat          = true
      frontend_ip_configuration_name = "frontend-ip"
      probe_id                       = azurerm_lb_probe.example.id
      backend_address_pool_ids       = [azurerm_lb_backend_address_pool.example.id]
    }
    
  4. variables.tf という名前のファイルを作成し、次のコードを挿入します。

    variable "resource_group_location" {
      type        = string
      default     = "eastus"
      description = "Location of the resource group."
    }
    
    variable "resource_group_name_prefix" {
      type        = string
      default     = "rg"
      description = "Prefix of the resource group name that's combined with a random ID so name is unique in your Azure subscription."
    }
    
    variable "username" {
      type        = string
      default     = "azureadmin"
      description = "The username for the local account that will be created on the new VM."
    }
    
    variable "password" {
      type        = string
      default     = ""
      description = "The password for the local account that will be created on the new VM. If left blank, a random password is generated."
    }
    
    variable "virtual_network_name" {
      type        = string
      default     = "test-vnet"
      description = "Name of the Virtual Network."
    }
    
    variable "subnet_name" {
      type        = string
      default     = "test-subnet"
      description = "Name of the subnet."
    }
    
    variable "network_security_group_name" {
      type        = string
      default     = "test-nsg"
      description = "Name of the Network Security Group."
    }
    
    variable "network_interface_name" {
      type        = string
      default     = "test-nic"
      description = "Name of the Network Interface."
    }
    
    variable "public_ip_name" {
      type        = string
      default     = "test-pip"
      description = "Name of the Public IP."
    }
    
    variable "nat_gateway" {
      type        = string
      default     = "test-nat"
      description = "Name of the NAT gateway."
    }
    
    variable "bastion_name" {
      type        = string
      default     = "test-bastion"
      description = "Name of the Bastion."
    }
    
    variable "virtual_machine_name" {
      type        = string
      default     = "test-vm"
      description = "Name of the Virtual Machine."
    }
    
    variable "virtual_machine_size" {
      type        = string
      default     = "Standard_B2s"
      description = "Size or SKU of the Virtual Machine."
    }
    
    variable "disk_name" {
      type        = string
      default     = "test-disk"
      description = "Name of the OS disk of the Virtual Machine."
    }
    
    variable "redundancy_type" {
      type        = string
      default     = "Standard_LRS"
      description = "Storage redundancy type of the OS disk."
    }
    
    variable "load_balancer_name" {
      type        = string
      default     = "test-lb"
      description = "Name of the Load Balancer."
    }
    
  5. outputs.tf という名前のファイルを作成し、次のコードを挿入します。

    output "resource_group_name" {
      value = azurerm_resource_group.example.name
    }
    
    output "private_ip_address" {
      value = "http://${azurerm_lb.example.private_ip_address}"
    }
    
    output "vm_password" {
      value     = azurerm_linux_virtual_machine.example[0].admin_password
      sensitive = true
    }
    

重要

4.x azurerm プロバイダーを使用している場合は、Terraform コマンドを実行する前に、Azure に対して認証する Azure サブスクリプション ID を明示的に指定 する必要があります。

azure サブスクリプション ID を providers ブロックに入れずに指定する 1 つの方法は、 ARM_SUBSCRIPTION_IDという名前の環境変数にサブスクリプション ID を指定することです。

詳細については、 Azure プロバイダーのリファレンス ドキュメントを参照してください

Terraform を初期化する

terraform init を実行して、Terraform のデプロイを初期化します。 このコマンドは、Azureリソースを管理するために必要なAzureプロバイダーをダウンロードします。

terraform init -upgrade

重要なポイント:

  • -upgradeパラメーターは、設定のバージョン制約に準拠する最新のバージョンに必要なプロバイダープラグインをアップグレードします。

Terraform実行計画を作成する

実行計画を作成するために terraform plan を実行してください。

terraform plan -out main.tfplan

重要なポイント:

  • terraform plan コマンドは実行プランを作成しますが、実行はしません。 代わりに、それは設定ファイルで指定された設定を作成するために必要な手順を決定します。 このパターンを使用すると、実際のリソースに変更を加える前に、実行プランが自分の想定と一致しているかどうかを確認できます。
  • 任意の-outパラメーターを使用すると、プランの出力ファイルを指定することができます。 -out パラメーターを使用すると、レビューしたプランがそのまま適用されることが保証されます。

テラフォームの実行計画を適用する

クラウドインフラストラクチャに対して実行計画を適用するには、terraform apply を実行してください。

terraform apply main.tfplan

重要なポイント:

  • terraform apply コマンドの例は、以前に terraform plan -out main.tfplan が実行されたことを前提としています。
  • -out パラメーターに別のファイル名を指定した場合は、terraform apply への呼び出しで同じファイル名を使用してください。
  • -out パラメーターを使用しなかった場合、任意のパラメーターを指定せずに terraform apply を呼び出してください。

結果を確認してください。

  1. Azure リソース グループ名を表示します。

    terraform output -raw resource_group_name
    
  2. 必要に応じて、VM (仮想マシン) のパスワードを表示します。

    terraform output -raw vm_password
    
  3. フロントエンドプライベート IP アドレスを表示します。

    terraform output -raw private_ip_address
    
  4. Bastion を使用して、ロード バランサーのバックエンド プールに関連付けられていない VM にログインします。

  5. ロードバランサーのフロントエンド プライベート IP アドレスを使用して、Nginx ウェブサーバーのカスタム ウェブページにアクセスするために、curl コマンドを実行します。

    curl http://<Frontend IP address>
    

リソースを整理する

Terraform を使用して作成されたリソースが不要になった場合、次の手順を実施してください。

  1. terraform plan を実行し、destroy フラグを指定してください。

    terraform plan -destroy -out main.destroy.tfplan
    

    重要なポイント:

    • terraform plan コマンドは実行プランを作成しますが、実行はしません。 代わりに、それは設定ファイルで指定された設定を作成するために必要な手順を決定します。 このパターンを使用すると、実際のリソースに変更を加える前に、実行プランが自分の想定と一致しているかどうかを確認できます。
    • 任意の-outパラメーターを使用すると、プランの出力ファイルを指定することができます。 -out パラメーターを使用すると、レビューしたプランがそのまま適用されることが保証されます。
  2. terraform applyを実行して、実行プランを適用します。

    terraform apply main.destroy.tfplan
    

AzureでのTerraformのトラブルシューティング

Azure で Terraform を使用する際の一般的な問題をトラブルシュートする

次のステップ