Terraformでmovedブロックを利用してローカル名を変更する

Terraformでは、movedブロックを利用することで、リソースの再作成を行わずにローカル名を変更できます。 developer.hashicorp.com

今回は本機能を試してみようと思います。

movedブロックとは

moved ブロックは、既存リソースの参照を安全に移動するための仕組みです。

これにより「ローカル名を変えたいだけなのに、リソースが削除・再作成されてしまう」という問題を避けることができます。

事前準備

リソース作成用のTerraform定義ファイルを作成する

Terraform定義ファイルを作成します。

今回は既存リソースグループに仮想ネットワークを作成します。

以下、仮想ネットワークを作成するためのTerraform定義ファイルを示します。

main.tfの作成

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

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

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

  # 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"
  }
}
rg.tfの作成

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

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

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

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

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

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

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

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

# Subscription ID
variable "subscription_id" {}
# TenantID
variable "tenant_id" {}

#-------------------------------
# Resource Group
#-------------------------------
# Resource Group Name
variable "resource_group_name" {
  default = "nishiyamas-tf-rg"
}

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

# Virtual Network Name
variable "virtual_network_name" {
  default = "nishiyamas-tf-moved-vnet"
}

# Subnet Name
variable "subnet_name" {
  default = "tf-moved-snet"
}

# Vnet Address Space
variable "vnet_address_space" {
  default = ["10.120.0.0/16"]
}

# Subnet Address Space
variable "snet_address_space" {
  default = ["10.120.0.0/24"]
}
terraform.tfvarsの作成

環境情報等を記載

※環境情報等を別ファイル管理をする場合に作成

# Tenand ID
tenant_id = "<Tenant ID>"

# SubScription ID
subscription_id = "<Subscription ID>"

リソースを作成する

定義ファイルの準備が出来たらリソースを作成します。

実行コマンドについては以下URLの「Terraformコマンドの実行」をご参照ください。

blog.jbs.co.jp

リソース作成後にtfstateファイルを確認すると、サブネットのローカル名は「snet-before」になっていることがわかります。

【terraform.tfstate ※一部抜粋】

    {
      "mode": "managed",
      "type": "azurerm_subnet",
      "name": "snet-before",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [

ローカル名を変更する

movedブロックを使わない場合

movedブロックを利用せず、以下のようにローカル名を変更します。

今回はサブネットのローカル名を「snet-before」から「snet-after」に変更します。

【vnet.tf】

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

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

# Subnet
resource "azurerm_subnet" "snet-after" { # 更新
  name                 = var.subnet_name
  resource_group_name  = data.azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = var.snet_address_space
  depends_on = [
    data.azurerm_resource_group.rg,
    azurerm_virtual_network.vnet
  ]
}

この状態でterraform planを実行すると、以下のような差分が発生します。

terraform plan実行結果

上記の場合、既存リソースが一度削除され、新規作成されてしまいます。

movedブロックを使った場合

以下のように moved ブロックを追加します。

【vnet.tf】

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

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

# Subnet
resource "azurerm_subnet" "snet-after" { # 更新
  name                 = var.subnet_name
  resource_group_name  = data.azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = var.snet_address_space
  depends_on = [
    data.azurerm_resource_group.rg,
    azurerm_virtual_network.vnet
  ]
}

# movedブロックを追加
moved { 
  from = azurerm_subnet.snet-before
  to   = azurerm_subnet.snet-after
}

この状態でterraform planを実行すると、以下のようになります。

terraform plan実行結果

上記の場合、既存リソースの削除や新規作成はされず、stateの参照を移行することができます。

terraform apply後にtfstateファイルを確認すると、以下のようにローカル名が「snet-after」変更されていることがわかります。

【terraform.tfstate ※一部抜粋】

    {
      "mode": "managed",
      "type": "azurerm_subnet",
      "name": "snet-after",
      "provider": "provider[\"registry.terraform.io/hashicorp/azurerm\"]",
      "instances": [

おわりに

Terraformのローカル名を単純に書き換えると、Terraform は別リソースと認識し、リソースの再作成が起こってしまいます。

movedブロックを利用すれば、既存リソースを保持したまま安全にローカル名を変更可能です。

本記事が、Terraformを使用する際の参考となれば幸いです。

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

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

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

担当記事一覧