Terraformのimportコマンドとimportブロックを試してみた

Terraformの標準機能であるimportコマンド、またはimportブロックを使用すると、既存のリソースをTerraform管理下に置くことができます。今回はそれぞれの使用方法を紹介します。
2024.01.29

※Terraform v1.7.0を使用しています。

importコマンド

terraform importコマンドは、指定した既存リソース及びその設定情報の定義をtfstateファイルに生成するコマンドです。
- 公式ドキュメント

① インポート対象リソースの作成

「manabe-test-instance」というNameタグを付けたEC2インスタンスを作成します。

② resourceブロックの作成

tfファイルに、インポート対象リソース用のresourceブロックを定義します。
この時点では、パラメータの定義は不要です。
例えば、「aws_instance」においては「ami」と「instance_type」が必須パラメータですが未定義で問題ありません。

resource "aws_instance" "sample1" {
}

③ importコマンドの実行

importコマンドの使用方法は以下の通りです。

terraform import [resourceブロックのtype].[resourceブロックのname] [リソースID]

実行します。

$ terraform import aws_instance.sample1 i-0da09fb0d4fe82991
~~ 省略 ~~
Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

importコマンドが成功した後、tfstateファイルを見るとリソースの定義が生成されていることが確認できます。

④ tfファイルの修正

tfファイルのresourceブロックの中身は未定義のままなので、terraform planコマンドで差分を確認しつつ修正していきます。

resource "aws_instance" "sample1" {
  // 追記
  ami           = "ami-0de5b371cbca0edcb"
  instance_type = "t2.micro"

  tags = {
    Name = "manabe-test-instance"
  }
}

差分がなくなりました。

$ terraform plan
~~ 省略 ~~
No changes. Your infrastructure matches the configuration.

importブロック

importブロックはTerraform v1.5.0 でリリースされた機能です。

importコマンドではリソースの定義はtfstateファイル上にしか生成されず、tfファイルは手書きで編集する必要がありましたが、importブロックを使用するとtfファイル上にもリソース定義を自動生成することが可能です。
また、importコマンドは1リソースずつ行う必要がありますが、importブロックは複数リソースをまとめて実行することができます。

importブロックの一般的な使用方法として、resourceブロックをimportブロックによって自動生成するパターンと、resourceブロックを事前に作成しておくパターンがあります。

resourceブロックをimportブロックによって自動生成するパターン

① インポート対象リソースの作成

先ほど同様、「manabe-test-instance」というNameタグを付けたEC2インスタンスを作成します。
※先の手順で作成したインスタンスは、terraform destroyコマンドを使用して削除済です。

② importブロックの作成

以下のように定義します。

import {
  id = "i-052562f6eee9d60d9"
  to = aws_instance.sample1
}

「id」及び「to」は必須パラメータです。

  • 「id」:[リソースID]
  • 「to」:[resourceブロックのtype].[resourceブロックのname]

③ tfファイルにリソース定義をインポート

以下のように、「-generate-config-out=[任意の名前].tf」というオプションを付けてterraform planコマンドを実行します。
※生成するファイルが存在する場合エラーとなるので、存在しないファイル名を指定しなければなりません。

$ terraform plan -generate-config-out=import.tf
aws_instance.sample1: Preparing import... [id=i-052562f6eee9d60d9]
aws_instance.sample1: Refreshing state... [id=i-052562f6eee9d60d9]

Planning failed. Terraform encountered an error while generating this plan.

╷
│ Warning: Config generation is experimental
│
│ Generating configuration during import is currently experimental, and the generated configuration format may change in future versions.
╵
╷
│ Error: Conflicting configuration arguments
│
│   with aws_instance.sample1,
│   on import.tf line 14:
│   (source code not available)
│
│ "ipv6_address_count": conflicts with ipv6_addresses
╵
╷
│ Error: Conflicting configuration arguments
│
│   with aws_instance.sample1,
│   on import.tf line 15:
│   (source code not available)
│
│ "ipv6_addresses": conflicts with ipv6_address_count

実行後、本オプションで指定したtfファイルが作成され、中にリソース定義が生成されます。

また、import.tfファイルが生成されるのと同時に、terraform planコマンドの実行結果としていくつかエラーが出力されています。
Terraformによって生成されたファイルには共存しないパラメータが存在する可能性があり、存在する場合このようにエラーが出力されます。

本手順の場合、自動生成されたresourceブロック内のパラメータ「ipv6_addresses」と「ipv6_address_count」が競合していました。
「ipv6_address_count」をコメントアウトし、オプションを付けずにterraform planコマンドを実行します。

$ terraform plan
~~ 省略 ~~
Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.

エラーがなくなりました。

④ tfstateファイルにリソース定義をインポート

terraform applyコマンドを実行します。

$ terraform apply
aws_instance.sample1: Preparing import... [id=i-052562f6eee9d60d9]
aws_instance.sample1: Refreshing state... [id=i-052562f6eee9d60d9]
~~ 省略 ~~
Apply complete! Resources: 1 imported, 0 added, 0 changed, 0 destroyed.

実行後、tfstateファイルにリソース定義が自動生成されていることが確認できます。

ここまでの手順が完了したら、importブロックは削除して大丈夫です。

resourceブロックを事前に作成しておくパターン

importブロックの「to」に定義したresourceのアドレスがtfファイル上に既に存在する場合、terraformはtfファイルの自動生成を行わず、既存のresourceブロックと実際のリソースが紐づけられます。
事前にresourceブロックの定義が可能であればこちらのパターンが使用可能です。

① インポート対象リソースの作成

先ほど同様、「manabe-test-instance」というNameタグを付けたEC2インスタンスを作成します。
※先の手順で作成したインスタンスは、terraform destroyコマンドを使用して削除済です。

② importブロック、resourceブロックの作成

以下のようにimportブロック、resourceブロックを定義します。

import {
  id = "i-073eddd24e734b1ff"
  to = aws_instance.sample1
}

resource "aws_instance" "sample1" {
  ami           = "ami-0de5b371cbca0edcb"
  instance_type = "t2.micro"

  tags = {
    Name = "manabe-test-instance"
  }
}

③ インポートの実行

terraform applyコマンドを実行します。

$ terraform apply
aws_instance.sample1: Preparing import... [id=i-073eddd24e734b1ff]
aws_instance.sample1: Refreshing state... [id=i-073eddd24e734b1ff]
~~ 省略 ~~
Apply complete! Resources: 1 imported, 0 added, 1 changed, 0 destroyed.

実行後、tfstateファイルにリソース定義が生成されていることが確認できます。

ここまでの手順が完了したら、importブロックは削除して大丈夫です。
以上で本手順は終了です。

最後に

importブロックはtfファイルの生成も可能なので非常に便利ですが、本番環境等においてterraform applyコマンドを使用するのは少し怖い気もします。
使用する場合は既存リソースの再生成等が行われないように注意しないといけません。

また、今回はTerraformの標準機能を使用したインポート方法をご紹介しましたが、「Terraformer」や「terracognita」といったツールを使用したインポート方法も存在するようなので、今度そちらも試してみようと思います。