こんにちは!クラウドインフラの世界へようこそ。
AWSのコンソール画面(ClickOps)でポチポチと手動で作ってしまったVPCやEC2、S3バケット……。「これ、後からTerraformのコードで管理したくなったけど、どうすればいいんだろう? 下手に触って本番環境を壊したら怖いな……」と頭を抱えた経験はありませんか?
大丈夫、焦らなくて大丈夫ですよ!現場で活躍するエンジニアも、最初はみんな同じ壁にぶつかります。
この記事では、そんな「手動で作られた既存のAWSリソース」を、Terraformのコード管理下に安全・確実に引き入れる強力な仕組み『terraform import』を徹底解説します。
昔のTerraformはインポート作業が少し複雑だったのですが、Terraform v1.5以降で登場した「宣言的インポート(importブロック)」を使えば、初心者の方でも驚くほど安全に、かつ自動でコード生成まで行えるようになりました。
これをマスターすれば、既存環境のコード化(IaC化)に怯える必要はもうありません。毎日の運用・保守作業が劇的に楽になりますよ!一緒に一歩ずつ進めていきましょう。
—
1. なぜ「インポート」が必要なのか?(メンタルモデルの理解)
実務に入る前に、まずはTerraformがリソースをどう管理しているのか、簡単なイメージを掴んでおきましょう。ここを理解しておくと、トラブルが起きたときでも慌てずに済みます。
Terraformの内部では、常に3つの状態が存在しています。
[ 1. 設定ファイル (.tf) ] <--- コードで定義した理想の姿 │ ▼ [ 2. 状態管理ファイル (terraform.tfstate) ] <--- Terraformが認識している現実 │ ▼ [ 3. 実際のAWSリソース ] <--- クラウド上の現実 通常、Terraformで新しいリソースを作るときは、`1 -> 2 -> 3` の順に全自動で作成されます。
しかし、マネジメントコンソール等で手動作成したリソースは、`3` しかない状態です。Terraformは「`3` の存在」をまだ知りません。この状態でいきなり `.tf` コードだけを書いて `terraform apply` を実行するとどうなるでしょうか?
Terraformは「あ、新しいリソースを作るんだな!」と勘違いし、既存リソースと重複して新しく作り直そうとするか、名前の衝突でエラーを起こしてしまいます。
そこで登場するのがインポートです。
インポートとは、「AWS上にある既存リソース(3)の情報を取り込み、Terraformの管理帳簿(2)とコード(1)に完璧に同期させる作業」のことなのです。
—
2. 実践準備:環境のセットアップ
さあ、実際に手を動かしてみましょう!
今回は一番シンプルで分かりやすい「S3バケット」を手動で作成し、それを安全にTerraformに取り込むハンズオンを行います。
必要な前提条件
- Terraform CLI: v1.5.0 以上(最新版を推奨)
- AWS CLI: 認証設定(`aws configure`)が完了していること
バージョンを確認してみましょう。ターミナル(またはコマンドプロンプト)で以下を実行します。
terraform -v
Terraform v1.5.0 以上であることを確認してください
実験用の既存リソースを手動作成する
まずは、インポート対象となる「手動で作られたS3バケット」をAWS CLIでサクッと作成しておきます。(AWSコンソールから手動で作ってもOKです)
ユニークなバケット名を決めて変数に入れます
BUCKET_NAME=”my-legacy-bucket-$(date +%s)”
AWS上にS3バケットを作成(手動作成のシミュレーション)
aws s3api create-bucket –bucket $BUCKET_NAME –region ap-northeast-1 –create-bucket-configuration LocationConstraint=ap-northeast-1
作成されたバケット名を出力してメモしておきます
echo “作成されたバケット名: ${BUCKET_NAME}”
これで「コード管理されていない野良リソース」がクラウド上に準備できました!
—
3. 完全ステップ解説:既存リソースを安全に取り込む5つの手順
ここからが本番です。Terraform v1.5から導入された「自動コード生成機能を備えた現代的なインポート手順」で進めます。恐ろしい手動でのコード手書きは不要です!
ステップ1: 作業用ディレクトリと基本設定の作成
適当な空の作業ディレクトリを作成し、初期化ファイルを用意します。
`provider.tf`(プロバイダーの設定)
Terraformプロバイダーのバージョン定義
terraform {
required_version = “>= 1.5.0”
required_providers {
aws = {
source = “hashicorp/aws”
version = “~> 5.0”
}
}
}
AWSプロバイダーの設定(東京リージョンを指定)
provider “aws” {
region = “ap-northeast-1”
}
ファイルを保存したら、初期化を実行します。
terraform init
—
ステップ2: `import` ブロックを記述する
次に、既存リソースとTerraformのリソース名を紐付けるための「`import` ブロック」を書きます。
`imports.tf` を新規作成してください。
既存リソースをTerraformに取り込むための宣言ブロック
import {
# Terraform側で管理したいリソースの型と名前を指定
to = aws_s3_bucket.imported_bucket
# 実際のAWSリソースのID(S3の場合はバケット名)
id = “先ほどメモしたバケット名(例: my-legacy-bucket-1700000000)”
}
—
ステップ3: 設定コードの自動生成(魔法のコマンド)
ここが一番のハイライトです!
通常、Terraformコード(`.tf`)は自分で書く必要がありますが、Terraformに既存リソースの構成情報を読み取らせてコードを自動生成させます。
ターミナルで以下のコマンドを実行してください。
terraform plan -generate-config-out=generated_resources.tf
このコマンドを実行すると、TerraformはAWSへ見に行き、「あ、`import` ブロックで指定されたS3バケットの設定はこうなってますね!」と解読して、`generated_resources.tf` というファイルにコードを全自動で書き出してくれます。
—
ステップ4: 生成されたコードの確認とクリーンアップ
自動生成された `generated_resources.tf` を開いてみてください。
以下のようなコードが生成されているはずです。
__generated__ by Terraform
ただし、デフォルト値や不要なパラメータも含まれている場合があります
resource “aws_s3_bucket” “imported_bucket” {
bucket = “my-legacy-bucket-1700000000”
bucket_prefix = null
force_destroy = null
object_lock_enabled = false
tags = {}
tags_all = {}
}
ちょっと不要な項目(`null` のものなど)が多くて見づらいですね。
プロの現場では、ここから必要な定義だけに整理(リファクタリング)します。今回は以下のように綺麗に整えましょう。
綺麗に整理したS3バケットの定義コード
resource “aws_s3_bucket” “imported_bucket” {
bucket = “my-legacy-bucket-1700000000” # メモしたご自身のバケット名
tags = {
Environment = “ManagedByTerraform” # 管理配下に入った証としてタグを付与
}
}
—
ステップ5: `terraform apply` で状態(State)を確定させる
コードの整理が終わったら、いよいよインポートを確定させます。
terraform apply
実行すると、ターミナルに以下のようなメッセージが表示されます。
Plan: 1 to import, 0 to add, 1 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
「1 to import(1つのインポート)」 と表示されていることを必ず確認してください!「1 to destroy(1つの削除)」などが出ていたら危険のシグナルです。
確認後、`yes` と入力してEnterを押します。
aws_s3_bucket.imported_bucket: Importing… [id=my-legacy-bucket-1700000000]
aws_s3_bucket.imported_bucket: Import complete [id=my-legacy-bucket-1700000000]
Apply complete! Resources: 1 imported, 0 added, 1 changed, 0 destroyed.
おめでとうございます! 既存のAWSリソースが、無事にあなたのTerraformコードおよびState管理下に組み込まれました!
—
4. 本当に安全?「ドリフト(差分)」がないことを確認する
インポートが成功したかどうかを確かめる黄金ルールがあります。
それは、もう一度 `terraform plan` を叩くことです。
terraform plan
実行結果が以下のようになれば完全勝利です。
No changes. Your infrastructure matches the configuration.
Terraform has meached the state of your infrastructure and found no differences to your configuration.
「No changes(変更なし)」。
これが、インフラの実際の状態(AWS)、Terraformの管理状態(State)、そしてあなたの書いたコード(HCL)の3つが完全な調和(冪等性)を保っているという動かぬ証拠です。
—
5. 現場で震えないための「シニアエンジニアの知恵袋」
最後に、実際のプロダクション環境で作業する際に事故を防ぐための極秘プロテクニックを3つ伝授します。
① 作業前に必ず State のバックアップを取る
本番環境でインポート作業を行う際は、必ずあらかじめStateファイル(`.tfstate`)のバックアップを取りましょう。
リモートStateを使っている場合でもローカルに退避させておく
terraform state pull > backup_before_import.tfstate
万が一インポート作業でStateが壊れても、このファイルがあればいつでも元の状態に戻せます。
② 親リソースと子リソースの分離に注意する
例えばEC2インスタンスをインポートしても、それにアタッチされている「Security Groupのルール」や「IAMロールのポリシー詳細」まで全自動で追従してくるとは限りません。
リソースによっては「親リソース」と「関連リソース(子)」を個別に `import` ブロックで記述する必要がある点に留意してください。
③ インポート完了後の `imports.tf` は残しても削除しても良い
`import` ブロックは、一度 `apply` が完了してStateに取り込まれた後は、残しておいても害はありません(2回目以降の `apply` では無視されます)。
チームの運用ルールに合わせて、残すか削除するかを決めましょう。(個人的には、履歴として残すかコミットログに明記して削除するのがコードをシンプルに保つコツです)。
—
まとめ
今回の手順をおさらいしてみましょう。
1. `import` ブロックに「取り込みたい既存リソースのID」を書く
2. `terraform plan -generate-config-out=…` でコードを自動生成する
3. 生成されたコードを綺麗に整える
4. `terraform apply` でインポートを確定する
5. `terraform plan` で「No changes」になることを確認する
どうでしょう? 難しそうに思えた「既存リソースのIaC化」が、驚くほど整然とした手順に思えてきたのではないでしょうか。
手動で作られたブラックボックスなインフラを恐れる必要はもうありません。この強力なツールを手にしたあなたなら、どんな既存環境でも安全にコードの世界へと導くことができますよ。
ぜひ、開発環境の小さなお試しリソースから挑戦してみてくださいね!応援しています!