Terraformのstate解析とimportブロック応用

stateは「コードと実物の対応表」

Terraform はコード(あるべき姿)と実際のリソースの間に、state という対応表を持ちます。

コード                state                     実リソース
aws_s3_bucket.logs → bucket-id: logs-9f2a1c → AWS上のS3バケット

plan が計算するのは「コードと state の差」ではなく、コード・state・実物の三者の差です。ここを取り違えると挙動が読めません。

  • コードにあり state に無い → 新規作成しようとする
  • state にあり実物が無い → 作り直そうとする(手で消された場合)
  • 実物にあり state に無い → Terraform は存在を知らない(触らない)

最後のケースが、手作業で作られたリソースの状態です。放置すると、同じ名前で作ろうとして衝突したり、消したつもりが残り続けたりします。これを解消するのが import です。

importブロック

かつては terraform import コマンドで1件ずつ state へ登録していました。適用してみるまで結果が分からず、間違えると state を壊す危険がありました。

現在は import ブロックをコードに書く方式が使えます。

import {
  to = aws_s3_bucket.logs
  id = "logs-9f2a1c"
}

resource "aws_s3_bucket" "logs" {
  bucket = "logs-9f2a1c"
}

利点は plan で結果を事前に確認できることです。取り込んだ結果コードと実物に差があれば、plan が「変更あり」として見せてくれます。差が出たらコード側を実物に合わせるのが原則で、逆にすると取り込んだ瞬間に本番が書き換わります。

さらに terraform plan -generate-config-out=generated.tf で、実物からリソース定義の雛形を生成できます。手で書き写す作業が減り、属性の書き漏らしも防げます。

大量のリソースを取り込む

数十〜数百件を手作業で書くのは現実的ではありません。実務では次の流れを組みます。

  1. クラウドのAPIやCLIで既存リソースを列挙する(タグやリソースグループで絞る)
  2. state を読み、既に管理下にあるものを除外する
  3. 残りから import ブロックを機械生成する
  4. plan を回し、差分が出た項目だけを人が確認する

state は JSON です。terraform show -json で機械可読な形が得られ、リソースの種類・アドレス・属性を取り出せます。state ファイルを直接編集してはいけません — 書式は内部仕様で、版によって変わります。読むのは可、書くのはコマンド経由が原則です。

stateそのものの運用

  • 秘密情報が入る — DBのパスワードなどが平文で含まれることがあります。リポジトリに置かない。リモートバックエンド(S3 + 暗号化など)に置きます
  • ロックが要る — 2人が同時に apply すると state が壊れます。ロック機構のあるバックエンドを使います
  • 分割の単位を決める — 1つの巨大な state は plan が遅く、影響範囲も広くなります。環境・サービス単位で分けます
  • [[GitOps(Atlantis)]] と組み合わせる — 適用をPR経由に寄せると、誰がいつ state を動かしたかが追えます

初学者向けポイント

  • plan の forces new resource を必ず読む — 取り込み後の最初の plan で出たら、コード側が実物と食い違っているサインです。適用すると消えます
  • 取り込みは一度に全部やらない。種類ごとに小さく分けると、差分の確認が現実的な量に収まります
  • terraform state rm は state からの登録解除で、実リソースは消えません。逆に destroy は実物を消します。この2つを取り違えると事故になります

関連技術とのつながり

  • [[IaC]] — コードで定義する考え方。import は「後からコード管理下へ入れる」操作
  • [[クラウドコンピューティング]] — 取り込む対象のリソース群
  • [[GitOps(Atlantis)]] — 適用をPR経由に寄せ、state の変更を追跡可能にする
  • [[CI/CD]] — 取り込み用の生成処理と plan を自動化する場所
  • [[JSON Schema]] — terraform show -json の出力を機械的に扱うときの考え方
Q: 「実リソースは存在するがstateに無い」状態でTerraformはどう振る舞う?
- [ ] 自動的に取り込む
- [ ] 削除しようとする
- [x] 存在を知らないため何もしない
解説: 放置すると同名で作ろうとして衝突したり、消したつもりが残り続けたりします。importで解消します。

Q: `terraform import` コマンドに対するimportブロックの利点はどれ?
- [x] `plan` で取り込み結果を事前に確認できる
- [ ] stateファイルが不要になる
- [ ] 実行が速くなる
解説: 適用前に差分が見えるため、コードと実物の食い違いを事前に直せます。

Q: 取り込み後の最初の `plan` で `forces new resource` が出たときの正しい対応はどれ?
- [ ] そのまま適用する
- [x] コード側を実物に合わせて書き直す
- [ ] stateファイルを直接編集する
解説: そのまま適用すると実リソースが作り直されます。stateの直接編集は書式が内部仕様のため禁じ手です。