Terraform Apply 実行の内部動作:承認後の実際の処理フロー

プラン出力を確認し、Terraform が2つの EC2 インスタンスを作成すること、既存のデータベースを削除しないこと、正しいセキュリティグループをアタッチすることを確認しました。いよいよ terraform apply と入力して Enter キーを押します。ターミナルには aws_instance.app_server: Creating... のようなメッセージが流れ、待機状態に入ります。

この瞬間、Infrastructure as Code は設定ファイルから現実のインフラへと変わります。サーバーが起動し、ネットワークが構成され、DNS レコードが作成されます。しかし、terraform apply の内部では具体的に何が起きているのでしょうか。また、このステップで問題を起こさないためにはどうすればよいのでしょうか。

保存したプランファイルを使うべき理由

terraform apply を安全に実行する方法は、事前に生成したプランファイルを適用することです。terraform plan -out=plan.tfplan を実行した後、terraform apply plan.tfplan を実行します。これにより、レビューした内容と完全に同じ変更が適用されることが保証されます。

以下が、プランファイルを生成して適用する正確なコマンドシーケンスです:

terraform plan -out=plan.tfplan
terraform apply plan.tfplan

プランファイルなしで terraform apply を実行するリスクは、目に見えにくいですが現実に存在します。terraform plan を実行してから terraform apply を実行するまでの間に、チームの他のメンバーが同じ設定に変更をマージする可能性があります。あるいは、気づかないうちに変数ファイルを変更してしまうかもしれません。保存されたプランなしで terraform apply を実行すると、Terraform はその時点の設定を使ってプランを再実行します。その結果は、10分前にレビューした内容と異なる可能性があります。

本番環境では、常に保存されたプランファイルを使用してください。これにより監査証跡が作成され、「これが承認された内容です」と plan.tfplan を指し示すことができます。変更が小さく頻繁に行われるステージング環境や開発環境では、プランファイルなしで terraform apply を実行する利便性が許容される場合もあります。ただし、そのトレードオフを理解しておく必要があります。

Apply プロセス中に何が起きているか

terraform apply が実行されるとき、単に「設定を適用」するわけではありません。変更が必要なリソースごとに、プロバイダーの API と通信します。aws_instance を作成する場合、Terraform は AWS EC2 API を呼び出してインスタンスを起動します。google_storage_bucket を更新する場合、Google Cloud Storage API を呼び出します。

各 API 呼び出しには、ミリ秒から数分までの時間がかかります。仮想マシンの作成には通常30秒から数分かかります。マネージド Kubernetes クラスターのプロビジョニングには10〜15分かかることもあります。Terraform はターミナルに進捗を表示しますが、個々のリソースに対するプログレスバーは表示されません。次のようなメッセージが表示されます:

以下のフローチャートは、apply フローと成功・失敗時の分岐結果をまとめたものです:

flowchart TD A[terraform apply 開始] --> B[プランファイルを読み込むか再プラン] B --> C[ステートロックを取得] C --> D[各リソースに対して:プロバイダーAPIを呼び出し] D --> E{すべてのリソースが作成/更新されたか?} E -- Yes --> F[完全なステートをステートファイルに書き込み] F --> G[ステートロックを解放] G --> H[Apply成功] E -- No --> I[作成済みリソースの部分ステートを保存] I --> J[ステートロックを解放] J --> K[手動介入が必要] K --> L[問題を修正して再適用] K --> M[手動で破棄するか terraform destroy を使用]
aws_instance.app_server: Still creating... [10s elapsed]
aws_instance.app_server: Still creating... [20s elapsed]

この間、Terraform はステートロックを保持しています。現在の操作が完了するかタイムアウトするまで、チームの他のメンバーは terraform applyterraform plan を実行できません。これは、複数の人が同時に同じインフラを変更することを防ぐための意図的な設計です。

Apply 成功時に何が起きるか

すべてのリソースが正常に作成または更新された後、Terraform は現在のステートをステートファイルに書き込みます。このステートファイルには、各リソースの一意のID、すべての属性、およびリソース間の関係が記録されます。たとえば、EC2 インスタンスを作成してセキュリティグループをアタッチした場合、ステートファイルは aws_instance.app_serveraws_security_group.web_sg に関連付けられていることを認識します。

このステートファイルは、インフラの唯一の信頼できる情報源(シングルソースオブトゥルース)になります。次回 terraform plan を実行するとき、Terraform はライブのクラウドリソースではなく、ステートファイルと設定を比較します。これが、破損したステートファイルや欠落したステートファイルが多くの問題を引き起こす理由です。Terraform は参照点を失ってしまうのです。

Apply 失敗時に何が起きるか

Apply の失敗はよくあることなので、その対処方法を知っておくべきです。リソース作成が失敗する原因としては、以下のようなものがあります:

  • クォータ制限に達した(例:リージョン内の EC2 インスタンス数が多すぎる)
  • プロバイダーの認証情報が期限切れまたは無効
  • 既存のリソースとの競合(例:既に存在する DNS レコードを作成しようとした)
  • クラウドプロバイダーの障害またはスロットリング

障害が発生した場合、Terraform はすべてをロールバックしません。失敗したリソースをマークし、正常に作成されたリソースのステートを保存します。つまり、一部のリソースは存在し、一部は存在しないという部分的な状態になります。Terraform は障害発生前に作成されたリソースを自動的にクリーンアップしません。

たとえば、5つのリソースを作成していて4つ目が失敗した場合、最初の3つのリソースはクラウドアカウントに残ります。ステートファイルには、これら3つが作成されたと記録されます。次に何をすべきか判断する必要があります:

  • 問題を修正し(例:クォータ増加をリクエスト)、terraform apply を再実行する。Terraform は残りのリソースを作成しようと試みます。
  • 作成されたリソースを手動で破棄して最初からやり直す。
  • terraform destroy を使用してすべてをクリーンアップする。ただし、すべてのリソースを削除しても問題ないと確信している場合に限ります。

この部分ステートの動作は、本番環境以外でインフラ変更をテストすべき理由の一つです。本番環境での Apply 失敗は、手動介入が必要な不整合な状態を残す可能性があります。

Apply 実行前の実践的チェックリスト

重要な環境で terraform apply を実行する前に、以下のチェックを実施してください:

  • 予期しない変更、特に削除がないかプラン出力をレビューしましたか?
  • ステートファイルはバックアップされているか、バージョニング対応のリモートバックエンドに保存されていますか?
  • 問題が発生した場合にロールバックするための認証情報はありますか?
  • メンテナンスウィンドウやチームへの通知は設定されていますか?
  • 本番環境の場合:保存されたプランファイル(terraform apply plan.tfplan)を使用しましたか?
  • データベース変更の場合:Terraform とは別にマイグレーションのロールバック計画はありますか?

具体的なポイント

terraform apply を実行することは、設定が実際のインフラになる瞬間です。本番環境では保存されたプランファイルを使用して、レビューした内容と完全に同じ変更が適用されることを保証してください。障害が発生すると自動ロールバックではなく部分ステートが残ることを理解してください。そして、ステートファイルがどこにあり、どのように復元するかを常に把握しておいてください。ステートファイルがなければ、Terraform はインフラを管理できなくなります。