Cloud Run のサービスを Terraform で管理しつつ、日々のデプロイは別のスクリプト(イメージをビルド → Cloud Run を更新)で回していました。
ある日、設定を1つ足すだけのつもりで terraform plan を打つと、変えていないはずのサービスまで「変更あり」で並びました。中身を見ると、本番の web サービスのイメージを今動いているものより古いタグに差し替える変更でした。そのまま apply していたら、本番が過去のコードに戻るところでした。
原因
Terraform のコードにはイメージのタグが書いてあります(例:web_image_tag = "aaa1111")。
デプロイスクリプトは Cloud Run を直接新しいイメージ(例:bbb2222)に更新しますが、Terraform 側のタグを書き換えたコミットを main に戻していませんでした。その結果、
- 本番で動いているもの:
web:bbb2222 - Terraform のコードに書いてあるもの:
web:aaa1111
というズレができます。この状態で無指定の terraform apply を打つと、Terraform は「コードのとおりにする」ので、本番を aaa1111 に戻します。自分が触った設定とは無関係なサービスが巻き込まれます。
直し方1:plan の件数を先に見る
Plan: N to add, M to change, K to destroy. の数字が、自分が変えたつもりの数より多ければドリフトがあります。中身を読むまで apply しません。
terraform plan -no-color | grep -E '^Plan:|will be updated|must be replaced'
直し方2:apply は -target で変えたものだけに絞る
terraform plan -target=module.my_change
terraform apply -target=module.my_change
-target は Terraform 自身が「日常の運用で使うものではない」と注意しているオプションです。ここでは「ズレを直すまでの間、関係ないものに触らない」ための一時的な手当てとして使っています。
直し方3:ズレの元を断つ
スクリプトでデプロイしたら、Terraform 側のタグも同じ値に書き換えてコミットし、main に戻すところまでを1つの手順にします。本番のイメージとコードのタグが一致していれば、無指定の plan は自分の変更だけを出します。
今どちらが動いているかは、次で比べられます。
# 本番で動いているイメージ
gcloud run services describe web --region asia-northeast1 \
--format="value(spec.template.spec.containers[0].image)"
# Terraform のコードに書いてあるタグ
grep -n 'web_image_tag' envs/prod/*.tf
まとめ
- Terraform 以外の手段でデプロイすると、コードのタグが古いまま残り、無指定の apply が本番を巻き戻す
- plan の件数が想定より多ければ apply しない。中身を読む
- 当面は
-targetで絞る。根本はデプロイのたびにタグをコミットして main に戻すこと
生成AI(Claude Code)に書かせて一人で会社を回している記録を note に書いています。
https://note.com/kaito_cometa