悪魔は `terraform plan` に潜む:本番環境を破壊から守る「予期せぬ再作成」との決別
「え、なんでここで `destroy` が走るの?」
深夜のリリース作業中、そんな悲鳴を上げたことはないだろうか。IaC(Infrastructure as Code)の伝道師を自称する者であっても、Terraformの「予期せぬリソース再作成」という地雷を踏むことはある。本稿では、Terraformがなぜ時に牙を剥くのか、その深淵を覗き込み、鉄壁の守りを築くための「プロの技術」を伝授する。
—
1. なぜ「再作成」が起きるのか?:知られざるAPIの挙動
Terraformの `plan` は、単なる差分表示ではない。クラウドプロバイダーのAPI仕様と、TerraformのStateファイル間の「通訳」だ。以下のケースは、実務で最も多く発生する「破壊のトリガー」である。
- 「ForceNew」の罠(API仕様の変更): クラウド側のAPIが、特定のプロパティ変更に対して「更新不可(PUT/PATCH不可)」と定義している場合、Terraformは強制的に `delete` して `create` し直す。特にデータベースのインスタンスタイプや、一部のリージョン制限に関わる属性は要注意だ。
- 依存関係の連鎖: あるリソースAの属性が変更される際、それがリソースBの「ID」に関与していると、連鎖的に再作成が発生する。
- 計算された値の不一致: `random_id` や `timestamp()` などをリソースのパラメータに組み込むと、planのたびに「差分」が発生し、無限再作成ループに陥ることがある。
—
2. 計画段階で「破壊」を予見する:プロの審美眼
`terraform plan` を眺める際、`-/+`(置換) の記号がどこに出ているかを直感的に探せるようにならなければならない。
-refresh-only の真価
Stateファイルと実環境がズレている状態で `plan` を実行すると、誤った差分が表示される。リリース前には必ず以下を実行し、Stateを最新の状態に同期させよ。
実環境の構成をstateに反映させる(リソースは変更しない)
terraform plan -refresh-only
ライフサイクル設定で「防御壁」を築く
もし、誤操作でDBやストレージが消えるのを防ぎたいなら、迷わず `lifecycle` ブロックを使うべきだ。
resource “aws_db_instance” “production_db” {
# … 略 …
lifecycle {
# 誤操作による削除を完全にブロックする
prevent_destroy = true
# 特定の属性変更による再作成を無視する(API仕様変更時の一時的退避)
ignore_changes = [
instance_class,
tags[“CreatedBy”]
]
}
}
—
3. 生産性を極限まで高める「神設定」
現場のテックリードとして、チーム全体のレベルを底上げするための設定を共有する。
推奨 VSCode プラグイン
- HashiCorp Terraform (公式): 言わずもがな。
- TFLint: `plan` する前に静的解析を行う。「クラウドの型」に合わない記述をエディタ上で即座に検知する。
- Terraform Lens: 巨大なstateファイルの中から必要なリソースを瞬時に検索する。
隠れたキーボードショートカット(VSCode)
- `Ctrl + Alt + F` (Format): ファイル保存時に自動フォーマットされるように設定せよ(`.vscode/settings.json`)。
- `Ctrl + Click` (Jump to Definition): モジュール構造が深い場合、変数定義へ即座に飛ぶ。
—
4. ベストプラクティス:保守性の高い構成
設定ファイルは「DRY(Don’t Repeat Yourself)」を追求しすぎると、逆に依存関係が見えなくなる。「疎結合かつ明確な構造」が正義だ。
main.tf の構成例:モジュールは責務ごとに分割する
module “vpc” {
source = “./modules/network”
# 変数は直接記述せず、必ずtfvars経由で注入する
cidr_block = var.vpc_cidr
}
vars.tf (型定義を徹底する)
variable “vpc_cidr” {
type = string
description = “VPCのCIDRブロック。変更時は慎重に行うこと”
validation {
condition = can(regex(“^([0-9]{1,3}\\.){3}[0-9]{1,3}/[0-9]{1,2}$”, var.vpc_cidr))
error_message = “CIDRの形式が不正です。”
}
}
チーム開発の鉄則:Stateの共有化
- Remote Backend (S3 + DynamoDB): ローカルの `.tfstate` は即刻廃止せよ。ロック機構がない環境での並列実行は破滅を招く。
- Terraform Cloud / Enterprise: コストが許すなら導入すべきだ。特に「Planの共有」機能により、メンバー間でのレビュー品質が劇的に向上する。
—
最後に:エンジニアとしての矜持
「自動化」とは、単にコマンドを叩くことではない。「何が起きるかを完全に掌握し、予測不能な事態を排除し続けるプロセスそのもの」である。
`plan` で表示される行の一文字一文字に、本番環境の命がかかっている。その重みを理解しているか? もし `plan` を確認せずに `apply` を打っているなら、今すぐその習慣を改めるべきだ。
技術を愛し、コードを通じてインフラを制御せよ。それが我々SREに課せられた、唯一の、そして最高の任務なのだから。