1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

既存クラウドリソースをTerraformに取り組む手法の比較

1
Last updated at Posted at 2026-06-18

はじめに

既存インフラをTerraform管理下に置くには、以下の4つの手法が考えられます。

  • terraform importだけを使う
  • importブロック + -generate-config-outの組み合わせ
  • Terraformerなどのサードパーティーツールを使う
  • terraform query + -generate-config-outの組み合わせ

また、どの手法を採用する場合でも、AIエージェントを使うことは最早一般的だと言えます。
その上で、どの手法が最も効率・精度よくTerraform管理下に置けるかは気になるところです。
自分はこの4つを試してみましたが、結論としてはimportブロック + -generate-config-outの組み合わせが現状は一番いいと思いました。
本記事では、4つの手法の比較と、その上でなぜimportブロック + -generate-config-outの組み合わせが一番いいと感じたかについてを紹介します。


1. terraform import + 手動でコード作成

概要

terraform import <リソースタイプ.名前> <リソースID> でステートにリソースを取り込んだ後、対応するコードを開発者が手書きする。

手順

  • terraform import aws_instance.web i-0123456789abcdef0のようなterraformコマンドをターミナルで実行する(このとき、事前にaws_instance.webのリソースを作っておく)
$ terraform import aws_instance.web i-0123456789abcdef0
aws_instance.web: Importing from ID "i-0123456789abcdef0"...
aws_instance.web: Import prepared!
  Prepared aws_instance for import
aws_instance.web: Refreshing state... [id=i-0123456789abcdef0]

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.
  • terraform state show aws_instance.webコマンドや実機より現在の属性を確認
$ terraform state show aws_instance.web
# aws_instance.web:
resource "aws_instance" "web" {
  ami                                  = "ami-0123456789abcdef0"
  arn                                  = "arn:aws:ec2:ap-southeast-2:123456789012:instance/i-0123456789abcdef0"
    associate_public_ip_address          = false
    availability_zone                    = "ap-southeast-2a"
~~~
    root_block_device {
        delete_on_termination = true
        device_name           = "/dev/sda1"
        encrypted             = false
        iops                  = 225
        kms_key_id            = null
        tags                  = {
            "Name"    = "kato-import-test"
            "Owner"   = "kato"
            "Project" = "import-test"
        }
        tags_all              = {
            "Name"    = "kato-import-test"
            "Owner"   = "kato"
            "Project" = "import-test"
        }
        throughput            = 0
        volume_id             = "vol-0123456789abcdef0"
        volume_size           = 75
        volume_type           = "gp2"
    }
}
  • 確認した属性をもとに .tf ファイルを手書き
resource "aws_instance" "web" {
  ami                  = "ami-0123456789abcdef0"
  instance_type        = "t3a.micro"
  subnet_id            = "subnet-0123456789abcdef0"
  vpc_security_group_ids = ["sg-0123456789abcdef0"]
  iam_instance_profile        = "kato-import-test"

  tags = {
    Name = "kato-import-test"
  }
}
  • terraform planでドリフトがなくなるまで調整
$ terraform plan
aws_instance.web: Refreshing state... [id=i-0123456789abcdef0]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are
needed.

長所

  • Terraform のバージョンを選ばない(古いバージョンでも動作)
  • 生成されるコードが自分の命名規則・スタイルに合わせることができる
  • 不要な属性を意図的に省略し、シンプルなコードにできる

短所

  • コーディング工数が大きい(属性数が多いリソースほど辛い)
  • 属性の書き漏れによるterraform planのドリフト解消が手間
  • 大量リソースへのスケールが困難

向いているケース

  • 対象リソースが少数
  • コードの品質・可読性を最優先したい場合
  • チームの Terraform スキルが高く、手書きのほうが速い場合

AI活用のしやすさ

  • terraform importを実行するのは人が行う必要がある
    • AIに実行させてもいいが、リソースごとに実行するため、トークン消費量が多い。
  • terraform state showの出力をコピーしてAIに渡す手間が毎回発生し、インタラクションが人間主導になる
    • この実行をAIにやらせる場合でもリソースごとに実行するため、トークン消費量が多い。
  • 属性の省略基準(どの属性を書いてどの属性を省くか)をAIが正確に判断するのは難しく、指示が曖昧だと冗長または不足なコードになりやすい
  • リソース数が多い場合、AIへの入力・出力のやり取りが繰り返し発生し、スケールしない

2. terraform import + -generate-config-out

概要

Terraform 1.5より導入された -generate-config-outオプションを使い、importブロックと組み合わせてコードを自動生成する。

手順

  • import ブロックを.tfファイルに記述
import {
    to = aws_instance.web
    id = "i-0123456789abcdef0"
}
  • terraform plan -generate-config-out=generated.tfを実行(この時エラーが出ることがありますが、generated.tfが生成されていれば、この時点では問題ありません)
$ terraform plan -generate-config-out=generated.tf
aws_instance.web: Preparing import... [id=i-0123456789abcdef0]
aws_instance.web: Refreshing state... [id=i-0123456789abcdef0]

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.web,
│   on generated.tf line 1:
│   (source code not available)
│ 
│ "primary_network_interface": conflicts with associate_public_ip_address
╵
╷
│ Error: Conflicting configuration arguments
│ 
│   with aws_instance.web,
│   on generated.tf line 13:
│   (source code not available)
│ 
│ "ipv6_address_count": conflicts with ipv6_addresses
╵
╷
│ Error: Conflicting configuration arguments
│ 
│   with aws_instance.web,
│   on generated.tf line 14:
│   (source code not available)
│ 
│ "ipv6_addresses": conflicts with ipv6_address_count
  • 生成されたgenerated.tfを確認・整形(1. terraform import + 手動でコード作成と同じリソースを対象にしているので、具体例は省略します)
  • terraform applyでステートに取り込む
$ terraform apply
aws_instance.web: Preparing import... [id=i-0123456789abcdef0]
aws_instance.web: Refreshing state... [id=i-0123456789abcdef0]

Terraform will perform the following actions:

  # aws_instance.web will be imported
    resource "aws_instance" "web" {
    ami                                  = "ami-0123456789abcdef0"
    arn                                  = "arn:aws:ec2:ap-southeast-2:123456789012:instance/i-0123456789abcdef0"
        associate_public_ip_address          = false
        availability_zone                    = "ap-southeast-2a"
~~~~~~
        root_block_device {
            delete_on_termination = true
            device_name           = "/dev/sda1"
            encrypted             = false
            iops                  = 225
            kms_key_id            = null
            tags                  = {
                "Name"    = "kato-import-test"
                "Owner"   = "kato"
                "Project" = "import-test"
            }
            tags_all              = {
                "Name"    = "kato-import-test"
                "Owner"   = "kato"
                "Project" = "import-test"
            }
            throughput            = 0
            volume_id             = "vol-0123456789abcdef0"
            volume_size           = 75
            volume_type           = "gp2"
        }
    }

Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_instance.web: Importing... [id=i-0123456789abcdef0]
aws_instance.web: Import complete [id=i-0123456789abcdef0]

Apply complete! Resources: 1 imported, 0 added, 0 changed, 0 destroyed.

長所

  • 公式機能のため追加ツール不要
  • importブロックをコードとして管理でき、レビュー・再現が容易
  • 大量リソースでもimportブロックを列挙することで対応可能

短所

  • Terraform 1.5 以上が必須
  • 自動生成コードは冗長になりやすく、整形・レビュー工数が発生する
  • 一部プロバイダーでは生成品質にばらつきがある
  • Terraform 1.5〜1.7 は試験的機能扱いであり、挙動が変わる場合がある

向いているケース

  • Terraform 1.5+ を使用している環境
  • 中〜大規模のリソースをまとめてインポートしたい場合
  • インポート操作をコードレビューのワークフローに組み込みたい場合

AI活用しやすさ

  • importブロックの記述はシンプルな構文(toidの2つの属性のみ)なので、リソース一覧をAIに渡せばまとめて生成させやすい
  • terraform plan -generate-config-outでコードが自動生成されるため、AIへコードを書かせる指示が不要。AIの役割は生成済みコードの整形・クリーンアップに絞られる
    • 具体的には、命名規則への統一・不要なブロックの削除をAIに依頼できる
  • ただし、terraform planterraform applyの実行自体は人間(またはCIパイプライン)が行う必要があり、完全な自動化にはもう一工夫必要
  • 生成コードにエラーが含まれる場合(上記のように conflicting arguments など)、エラーメッセージをAIに渡して修正を依頼するサイクルが発生する

3. Terraformerなどのサードパーティツール

概要

サードパーティツールを使い管理下に置くことも手の一つです。ここでは、その中でも検索した時に最初に引っかかったTerraformerを紹介します。これは、GitHubのGoogleCloudPlatformでOSSとして公開されているサードパーティツールで、既存リソースから .tfファイルと.tfstateを一括生成する。場所はここです。なお、こちらは2026/6/18時点で既にアーカイブに入っているため、これ以上更新されません。そのため、紹介しておいてではありますが、使うことは非推奨です。本記事では、これまで主流だったサードパーティーツールの例として挙げます。

手順

インストールはGitHubの「Installation」を参考に実行してください。以降は、インストールされている前提で紹介します。

  • terraformer importを実行します。このままではリソースの全てをimportしてしまうので、同時にリソースタイプやリージョンなどをフィルターしてください。以下は、シドニーリージョンにある、名前がkato-import-testという名前のEC2インスタンスを抽出しています。
terraformer import aws --regions=ap-southeast-2 --resources=ec2_instance --filter='Name=tags.Name;Value=kato-import-test'
  • 生成されたgenerated/aws/配下のコードを取り込み、命名規則に合わせてリファクタリングする
resource "aws_instance" "tfer--i-0123456789abcdef0_kato-import-test" {
  ami                         = "ami-0123456789abcdef0"
  associate_public_ip_address = "false"
  availability_zone           = "ap-southeast-2a"
~~~~~~
  tags_all = {
    Name    = "kato-import-test"
    Owner   = "kato"
    Project = "import-test"
  }

  tenancy                = "default"
  vpc_security_group_ids = ["sg-0123456789abcdef0"]
}
  • このとき、generated/aws/配下にtfstateファイルができるので、クラウド管理にしたいときは、バックエンド設定を記述した上でterraform init -migrate-stateを実行してリモートへ移行してください

長所

  • Terraform公式では対応していない操作も可能になる
  • 社内要件(命名規則、タグなど)を組み込めるものもある

短所

  • メンテナンスが不安定な時期がある(Issue・PR が滞留しやすい)
  • 生成コードの品質はツール依存で、大量のリファクタリングが必要になることが多い
  • 開発・保守コストが発生する
  • プロバイダーのバージョンアップへの追従が必要

向いているケース

  • 検証・開発段階で使う場合
  • ツールの信頼性が取れている場合

AI活用のしやすさ

  • フィルター条件や対象サービスが増えるとコマンドが複雑になりやすいが、AIに下書きを作らせることで試行回数を減らしやすい
  • 生成リソース名(tfer--...)や作成される属性の冗長性はツールに依るため、その人間レビューは必要
  • 使用例の数がツールによってバラバラなため、ものによってはAIで上手く作成できない
  • ツールが非推奨(アーカイブ済み)だと将来の互換性リスクが残るため、AIで手順を自動化しても長期運用の安心感は低い

4. terraform query

概要

terraform queryコマンドでステートや計画データをクエリし、リソース情報を抽出・確認できる。インポートそのものではなく、インポート後の検証や棚卸しに位置づけられる。これと-generate-config-outを組み合わせることで、インポートを行う。

手順イメージ

こちらに実行手順を載せてますので、割愛します。

長所

  • ステート内のリソース情報を柔軟に検索・集計できる
  • スクリプト連携により自動化が容易

短所

  • インポート機能ではないため、単体では既存リソースの取り込みには使えない
  • 公式ドキュメントの整備が追いついておらず、公式には既に載っているもののまだ使えない機能もある

向いているケース

  • インポート済みステートの棚卸し・監査
  • ドリフト検出のスクリプト自動化
  • 大規模ステートから特定条件のリソースを抽出したい場合

AI活用のしやすさ

  • Terraform公式が整備しているため、ドキュメントの信頼性は高い


4つを比較しての結論

今回自分が既存リソースをTerraformに取り組む手法をいくつか試してみて、現段階で最も有効的だと感じたのは、冒頭でも記載した通りimportブロック + -generate-config-outの組み合わせだと感じました。理由は以下の通りです。

  • importブロックの機能はTerraform公式が出しているため、信頼性が高い
  • importブロックが単純な構造のため、AIでも記述しやすい
  • ほぼ全てのリソースにおいてimportブロックは整備されているため、リソース制限が少ない
  • 一度importブロックに記述させることで、対象リソースを網羅しているか人が確認できる
  • -generate-config-outコマンドでコードを作るため、importブロックさえしっかりしていればコードの冪等性が高い

一方で、この手法ではimportブロックに記載するリソースIDをどのようにして取得するかの問題があります。
自分の経験になってしまいますが、対象リソース全てに特定のタグが付いている場合は比較的精度よくやってくれます。しかし、実運用でこれが為されていることは少なく、大抵はタグ付け漏れがある、またはそもそもタグが付いていないという場合が多いと思います。その場合は名前などで引っかけることになると思いますが、その際の精度はそこまで高くない印象です。
このように名前などで対象リソースIDを取得するのはterraform queryが最も精度が良かったです。ただ、terraform queryは公式ドキュメントの整備が未熟であったり、そもそも対応リソースが少なかったりと現段階ではまだ使いにくいと思いました。
以上より、2026/6/18時点ではimportブロック + -generate-config-outの組み合わせが最も効果的ですが、将来性ではterraform queryに軍配が上がると考えてます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?