📌

[Terraform] 既存のリソースをimportするにはimport blockが有用

2024/02/18に公開

副業で携わっている案件で、Terraform で管理されていないインフラストラクチャのリソースを Terraform で管理する(state ファイルに反映する)ことになり、下記の2つの方法について調査をしました。

  • terraform import コマンドを使う
  • import block を使う

チームでの運用を考慮すると、terraform import コマンドにはいくつかの課題があることがわかりました。また、v1.5 から使用可能となった import block はこの課題を解消しており、import block の方が有用ではないか、と考えたのでこの点について紹介します。

前提

下記の運用を前提にしています。

  • terraform apply コマンドは、CI/CD のワークフローによって、PR がマージされたタイミングで自動で実行される
  • state ファイルの変更を伴うコマンドの実行はローカルで行わない

逆に、開発者がローカル上で定常的に state ファイルを書き換えるような操作を行うことは前提としていません。

terraform import コマンドについて

terraform import コマンドを使うことで、state ファイルに目的のリソースを反映することができます。

https://developer.hashicorp.com/terraform/cli/commands/import

作業フローは下記のとおりです。

しかし、下記に上げる 2 点の問題点から基本的に使用は控えるべきだと考えました。

1. コマンド実行後に一時的に state ファイルと configuration ファイルに差分が生じる

terraform import コマンドを実行すると、state ファイルに目的のリソースは反映されているのですが、この時点ではまだ configuration ファイル (.tf ファイル) の resource block として定義されているわけではありません。

そのため、resource block を定義するまでに、terraform plan コマンドを実行すると差分が出てしまいます。

チームでの運用を考えると、ある開発者が terraform import を実行し、別の開発者が terraform plan を実行すると意図しない差分が出るなどの問題が生じてしまう可能性が存在します。

2. コマンド実行前にレビューしづらい

terraform import コマンドを実行する場合、実行前にこのコマンドの内容を第三者にどのようにレビューしてもらうか、という問題があります。ワンショットのシェルスクリプトを作成し、これをレビューしてもらうという方法もありますが、state ファイルにリソースがどのように反映されるかイメージしづらく、決してわかりやすい方法ではありません。

また、基本的に state ファイルの更新を伴う操作はローカルでは行うべきではなく、CI/CD パイプラインによって行うべきです。terraform planterraform apply を行う CI/CD があったとしても、さらに terraform import を対応するためのコストは低くはないでしょう。

import block について

次は、Terraform v1.5 から利用できるようになった import block についてです。この方法がチームでの運用に適していると考えられます。

https://developer.hashicorp.com/terraform/language/import

作業フローは下記のとおりです。

import block 使用時と異なり、resource block を定義してから terraform apply した後に state ファイルが更新されます。

そのため、import block の課題であったタイムラグやレビューのしづらさの問題が解消されているのです。

  • terraform apply 前に、import blockresource block のレビューが可能
  • terraform apply によって state ファイルが更新される

import block 使用例

import block の使用例を紹介します。
UI から作成した GCS Bucket を Terraform 管理にする場合について考えてみます。まず、import block を使ってリソースを追加します。

import {
  id = "mybucket-import-test"
  to = google_storage_bucket.mybucket_import_test
}

次に、terraform plan -generate-config-out コマンドを使って、import block を使用したリソースの定義を生成します。-generate-config-out オプションは Experimental ですので使用する際は一定の検討が必要ですが、私は PoC を経た上で有用だと判断し導入を決断しました。

https://developer.hashicorp.com/terraform/language/import/generating-configuration

terraform plan -generate-config-out=gen_google_storage_bucket.tf

生成されたファイルを見てみます。注目すべきなのは、この時点では state ファイルは変更されていない点です。

# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.

# __generated__ by Terraform from "mybucket-import-test"
resource "google_storage_bucket" "mybucket_import_test" {
  default_event_based_hold    = false
  enable_object_retention     = false
  force_destroy               = false
  labels                      = {}
  location                    = "ASIA-NORTHEAST1"
  name                        = "mybucket-import-test"
  project                     = "myproject"
  public_access_prevention    = "enforced"
  requester_pays              = false
  rpo                         = null
  storage_class               = "STANDARD"
  uniform_bucket_level_access = true
  timeouts {
    create = null
    read   = null
    update = null
  }
}

上記の import blockresource block を反映した PR を作成することで新たに追加されるリソースを第三者がレビューすることが可能です。レビューを経た PR をマージし、CI/CD によって terraform apply を実行することで、このリソースが state ファイルに追加されます。

チームでの運用を考えた場合、追加でいくつか作業をするのがベターです。

まず、import blockapply 後に state ファイルに反映後は不要になるため削除します。

次に、任意ですが、自動生成した resource block の定義は引数が冗長であるため、必要な引数のみを残し、不要な引数を削除します。

resource "google_storage_bucket" "mybucket_import_test" {
  location = "ASIA-NORTHEAST1"
  name     = "mybucket-import-test"
}

だいぶスッキリしたのではないでしょうか?

まとめ

terraform import コマンドは手軽に利用できるメリットはあるものの、チームでの運用を考えると、import block を利用したほうが良いのではないかと考えました。

より良い方法などありましたら、コメントお願いします 🙇‍♂️

Discussion