Terraformへのimportとremove

Azure

Terraformには「import」(Terraformで管理していないリソースを管理下に置く)と「remove」(Terraformで管理しているリソースを管理外とする)の2つの機能があります。今回はAzureのVnet(Virtual Network)とSubnetを使って、2つの機能を試していきます。

前提

  • Terraformのバージョンはv1.7.2です
  • プロバイダー設定や認証設定は省略します。

import

Terraformで管理していない、手動やCLIなどで作成したリソースをTerraformで管理したくなる場面があると思います。そんな時は、「import」を行うことで管理下に置くことができます。「import」方法は大きく2種類あります。「import コマンド」と「import ブロック」の2つになります。今回はterraform v1.5.0で追加された「import ブロック」を使います。「importコマンド」はステートにインポートするだけなので、そこからは自分でtfファイルのリソースブロックを記述します。一方、「import ブロック」は名前にある通りリソースブロックを生成してくれるため、より便利な機能となっています。

VNETをimport

tfファイルに以下のようにimportブロックを記載します。「id」にはインポート対象のAzureリソースIDを指定します。そしてそれをどのリソースブロックに記載するかを「to」で指定します。

import {
  id = "/subscriptions/subscription_id/resourceGroups/rg-dev/providers/Microsoft.Network/virtualNetworks/vnet-databricks"
  to = azurerm_virtual_network.import
}

この状態で以下のコマンドを実行します。tfファイル名は任意ですが、新規作成されるため名前は既存のファイルと被らないようにします。

terraform plan -generate-config-out="temp.tf"

実行後は以下のようにtemp.tfファイルが作成され、terraformのVNET用のコードが生成されます。(subscription_idは置換しています。)

ただし、生成されたコードは完ぺきではありません。例えば、コード生成と同時にターミナルにplanの結果が表示されます。そこには複数のエラーが発生していました。以下がそのエラーです。1つ目は指定できる値が範囲外であるエラーです。2つ目は、subnet作成時のidは作成後に生成されるので、作成時に指定できないというエラーです。実際にTerrafromのドキュメントを見てもsubnetブロックにidの項目はありません。このようにある程度は自動生成されるため便利ですが、微調整は必要になります。

Error: expected flow_timeout_in_minutes to be in the range (4 - 30), got 0

Error: Value for unconfigurable attribute
Can't configure a value for "subnet.0.id": its value will be decided automatically based on the result of applying this configuration

subnetを外だし

作成されたコードを見ると、subnetはvnetリソースに中に記載されています。個人的にsubnetは別リソースブロックとして記載したいのでimportブロックを以下のように変えて実行してみます。

import {
  id = "/subscriptions/subscription_id/resourceGroups/rg-dev/providers/Microsoft.Network/virtualNetworks/vnet-databricks"
  to = azurerm_virtual_network.import
}

import {
  id = "/subscriptions/subscription_id/resourceGroups/rg-dev/providers/Microsoft.Network/virtualNetworks/vnet-databricks/subnets/default"
  to = azurerm_subnet.import_default
}

import {
  id = "/subscriptions/subscription_id/resourceGroups/rg-dev/providers/Microsoft.Network/virtualNetworks/vnet-databricks/subnets/host"
  to = azurerm_subnet.import_host
}

import {
  id = "/subscriptions/subscription_id/resourceGroups/rg-dev/providers/Microsoft.Network/virtualNetworks/vnet-databricks/subnets/container"
  to = azurerm_subnet.import_container
}

再度コマンドを実行すると、sunetリソースも生成されます。delegationもちゃんと設定されていますね。手書きだとやや面倒なのでありがたいです。ただし、vnetリソースにもsubnetプロパティは変わらず生成されるので、削除は必要です。

また、subnetリソースには自信が属するvnet名を記載します。しかし、vnet名は文字列で記載されます。基本的には「azurerm_virtual_network.import.name」ように参照すると思います。この辺は手動で修正が必要です。生成されたコードを少し手直ししました。

問題なければapplyを行います。「Apply complete! Resources: 4 imported, 0 added, 0 changed, 0 destroyed.」と表示されれば成功です。

ちなみに一度importできたらimportブロックは削除して大丈夫です。その後もう一度planを行い、変更がなければ大丈夫です。

importしたリソースの変更

次に、取り込んだvnetの情報を更新してみましょう。タグの値を「manual」から「terraform」に変えてapplyしてみます。変更検知されています。

実際にapplyした後にAzure Portalからタグを確認すると、タグが変更されていることが確認出来ました。問題なくVNETをTerraform管理下に置くことができているようです。

remove

Terraformで作成したリソースをTerraformの管理下から外したい、でもリソース自体は削除したくない、そんなことよくあると思います。何も考えずリソースブロックを削除してapplyするとTerraform管理下から外されるのと同時に実際のリソースもAzureから削除されてしまいます。そんな時に使えるのが「removed ブロック」です。

removeもimportと同様に以前はコマンドで行っていましたが、v1.7からブロックで記述できるようになりました。

subnetのremove

importしたsubnetの1つ(今回はdefault subnet)をremoveします。以下のようにremoveブロックを作成して、fromに対象のリソースを指定します。またlifecycleでは実際のAzureリソースとして削除されないように「destry = false」を指定します。「azurerm_subnet.import_default」リソースブロック自体は削除しておいてください。

removed {
  from = azurerm_subnet.import_default
  lifecycle {
    destroy = false
  }
}

この状態でapplyを実行すると、「Warning: Some objects will no longer be managed by Terraform」という注意メッセージが表示されます。問題なければそのまま実行します。

では本当に削除されたのか確認してみましょう。Azure Portal上からdefaultサブネットのCIDRを変更します。(10.3.2.0 → 10.3.3.0)

その後再度applyを実行すると、差分は検出されませんでした。問題なくTerraform管理外とすることができました。

最後に

とても簡単にimportやremoveができます。特にimportは自分で一からプロパティを調べてterraformを書くよりずっと楽なことが多いです。とりあえずAzure Portalで作ってみてそれをimportしながらterraformを書くことで効率よく作業できそうです。

コメント