そう感じているLinuxエンジニアは多い。AzureのVNetとLinux VMをTerraformでコード化すれば、同じ構成を何度でも一発で再現でき、インフラの変更履歴もGitのpull requestとして残せる。
この記事では、TerraformのazurermプロバイダーでAzureのVNet・サブネット・NSG・Linux VMをコード化する実践手順を解説します。versions.tf / variables.tf / main.tf の設計から、terraform plan/apply/destroyの実行と実際のコマンド出力まで一気通貫で進めます。動作確認環境はUbuntu 24.04 LTS(Terraform 1.9.x、Azure CLI 2.65.x)です。
この記事のポイント
・AzureのVNetとLinux VMはazurermプロバイダーで完全コード化できる
・terraform planで変更内容を事前確認してからapplyするのが鉄則
・terraform destroyで検証後のリソースを一括削除でき、コスト管理がしやすい
・本番ではtfstateをAzure Blob Storageのリモートバックエンドで管理する
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜAzureのインフラをTerraformで管理するのか
azコマンドでも同じリソースを作成できる。それでもTerraformを使う理由は何か。主な違いは「冪等性(べきとうせい)」にある。・azコマンドは命令的(Imperative): 「今すぐVMを1台作れ」という命令を実行する。同じコマンドを2回実行すれば2台立ち上がる(またはエラーになる)
・Terraformは宣言的(Declarative): 「この構成が存在すべき」と宣言する。既に存在すれば何もせず、差分だけを適用する
・Gitでの変更管理: .tfファイルをリポジトリで管理することで、誰がいつ何を変えたかがpull requestに残る
・本番と検証の再現性: 変数(variables.tf)でVMサイズや環境名だけ切り替えれば、同じ.tfを本番と検証で使い回せる
azコマンドは「今すぐ1回だけ作る」ときに手早い。Terraformは「何度でも同じ構成を再現したい」「チームで管理したい」ときに力を発揮する。
Terraformのインストールと認証設定
1. Terraformをインストールする
Ubuntu 24.04 LTSの場合は、HashiCorpの公式APTリポジトリからインストールする。# HashiCorpの署名キーを追加 sudo apt update && sudo apt install -y gnupg software-properties-common wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | \ sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null # APTリポジトリを登録 echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \ https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \ sudo tee /etc/apt/sources.list.d/hashicorp.list # Terraformをインストール sudo apt update && sudo apt install -y terraform
sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo sudo yum install -y terraform
$ terraform -version Terraform v1.9.5 on linux_amd64
2. Azure CLIでログインする
TerraformがazurermプロバイダーでAzureへ接続する認証方法は主に2つある。・az login(ブラウザ認証): 開発・検証環境向け。最もシンプル
・サービスプリンシパル(環境変数): CI/CDやcron環境向け
この記事では az login を使った方法で進める。Azure CLIがインストール済みであれば以下を実行する:
$ az login
[ { "cloudName": "AzurePublicCloud", "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "isDefault": true, "name": "MySubscription", "state": "Enabled", "tenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "user": { "name": "user@example.com", "type": "user" } } ]
$ az account show --query id -o tsv xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
プロジェクトディレクトリとファイル構成の設計
作業ディレクトリを作成して、以下の構成でファイルを用意する:$ mkdir azure-terraform-lab && cd azure-terraform-lab
azure-terraform-lab/ ├── versions.tf # プロバイダー・バージョン設定 ├── variables.tf # 変数定義 ├── main.tf # リソース定義(VNet・NSG・VM) ├── outputs.tf # 出力値(IPアドレス等) └── terraform.tfvars # 変数の実際の値(Gitには含めない)
1. versions.tf — プロバイダーとバージョンを固定する
terraform { required_version = ">= 1.9.0" required_providers { azurerm = { source = "hashicorp/azurerm" version = "~> 4.0" } } } provider "azurerm" { features {} subscription_id = var.subscription_id }
required_providers でバージョンを固定(~> 4.0 は 4.x 系の最新を使う指定)することで、プロバイダーの予期しないバージョンアップによる挙動変化を防ぐ。2. variables.tf — 変数を定義する
variable "subscription_id" { description = "Azure サブスクリプションID" type = string } variable "location" { description = "Azureリージョン" type = string default = "japaneast" } variable "resource_group_name" { description = "リソースグループ名" type = string default = "rg-terraform-lab" } variable "vm_size" { description = "VMサイズ" type = string default = "Standard_B1ms" } variable "admin_username" { description = "VM管理者ユーザー名" type = string default = "azureuser" } variable "ssh_public_key" { description = "SSH公開鍵の内容(~/.ssh/id_rsa.pub)" type = string }
3. terraform.tfvars — 変数の実際の値(Git管理外)
subscription_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ssh_public_key = "ssh-rsa AAAAB3Nz..."
.gitignore に追加してリポジトリに含めないこと。# .gitignore terraform.tfvars .terraform/ *.tfstate *.tfstate.backup
VNetとサブネット・NSGをTerraformで定義する
main.tf にリソースを記述していく。まずネットワーク関連のリソース(リソースグループ・VNet・サブネット・NSG)から定義する。1. リソースグループとVNet
# ---- リソースグループ ---- resource "azurerm_resource_group" "main" { name = var.resource_group_name location = var.location } # ---- 仮想ネットワーク(VNet)---- resource "azurerm_virtual_network" "main" { name = "vnet-terraform-lab" address_space = ["10.0.0.0/16"] location = azurerm_resource_group.main.location resource_group_name = azurerm_resource_group.main.name } # ---- サブネット ---- resource "azurerm_subnet" "main" { name = "subnet-main" resource_group_name = azurerm_resource_group.main.name virtual_network_name = azurerm_virtual_network.main.name address_prefixes = ["10.0.1.0/24"] }
address_space はVNet全体のCIDRブロック(/16)、address_prefixes はサブネットの範囲(/24)を指定する。2. NSG(SSH許可ルール)とパブリックIP
# ---- ネットワークセキュリティグループ ---- resource "azurerm_network_security_group" "main" { name = "nsg-terraform-lab" location = azurerm_resource_group.main.location resource_group_name = azurerm_resource_group.main.name security_rule { name = "AllowSSH" priority = 1001 direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = "22" source_address_prefix = "*" destination_address_prefix = "*" } } # NSGをサブネットに関連付け resource "azurerm_subnet_network_security_group_association" "main" { subnet_id = azurerm_subnet.main.id network_security_group_id = azurerm_network_security_group.main.id } # ---- パブリックIP ---- resource "azurerm_public_ip" "main" { name = "pip-terraform-lab" location = azurerm_resource_group.main.location resource_group_name = azurerm_resource_group.main.name allocation_method = "Static" sku = "Standard" }
source_address_prefix を特定のIPレンジに絞ること。Linux VMをTerraformで定義する
1. NIC(ネットワークインターフェース)
resource "azurerm_network_interface" "main" { name = "nic-terraform-lab" location = azurerm_resource_group.main.location resource_group_name = azurerm_resource_group.main.name ip_configuration { name = "ipconfig1" subnet_id = azurerm_subnet.main.id private_ip_address_allocation = "Dynamic" public_ip_address_id = azurerm_public_ip.main.id } }
2. Linux VM本体
resource "azurerm_linux_virtual_machine" "main" { name = "vm-terraform-lab" resource_group_name = azurerm_resource_group.main.name location = azurerm_resource_group.main.location size = var.vm_size admin_username = var.admin_username network_interface_ids = [ azurerm_network_interface.main.id, ] # パスワード認証を無効にしてSSH公開鍵認証のみ許可 disable_password_authentication = true admin_ssh_key { username = var.admin_username public_key = var.ssh_public_key } os_disk { caching = "ReadWrite" storage_account_type = "Standard_LRS" } source_image_reference { publisher = "Canonical" offer = "ubuntu-24_04-lts" sku = "server" version = "latest" } }
source_image_reference の offer 値(ubuntu-24_04-lts)はハイフンとアンダースコアが混在するため注意。az vm image list で正しい値を確認できる。3. outputs.tf — VMのIPアドレスを出力する
output "public_ip_address" { description = "VMのパブリックIPアドレス" value = azurerm_public_ip.main.ip_address } output "ssh_command" { description = "SSH接続コマンド" value = "ssh -i ~/.ssh/id_rsa ${var.admin_username}@${azurerm_public_ip.main.ip_address}" }
terraform init / plan / applyの実行
1. terraform init — プロバイダーをダウンロードする
$ terraform init Initializing the backend... Initializing provider plugins... - Finding hashicorp/azurerm versions matching "~> 4.0"... - Installing hashicorp/azurerm v4.14.0... - Installed hashicorp/azurerm v4.14.0 (signed by HashiCorp) Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure.
.terraform/ ディレクトリにプロバイダーのバイナリがダウンロードされる。2. terraform plan — 変更内容を事前確認する
apply 前に必ず plan を実行して「何が作られるか」を確認する。これがTerraformを使う上での鉄則だ。$ terraform plan Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # azurerm_resource_group.main will be created + resource "azurerm_resource_group" "main" { + location = "japaneast" + name = "rg-terraform-lab" } # azurerm_virtual_network.main will be created + resource "azurerm_virtual_network" "main" { + address_space = [ + "10.0.0.0/16", ] + location = "japaneast" + name = "vnet-terraform-lab" } # azurerm_linux_virtual_machine.main will be created + resource "azurerm_linux_virtual_machine" "main" { + admin_username = "azureuser" + location = "japaneast" + name = "vm-terraform-lab" + size = "Standard_B1ms" ... } ... Plan: 7 to add, 0 to change, 0 to destroy.
3. terraform apply — リソースを作成する
$ terraform apply Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes azurerm_resource_group.main: Creating... azurerm_resource_group.main: Creation complete after 2s [id=/subscriptions/.../rg-terraform-lab] azurerm_virtual_network.main: Creating... azurerm_virtual_network.main: Creation complete after 4s azurerm_subnet.main: Creating... azurerm_subnet.main: Creation complete after 3s azurerm_network_security_group.main: Creating... azurerm_network_security_group.main: Creation complete after 3s azurerm_public_ip.main: Creating... azurerm_public_ip.main: Creation complete after 2s azurerm_subnet_network_security_group_association.main: Creating... azurerm_subnet_network_security_group_association.main: Creation complete after 2s azurerm_network_interface.main: Creating... azurerm_network_interface.main: Creation complete after 2s azurerm_linux_virtual_machine.main: Creating... azurerm_linux_virtual_machine.main: Still creating... [1m0s elapsed] azurerm_linux_virtual_machine.main: Creation complete after 1m28s Apply complete! Resources: 7 added, 0 changed, 0 destroyed. Outputs: public_ip_address = "52.185.123.45" ssh_command = "ssh -i ~/.ssh/id_rsa azureuser@52.185.123.45"
4. SSH接続で動作確認する
outputs に表示された ssh_command をそのまま実行する:$ ssh -i ~/.ssh/id_rsa azureuser@52.185.123.45 Welcome to Ubuntu 24.04 LTS (GNU/Linux 6.8.0-1019-azure x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/pro Last login: Sun Aug 24 04:20:10 2026 from 203.0.113.1 azureuser@vm-terraform-lab:~$
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、AzureのVNetやVM構築をコードで再現できる実践スキルを養うには Azure実践ハンズオン講座 をご覧ください。現役エンジニアが教える実務直結カリキュラムで、Terraformを使ったインフラ自動化まで一気に習得できます。
terraform destroyでリソースを一括削除する
検証が終わったら terraform destroy でリソースをまとめて削除できる。Azure Portalで一つずつ消す手間が不要で、削除し忘れによる課金ミスも防げる。$ terraform destroy Do you really want to destroy all resources? Terraform will destroy all your managed infrastructure, as shown above. There is no undo. Only 'yes' will be accepted to confirm. Enter a value: yes azurerm_linux_virtual_machine.main: Destroying... azurerm_linux_virtual_machine.main: Still destroying... [30s elapsed] azurerm_linux_virtual_machine.main: Destruction complete after 58s azurerm_network_interface.main: Destroying... azurerm_subnet_network_security_group_association.main: Destroying... ... azurerm_resource_group.main: Destruction complete after 7s Destroy complete! Resources: 7 destroyed.
$ az group show --name rg-terraform-lab ResourceNotFoundError: (ResourceGroupNotFound) ...
本番向けTips — tfstateをAzure Blob Storageで管理する
ローカルのterraform.tfstate はチームで共有できない。本番ではAzure Blob Storageにステートを保管する(リモートバックエンド)。まずストレージアカウントとコンテナーを作成する:# ステート管理用のリソースグループとストレージアカウントを作成 az group create --name rg-tfstate --location japaneast az storage account create \ --resource-group rg-tfstate \ --name satfstate$(openssl rand -hex 4) \ --sku Standard_LRS \ --allow-blob-public-access false az storage container create \ --name tfstate \ --account-name satfstateXXXX
terraform { required_version = ">= 1.9.0" backend "azurerm" { resource_group_name = "rg-tfstate" storage_account_name = "satfstateXXXX" container_name = "tfstate" key = "terraform-lab.tfstate" } required_providers { azurerm = { source = "hashicorp/azurerm" version = "~> 4.0" } } }
トラブルシュート — よくあるエラーと対処法
「subscription_id が見つからない」エラー
Error: The `subscription_id` was not found in the Azure CLI credentials
subscription_id を設定したか確認する。az account show --query id -o tsv でIDを確認してから設定する。SSH接続できない(タイムアウト)
NSGとサブネットのアソシエーションが正しく apply されているか確認する:$ az network nsg show \ --resource-group rg-terraform-lab \ --name nsg-terraform-lab \ --query "securityRules[].{name:name,priority:priority,access:access,destPort:destinationPortRange}" \ --output table Name Priority Access DestPort -------- ---------- -------- ---------- AllowSSH 1001 Allow 22
AllowSSH の Allow ルールが表示されていれば NSG は正常だ。クライアント側のファイアウォールやセキュリティグループを確認する。「ImageReference が不正」エラー
Error: Code="InvalidParameter" Message="The value of parameter imageReference is invalid"
source_image_reference の値が間違っている。az vm image list で正しい値を確認する:$ az vm image list \ --publisher Canonical \ --offer ubuntu-24_04-lts \ --sku server \ --all \ --query "[0].{publisher:publisher,offer:offer,sku:sku,version:version}" \ --output table Publisher Offer Sku Version ----------- ----------------- ------ ---------- Canonical ubuntu-24_04-lts server 24.04.202408140
ubuntu-24_04-lts: ハイフンとアンダースコアの混在)が間違っていることが多いので注意する。「tfstateロック」エラー
Error: Error acquiring the state lock
terraform force-unlock LOCK_ID で解除する。本記事のまとめ
| やりたいこと | コマンドまたはファイル |
|---|---|
| azurermプロバイダーを設定する | versions.tf に required_providers { azurerm ... } |
| 変数を定義して値を渡す | variables.tf + terraform.tfvars |
| プロバイダーを初期化する | terraform init |
| 変更内容を事前確認する | terraform plan |
| リソースを作成する | terraform apply |
| リソースを一括削除する | terraform destroy |
| リモートバックエンドに切り替える | versions.tf に backend "azurerm" を追加して terraform init |
Azureの学習をもっと体系的に進めたいなら、Azure実践ハンズオン講座をご覧ください。現役エンジニアが教える実務直結カリキュラムで、VM構築からインフラ管理まで一気に習得できます。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:AzureのPoint-to-Site VPNでLinuxクライアントをVNetへ接続する方法|証明書認証とazコマンドによるVPN Gateway構築の実践
- この記事の属するカテゴリ:Azureへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます