★★ 中級

04. Virtual Machines

Azure の VM は VM 本体・NIC・Public IP・OS Disk を別リソースとして組み合わせる構造。AWS の aws_instance 一発作成と比べると、最初は冗長に見えますが「責務分離」と捉えると整理しやすいです。

構成要素

Azure で 1 台の VM を起動するために必要なリソース:

  1. azurerm_public_ip(公開アクセスする場合)
  2. azurerm_network_interface(NIC)
  3. azurerm_linux_virtual_machine または azurerm_windows_virtual_machine
  4. (必要なら)azurerm_managed_disk + azurerm_virtual_machine_data_disk_attachment

Public IP と NIC

resource "azurerm_public_ip" "web" {
  name                = "pip-web-prd"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location
  allocation_method   = "Static"
  sku                 = "Standard"
}

resource "azurerm_network_interface" "web" {
  name                = "nic-web-prd-001"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location

  ip_configuration {
    name                          = "internal"
    subnet_id                     = azurerm_subnet.public.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.web.id
  }
}

resource "azurerm_network_interface_security_group_association" "web" {
  network_interface_id      = azurerm_network_interface.web.id
  network_security_group_id = azurerm_network_security_group.web.id
}

azurerm_linux_virtual_machine

resource "azurerm_linux_virtual_machine" "web" {
  name                  = "vm-web-prd-001"
  resource_group_name   = azurerm_resource_group.main.name
  location              = azurerm_resource_group.main.location
  size                  = "Standard_B2s"
  admin_username        = "azureuser"
  network_interface_ids = [azurerm_network_interface.web.id]

  admin_ssh_key {
    username   = "azureuser"
    public_key = file("~/.ssh/id_rsa.pub")
  }

  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Premium_LRS"
    disk_size_gb         = 30
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "ubuntu-24_04-lts"
    sku       = "server"
    version   = "latest"
  }

  custom_data = base64encode(<<-EOT
    #!/bin/bash
    apt-get update
    apt-get install -y nginx
    systemctl enable --now nginx
  EOT
  )

  identity {
    type = "SystemAssigned"
  }

  tags = local.common_tags
}

SSH キー認証

Azure VM は パスワード認証はデフォルトで無効。SSH キーが必須です。

# 既存の公開鍵を使う
admin_ssh_key {
  username   = "azureuser"
  public_key = file("~/.ssh/id_rsa.pub")
}

# Terraform で鍵ペアを生成(学習用、本番では既存鍵を)
resource "tls_private_key" "ssh" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

# 秘密鍵を Key Vault 等に保存(あるいは output で抜く)
SSH より SSM 風の運用を Azure には Azure BastionJust-in-Time VM access があり、22 番ポート開放なしで管理できます。本番運用ではこちらが推奨。

Managed Identity

AWS の iam_instance_profile 相当。VM 自体が「自分の ID」で他 Azure サービスを叩けます。

resource "azurerm_linux_virtual_machine" "web" {
  # ...
  identity {
    type = "SystemAssigned"   # この VM 専用 ID。VM 削除で同時消滅
  }
}

# その ID に Storage への権限を付与
resource "azurerm_role_assignment" "vm_to_storage" {
  scope                = azurerm_storage_account.data.id
  role_definition_name = "Storage Blob Data Reader"
  principal_id         = azurerm_linux_virtual_machine.web.identity[0].principal_id
}

VM Scale Set

AWS の Auto Scaling Group 相当。複数 VM を 1 リソースで管理。

resource "azurerm_linux_virtual_machine_scale_set" "web" {
  name                = "vmss-web-prd"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location
  sku                 = "Standard_B2s"
  instances           = 3
  admin_username      = "azureuser"

  admin_ssh_key {
    username   = "azureuser"
    public_key = file("~/.ssh/id_rsa.pub")
  }

  source_image_reference {
    publisher = "Canonical"
    offer     = "ubuntu-24_04-lts"
    sku       = "server"
    version   = "latest"
  }

  os_disk {
    storage_account_type = "Standard_LRS"
    caching              = "ReadWrite"
  }

  network_interface {
    name    = "primary"
    primary = true
    ip_configuration {
      name      = "internal"
      primary   = true
      subnet_id = azurerm_subnet.private.id
    }
  }

  upgrade_mode = "Rolling"   # 自動でローリング更新
}
VM じゃない選択肢を先に検討 Web/API は Container AppsApp Service、バッチは Container InstancesFunctions。VM が必要なケースは「OS まで管理したい」「特殊ソフト」に限られます。