Terraformを用いたAzureリソースのデプロイ

はじめに

Terraformの概要、Terraformを用いたAzureリソースのデプロイ方法について基本的な流れを解説致します。

Terraformとは

Terraformとは、HashiCorp社が提供するIaC(Infrastructure as Code)*1のためのサービスです。

Terraformでは様々なインフラストラクチャ用のプロバイダーが用意されており、Azureでも使用できます。 registry.terraform.io

認証

TerraformでAzureリソースをデプロイする際に、Azureへ認証を行う必要があります。
Azureでは以下の認証方法があります。

  • Azure CLIを使用したAzureへの認証
  • マネージドIDを使用したAzureへの認証
  • サービスプリンシパルを使用したAzureへの認証
  • OpenID Connectを使用したAzureへの認証

今回はサービスプリンシパルを使用したAzureへの認証の認証にて実施致します。

registry.terraform.io

リソースのデプロイ

今回は例として以下リソースのデプロイを実施します。

  • Resource Group
  • Virtual Network
  • Network Security Group
  • Virtual Machine

前提

Terraformをインストール済であること

インストールを未実施の場合は以下を参照し、インストール後に後続手順を実施してください。 developer.hashicorp.com

サービスプリンシパルを作成済であること

未作成の場合は以下コマンドにて作成します。

#Sign In
az login --tenant <Tenant ID>

#Tenant、Subscription情報の取得
az account show --query "{subscriptionId:id, tenantId:tenantId}"

#変数に値を格納
$SUBSCRIPTION_ID="<Subscription ID>"

#Subscriptioinのセット
az account set --subscription $SUBSCRIPTION_ID

#Service Principalの作成
az ad sp create-for-rbac --role Contributor --scopes /subscriptions/$SUBSCRIPTION_ID --name "<Service Principal名>"

※Terraform構成ファイル作成時に使用するため出力の結果を控えてください。

状態格納用のストレージアカウントを作成済であること

既定だとローカルにTerraformの状態が格納されますが、ストレージアカウントへの格納が推奨となります。 以下コマンドより作成可能です。

#Sign In
az login --tenant <Tenant ID>

#Tenant、Subscription情報の取得
az account show --query "{subscriptionId:id, tenantId:tenantId}"

#変数に値を格納
$SUBSCRIPTION_ID="<Subscription ID>"
$REGION="<作成先Region>"
$RG_NAME="<Resource Group名>"
$ST_NAME="<Storage Account名>"
$BLOB_NAME="<Blob Container名>"

#Subscriptionのセット
az account set --subscription $SUBSCRIPTION_ID

#Resource Groupの作成
az group create --name $RG_NAME --location $REGION

#Storage Accountの作成
az storage account create --resource-group $RG_NAME --name $ST_NAME --sku Standard_LRS --encryption-services blob

#Blob Containerの作成
az storage container create --name $BLOB_NAME --account-name $ST_NAME

learn.microsoft.com

定義ファイルの作成

まず、各リソースの定義ファイルを作成します。

main.tfの作成

provider情報、状態格納先ストレージアカウントを記載します。

# Env info
provider "azurerm" {
  features {}
  subscription_id = var.subscription_id
  tenant_id       = var.tenant_id
  client_id       = var.client_id
  client_secret   = var.client_secret
}

# Azure Provider
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "=3.25.0"
    }
  }

  # Store Terraform state in Azure Storage
  backend "azurerm" {
    resource_group_name  = "<Resource Group名(状態格納用ストレージアカウントが格納されているResource Group)>"
    storage_account_name = "<Storage Account名>"
    container_name       = "<Blob Container名>"
    # Statment File Name
    key = "terraform.tfstate"
  }
}
valiables.tfの作成

各リソースの値を記載します。

#-------------------------------
# 基本変数定義
#-------------------------------

# Subscription ID
variable "subscription_id" {
  type = string
}

# Service Principal ID
variable "client_id" {
  type = string
}

# Service Principal Secret
variable "client_secret" {
  type = string
}

# TenantID
variable "tenant_id" {
  type = string
}

# Region
variable "location" {
  default = "<作成先Region>"
}


#-------------------------------
# Resource Group
#-------------------------------

# Resource Group Name
variable "resource_group_name" {
  default = "<Resource Group名>"
}

#----------------------------------
# Virtual Network
#----------------------------------

# Virtual Network Name
variable "virtual_network_name" {
  default = "<VNET名>"
}

# Subnet Name
variable "subnet_name" {
  default = "<Subnet名>"
}

# Vnet Address Space
variable "vnet_address_space" {
  default = ["<VNET IP Prefix>"]
}

# Subnet Address Space
variable "snet_address_space" {
  default = ["<Subnet IP Prefix>"]
}

#----------------------------------
# Network Security Group
#----------------------------------
# Network Security Group Name
variable "network_security_group_name" {
  default = "<NSG名>"
}

#----------------------------------
# Virtual Machine
#----------------------------------

# VM Name
variable "vm_name" {
  default = "<VM名>"
}

# VM Size
variable "vm_size" {
  default = "<VM Size>"
}

# Public IP Name
variable "public_ip_name" {
  default = "<Public IP名>"
}

# NIC Name
variable "nic_name" {
  default = "<NIC名>"
}

# OS DIsk Name
variable "os_disk_name" {
  default = "<OS Disk名>"
}

# OS Disk SKU
variable "os_disk_sku" {
  default = "<OS Disk SKU>"
}

# IP Config Name
variable "ip_config_name" {
  default = "<IP Config名>"
}

# Admin PW
variable "admin_pw" {
  type = string
}

# Admin User Name
variable "admin_user_name" {
  default = "<管理者User名>"
}
rg.tfの作成

リソースグループ設定を記載します。

#-------------------------------
# Resource Group
#-------------------------------

# Resource Group
resource "azurerm_resource_group" "rg" {
  name     = var.resource_group_name
  location = var.location
}
vnet.tfの作成

仮想ネットワーク設定を記載します。

#-------------------------------
# Virtual Network
#-------------------------------

# Virtual Network
resource "azurerm_virtual_network" "vnet" {
  name                = var.virtual_network_name
  address_space       = var.vnet_address_space
  location            = var.location
  resource_group_name = var.resource_group_name
  depends_on = [
    azurerm_resource_group.rg
  ]
}

# Subnet
resource "azurerm_subnet" "snet" {
  name                 = var.subnet_name
  resource_group_name  = var.resource_group_name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = var.snet_address_space
  depends_on = [
    azurerm_resource_group.rg,
    azurerm_virtual_network.vnet,
    azurerm_network_security_group.nsg
  ]
}
nsg.tfの作成

Network Security Group設定を記載します。

#-------------------------------
# Network Security Gtoup
#-------------------------------

# Network Security Group
resource "azurerm_network_security_group" "nsg" {
  name                = var.network_security_group_name
  location            = var.location
  resource_group_name = var.resource_group_name

  #-------------------------------
  # 受信規則
  #-------------------------------
  # RDP接続許可
  security_rule {
    name                       = "AllowRDPInBound"
    priority                   = 1000
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "3389"
    source_address_prefix      = "<接続元IP Address>"
    destination_address_prefix = "*"
  }
  #Resource Group作成後にデプロイ
  depends_on = [
    azurerm_resource_group.rg
  ]
}

# Subnetへの関連付け
resource "azurerm_subnet_network_security_group_association" "nsgSubnet" {
  subnet_id                 = azurerm_subnet.snet.id
  network_security_group_id = azurerm_network_security_group.nsg.id
  depends_on = [
    azurerm_resource_group.rg,
    azurerm_virtual_network.vnet,
    azurerm_subnet.snet
  ]
}
vm.tfの作成

仮想マシン設定を記載します。

#-------------------------------
# Virtual Machine
#-------------------------------

# Public IP
resource "azurerm_public_ip" "public_ip" {
  name                = var.public_ip_name
  location            = var.location
  resource_group_name = var.resource_group_name
  allocation_method   = "Static"

  depends_on = [
    azurerm_resource_group.rg,
  ]
}

# Network interface
resource "azurerm_network_interface" "nic" {
  name                = var.nic_name
  location            = var.location
  resource_group_name = var.resource_group_name

  ip_configuration {
    name                          = var.ip_config_name
    subnet_id                     = azurerm_subnet.snet.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.public_ip.id
  }

  depends_on = [
    azurerm_resource_group.rg,
    azurerm_virtual_network.vnet,
    azurerm_subnet.snet,
    azurerm_public_ip.public_ip
  ]
}

# Virtual Machine
resource "azurerm_windows_virtual_machine" "windows_vm" {
  name                  = var.vm_name
  admin_username        = var.admin_user_name
  admin_password        = var.admin_pw
  location              = var.location
  resource_group_name   = var.resource_group_name
  network_interface_ids = [azurerm_network_interface.nic.id]
  size                  = var.vm_size

  os_disk {
    name                 = var.os_disk_name
    caching              = "ReadWrite"
    storage_account_type = var.os_disk_sku
  }

  source_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2022-datacenter-azure-edition"
    version   = "latest"
  }
  depends_on = [
    azurerm_resource_group.rg,
    azurerm_virtual_network.vnet,
    azurerm_subnet.snet,
    azurerm_public_ip.public_ip,
    azurerm_network_interface.nic
  ]
}

Terraformコマンドの実行

定義ファイルの作成が完了しましたら、Terraformコマンドを実行していきます。

terraform init

初期化をし、provider pluginsを取得します。
成功すると「Terraform has been successfully initialized!」と表示されます。

terraform init実行画面

terraform fmt

カレントディレクトリのtfファイルをフォーマットします。(必要に応じて実施)
修正されたファイルがあればファイル名が出力されます。
※サブディレクトリも含むフォーマットする場合は「terraform fmt -recursive」を実行してください。

terraform fmt実行画面

terraform validate

構成の検証をします。
問題がなければ「Success! The configuration is valid.」と表示されます。

terraform validate実行画面

terraform plan

tfファイルにて定義された構築リソースを表示します。
※コマンド実行後に環境情報やシークレット情報の入力が必要です。

terraform plan実行画面(1)

構築内容や、作成・削除・変更されるリソース数が表示されます。

terraform plan実行画面(2)

terraform apply

リソースをデプロイします。
※実行後に環境情報やシークレット情報の入力が必要です。

terraform apply実行画面(1)

内容に問題がないことを確認し、「yes」を入力後「Enter」を押下します。

terraform apply実行画面(2)

問題なくデプロイを実行できると「Apply complete! Resources: * added, * changed, * destroyed.」と表示されます。

terraform apply実行画面(3)

Azure Portalを確認すると、リソースが問題なく構築されていることが確認できます。

Azure Portal画面

作成リソースの削除

Terraformコマンドの実行

デプロイ時同様、Terraformで管理されたリソースはTerraformコマンドで削除可能です。

terraform destroy

Terraformで構築したリソースの削除を実行します。

※「terraform plan -destroy」を実行することで、削除されるリソースを事前に確認することができます。
※ 実行後に環境情報やシークレット情報の入力が必要です。

terraform destroy実行画面(1)

内容に問題がないことを確認し、「yes」を入力後「Enter」を押下します。

terraform destroy実行画面(2)

問題なく削除が完了すると「Destroy complete! Resources: * destroyed.」と表示されます。

terraform destroy実行画面(3)

おわりに

本記事を最後までお読みいただき、ありがとうございます。
Terraformによるリソース管理を行うことで、効率的かつ正確なインフラストラクチャの構築、変更、削除ができるようになるかと思います。
本記事がTerraformを使用する際の参考となれば幸いです。

*1:IaC:サーバーやネットワークをはじめとしたインフラ構成をコード化し、構築や管理を自動化する手法のこと

執筆担当者プロフィール
西山 正太郎

西山 正太郎(日本ビジネスシステムズ株式会社)

クラウドソリューション事業本部に所属。近年は業務で主にMicrosoft Azureに携わっています。山登りが趣味です。

担当記事一覧