このクイックスタートでは、Terraformを使用して標準的な内部ロードバランサーと2台の仮想マシンをデプロイする方法を紹介します。 追加のリソースには、Azure Bastion、NAT Gateway、仮想ネットワーク、および必要なサブネットが含まれます。
Terraformはクラウドインフラストラクチャの定義、プレビュー、そしてデプロイメントを可能にします。 Terraform を使用する際は、HCL 構文を使って構成ファイルを作成します。 HCL 構文では、Azure などのクラウド プロバイダーと、クラウド インフラストラクチャを構成する要素を指定できます。 あなたの設定ファイルを作成した後、実行計画を作成します。これにより、インフラストラクチャの変更をデプロイする前にプレビューすることができます。 変更を確認したら、実行プランを適用してインフラストラクチャをデプロイします。
- azurerm_resource_group を使って Azure リソース グループを作成する
- azurerm_virtual_networkを使用して Azure Virtual Network を作成する
- Azure サブネットを作成するには、azurerm_subnet を使用します。
- AzureのパブリックIPをazurerm_public_ipを使用して作成します
- azurerm_lbを使用して Azure Load Balancer を作成する。
- azurerm_network_interface を使用して、Azure ネットワーク インターフェイスを作成する
- azurerm_network_interface_backend_address_pool_association を使用して、Azure ネットワークインターフェイスのロードバランサーのバックエンドアドレスプールの関連付けを作成する。
- azurerm_linux_virtual_machine を使用して Azure Linux 仮想マシンを作成する
- azurerm_virtual_machine_extension を使用して、Azure Virtual Machine Extension を作成する
- Azure NAT Gatewayを作成するには、azurerm_nat_gatewayを使用します。
- azurerm_bastion_host を使用して Azure Bastion を作成する
[前提条件]
アクティブなサブスクリプションがある Azure アカウントを作成します。 無料でアカウントを作成できます。
Terraformコードを実装する
この記事のサンプル コードは、Azure Terraform GitHub リポジトリにあります。 Terraform の現在および以前のバージョンからのテスト結果を含むログ ファイルを表示できます。 Terraform を使用して Azure リソースを管理する方法を示す 記事とサンプル コード
サンプル Terraform コードをテストして実行するディレクトリを作成し、それを現在のディレクトリにします。
providers.tf
という名前のファイルを作成し、次のコードを挿入します。terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = "~>4.0" } random = { source = "hashicorp/random" version = "~>3.0" } } } provider "azurerm" { features {} }
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] }
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." }
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
を呼び出してください。
結果を確認してください。
Azure リソース グループ名を表示します。
terraform output -raw resource_group_name
必要に応じて、VM (仮想マシン) のパスワードを表示します。
terraform output -raw vm_password
フロントエンドプライベート IP アドレスを表示します。
terraform output -raw private_ip_address
Bastion を使用して、ロード バランサーのバックエンド プールに関連付けられていない VM にログインします。
ロードバランサーのフロントエンド プライベート IP アドレスを使用して、Nginx ウェブサーバーのカスタム ウェブページにアクセスするために、curl コマンドを実行します。
curl http://<Frontend IP address>
リソースを整理する
Terraform を使用して作成されたリソースが不要になった場合、次の手順を実施してください。
terraform plan を実行し、
destroy
フラグを指定してください。terraform plan -destroy -out main.destroy.tfplan
重要なポイント:
-
terraform plan
コマンドは実行プランを作成しますが、実行はしません。 代わりに、それは設定ファイルで指定された設定を作成するために必要な手順を決定します。 このパターンを使用すると、実際のリソースに変更を加える前に、実行プランが自分の想定と一致しているかどうかを確認できます。 - 任意の
-out
パラメーターを使用すると、プランの出力ファイルを指定することができます。-out
パラメーターを使用すると、レビューしたプランがそのまま適用されることが保証されます。
-
terraform applyを実行して、実行プランを適用します。
terraform apply main.destroy.tfplan
AzureでのTerraformのトラブルシューティング
Azure で Terraform を使用する際の一般的な問題をトラブルシュートする