Terraformがステートファイルを必要とする理由(そしてラップトップに保存してはいけない理由)
terraform applyを実行して、サーバとデータベースの作成に成功したとします。すべてが正常に動作しています。満足してラップトップを閉じました。翌日、ロードバランサを追加する必要が生じ、設定を開いてリソースを追加し、terraform planを実行します。
Terraformは、すべてを最初から再作成しようとする計画を表示します。
何が起きたのでしょうか?Terraformは昨日構築したものを覚えていません。そのサーバが存在することも、データベースが稼働していることも知りません。作成したばかりのインフラの記録が一切ないのです。
これこそが、ほとんどのチームがステートファイルの必要性を痛感する瞬間です。
ステートファイルの実際の役割
ステートファイルはTerraformの作業記憶領域です。Terraformが作成したすべてのリソース、一意のID、最後に認識した設定、リソース間の関連性を記録します。terraform planを実行すると、Terraformはクラウドプロバイダに「何が存在するのか?」と問い合わせには行きません。それは遅く、一貫性がなく、プロバイダによって信頼性が異なるからです。代わりに、ステートファイルを読み込み、現在の設定と比較します。
レシートのようなものだと考えてください。購入のたびに、何を、いつ、いくらで買ったかが書かれたレシートを受け取ります。そのレシートがなければ、家の中をすべて調べて自分が何を所有しているか把握しなければなりません。Terraformも同じです。ステートファイルがなければ、クラウドアカウント全体をスキャンして自分が管理しているものを把握する必要があります。それでも、自分が作成したリソースと他の誰かが手動で作成したリソースを確実に区別することはできません。
2つのワークフローの視覚的な比較は以下の通りです。
ステートファイルには、各リソースに関する詳細情報が含まれています。クラウドサーバの場合、サーバID、IPアドレス、マシンタイプ、アベイラビリティゾーン、ネットワーク設定などです。データベースの場合は、エンドポイント、ポート、ストレージサイズ、バックアップ設定などです。この情報が、Terraformの次の操作における信頼できる情報源(Source of Truth)となります。
ラップトップ保存の問題
多くの開発者は、最初はステートファイルをローカルに保存します。これが最も簡単な方法です。Terraformはワーキングディレクトリにterraform.tfstateというファイルを作成し、そのまま進めます。
しかし、以下のような状況で問題が発生します。
- ラップトップが故障したり盗難にあった場合。
- 誤ってファイルを削除した場合。
- コンピュータを買い替えてファイルのコピーを忘れた場合。
- チームメイトが自分のマシンからTerraformを実行し、別のステートファイルを作成した場合。
ステートファイルが失われると、Terraformはインフラに関するすべての知識を失います。何も存在しないと認識します。terraform applyを再実行すると、すべてを最初から作成しようとします。結果として、リソースの重複、設定の競合、そして突然倍増するクラウド請求書に直面することになります。
さらに悪いことに、誰かがクラウドコンソールで手動でリソースを変更し、ステートファイルを更新しなかった場合、Terraformは同期が取れなくなります。サーバのRAMが4GBだと思っていても、実際のサーバは8GBです。次のterraform planは、現実と一致しない計画を生成します。
リモートステート:唯一の賢明なアプローチ
解決策は簡単です。ステートファイルをチーム全員がアクセスできる共有場所に保存することです。これをリモートステートと呼びます。
リモートステートとは、ステートファイルをAmazon S3、Azure Storage、Google Cloud Storageなどのストレージサービスに配置することを意味します。すべてのチームメンバーとすべてのCI/CDパイプラインが、同じステートファイルに対して読み書きを行います。これにより、全員が同じ信頼できる情報源を基に作業できるようになります。
リモートステートの設定は、通常、Terraformのバックエンドブロックで一度だけ行います。
terraform {
backend "s3" {
bucket = "my-team-terraform-state"
key = "production/terraform.tfstate"
region = "us-east-1"
}
}
一度設定すれば、Terraformはすべての計画の前にリモートストレージからステートファイルを自動的に取得し、適用後に更新をプッシュします。手動でファイルをコピーしたり、バージョンの競合を心配する必要はありません。
ステートロック:競合の防止
リモートステートを使用すると、複数の人が同時にTerraformを実行できるようになります。これにより、新たな問題が発生します。2人が同時にterraform applyを実行すると、ステートファイルが破損したり、一貫性のないインフラが作成される可能性があります。
ステートロックはこれを防ぎます。あるプロセスがterraform applyを開始すると、ステートファイルをロックします。他のプロセスはロックが解除されるまで待機する必要があります。ほとんどのリモートステートバックエンドはロックをサポートしています。S3はDynamoDBを使用してロックします。Azure Storageには組み込みのリースサポートがあります。Google Cloud Storageはオブジェクト世代番号を使用します。
ロックがない場合、以下のようなリスクが生じます。
- 2つの異なるパイプラインが同時に異なる変更をデプロイする。
- CI/CDパイプラインがデプロイ中に、開発者が手動でapplyを実行する。
- 変更の半分だけが記録される部分的な更新。
チーム環境では、ステートロックはオプションではなく必須です。
ステートファイル内の機密データ
ステートファイルには、Terraformがインフラについて知っているすべての情報が含まれます。これには、データベースのパスワード、APIキー、接続文字列などの機密情報も含まれます。Terraformはこれらの値をステートファイル内に平文で保存します。
つまり、ステートファイルはセキュリティリスクです。ステートファイルにアクセスできる人は誰でもシークレットを読むことができます。リモートステートバックエンドは通常、保存時と転送時の暗号化をサポートしています。S3はKMSによるサーバーサイド暗号化をサポートしています。Azure Storageはデフォルトで保存時暗号化をサポートしています。ステートストレージでは常に暗号化を有効にしてください。
また、環境ごとにステートファイルを分離するチームもあります。開発、ステージング、本番でそれぞれ別のステートファイルを別の場所に保存します。これにより、ある環境での変更が他の環境に影響を与えるのを防ぎます。また、ステートファイルが侵害された場合の影響範囲を限定できます。
CI/CDにおけるステートファイルの動作
CI/CDパイプラインでは、Terraformを実行するためにパイプラインがステートファイルにアクセスする必要があります。パイプラインは、認証情報やIAMロールを使用してリモートステートバックエンドに認証します。ステートファイルを取得し、terraform planを実行し、承認されればterraform applyを実行して更新されたステートをプッシュします。
これが、自動化にリモートステートが不可欠な理由です。エフェメラルコンテナで実行されるCI/CDパイプラインは、開発者のラップトップに保存されたステートファイルに依存できません。個々のマシンから独立して存在する、一貫性のあるアクセス可能な場所が必要です。
ステートファイル管理の実践的チェックリスト
- ステートファイルはローカルマシンではなく、リモートストレージに保存する。
- ストレージバックエンドの保存時および転送時の暗号化を有効にする。
- 同時変更を防ぐためにステートロックを設定する。
- 環境ごとに別々のステートファイルを使用する。
- IAMポリシーやアクセス制御を使用してステートファイルへのアクセスを制限する。
- ステートファイルをバージョン管理システムにコミットしない。
- 特に大きな変更の前には、ステートファイルを定期的にバックアップする。
チームにとっての意味
ステートファイルは無視できる実装の詳細ではありません。Terraformがインフラを確実に管理するための基盤です。適切に管理されたステートファイルがなければ、Terraformのワークフローは予測不能な結果、リソースの重複、デバッグが困難な障害を引き起こします。
複数の人がTerraformを実行するようになった瞬間、またはCI/CDパイプラインを追加した瞬間に、ステートファイルをリモートストレージに移行してください。設定には10分もかからず、問題が発生したときの復旧作業に何時間も費やす手間を省けます。
インフラは、ラップトップ上のファイルに委ねるにはあまりにも重要です。