ローカル状態を S3 に移行する

AWSBeginner
オンラインで実践に進む

はじめに

保守担当者は、稼働中のスタックのリソース対応付けを共有の場所に保存する必要があります。既存のレポートを保持しながら、ローカル状態を独立したバージョン管理付きの S3 バックエンドに移行し、状態の履歴と、バックエンドが独自に持つライフサイクルを観察します。

Terraform の状態、インポート、保存済みプラン、S3 オブジェクトのバージョンを理解していることを前提とします。この実験のすべてのリソースは、この新しい環境に用意されています。以前の状態や個人の AWS アカウントは不要です。

認定試験との関連

認定資格 試験のタスク 演習内容
CloudOps Engineer – Associate (SOA-C03) Task 3.1, Skill 3.1.6 稼働中のリソースを保持しながら、確認済みの設定と状態の変更を通じてインフラストラクチャを保守する、Terraform の基礎演習です。

実験の概要

概念図:保守作業で、設定、状態、既存のレポート用ストレージの関係を保持します。

ローカル状態とバックエンドの境界を確認する

このステップでは、業務用バケットと、それとは別の状態の保存先を識別します。用意されたレポート用ルートは、すでに migration-daily-reports を管理しています。そのローカル状態は、財務チームの参照用ストレージとは独立しています。バージョン管理された maintenance-team-state バケットはプラットフォームチームが準備したもので、このルートが使用し始める前から存在しています。

cd /home/labex/project/state-migration
terraform state list
terraform state show aws_s3_bucket.reports

リモートのバケット ID が migration-daily-reports であることを確認します。バックエンドはリソースの対応付けを保存するもので、AWS リソースを作成して読み取るプロバイダーとは別のものです。この環境では、プロバイダーとバックエンドの接続設定が個別に準備されています。

状態の保存場所を変更する前に、非公開のローカルバックアップを保存します。リダイレクト(>)は状態の JSON をファイルに書き込みます。状態やプランを公開のソース管理にコミットしてはいけません。

terraform state pull > local-before-migration.json
chmod 600 local-before-migration.json

バックエンドのバージョニングと、初期状態でオブジェクト一覧が空であることを確認します。

aws s3api \
  get-bucket-versioning \
  --bucket maintenance-team-state

Status: Enabled と表示されるはずです。

aws s3api \
  list-objects-v2 \
  --bucket maintenance-team-state

状態オブジェクトはまだ存在しないはずです。空の保存先を選ぶことは重要です。別の環境がすでに使っているキーに移行すると、その環境の管理記録を上書きするおそれがあります。migration-finance-reference には手を加えないでください。

既存の対応付けを意図した S3 キーに移行する

このステップでは、リモートバックエンドを設定し、既存のローカルリソースの対応付けを空の保存先にコピーします。キーはバックエンドのバケット内にある状態オブジェクトの名前です。特定の 1 つの環境用に選択します。

S3 バックエンドの部分的な宣言を書き込みます。接続設定は別途用意されており、その次のファイルで使用するバケットとキーを指定します。

cat > backend.tf <<'HCL'
terraform {
  backend "s3" {}
}
HCL

環境固有のバックエンド設定を作成します。use_lockfile = true は、今後の書き込みに対して Terraform 標準の S3 ロックファイルを有効にします。

cat > reports.s3.tfbackend <<'HCL'
bucket       = "maintenance-team-state"
key          = "reports/production.tfstate"
region       = "us-east-1"
use_lockfile = true
HCL

-migrate-state は、既存の対応付けを新しいバックエンドに移すよう Terraform に指示します。Terraform は既存の状態をコピーするかを尋ね、printf のパイプラインが回答 yes を渡します。この実験の保存先キーが空だったことを確認してから実行してください。

printf 'yes\n' | terraform init \
  -backend-config=backend-connection.hcl \
  -backend-config=reports.s3.tfbackend \
  -migrate-state

S3 バックエンドの設定が成功し、初期化が完了するはずです。既存の別環境に切り替える手段として移行を使ってはいけません。既存の状態の選択は別の操作であり、このコースの後の実験で扱います。

新しい保存場所から対応付けを確認します。

terraform state show aws_s3_bucket.reports

リソース ID は引き続き migration-daily-reports でなければなりません。S3 に実際の状態オブジェクトが保存されたことを確認します。

aws s3api \
  head-object \
  --bucket maintenance-team-state \
  --key reports/production.tfstate

ETag と VersionId により、保存された状態オブジェクトを確認できます。このメタデータだけでは十分ではありません。バックグラウンドチェックではリソースの対応付けも読み取り、既存レポートの ID とバイト列を比較します。

terraform plan

No changes と表示されるはずです。状態の移行によって業務用バケットが再作成されてはいけません。

リモート状態の新しいバージョンを観察する

このステップでは、確認済みの設定更新を 1 つ行い、その結果生まれる状態の履歴を観察します。バージョニングは以前の状態オブジェクトを保持します。この実験では履歴を観察し、破損した状態の復元は行いません。

バケット名、所有者、削除時の設定を変更せずに、リビジョンタグを追加します。

cat > main.tf <<'HCL'
resource "aws_s3_bucket" "reports" {
  bucket        = "migration-daily-reports"
  force_destroy = false
  tags = { Owner = "reporting", Revision = "two" }
}
HCL

プランを保存して確認します。

terraform plan -out=revision.tfplan

0 to add, 1 to change, 0 to destroy と表示されるはずです。この既存リソースをそのまま更新する操作だけを適用します。

terraform apply revision.tfplan

バックエンドのオブジェクトのバージョンを確認します。

aws s3api \
  list-object-versions \
  --bucket maintenance-team-state \
  --prefix reports/production.tfstate

移行と更新の後には、状態のバージョンが少なくとも 2 つ存在するはずです。これらは管理の履歴を表し、もう一方のバケットにある業務レポートのバージョンとは異なります。

aws s3 \
  cp s3://migration-daily-reports/report.txt -

レポートは Daily sales: 120 orders のままです。AWS View には、業務用、財務チームの参照用、バックエンドがそれぞれ別のバケットとして表示されます。状態ファイルには機密値が含まれる場合があるので、この演習に必要なメタデータだけを確認してください。

terraform plan

No changes と表示されるはずです。独立したクリーンアップ段階を始める前に、この正常な状態を検証してください。

バックエンドを保持して業務リソースを削除する

このステップでは、機能とデータ保持のチェックを通過した後で、この使い捨ての業務スタックを廃止します。プラットフォームチームのバックエンドと、独立した財務チームの参照用ストレージは、スタックの削除対象外です。

force_destroy = false は、Terraform がバージョン管理されたレポート用バケットの中身を黙って消すことを防ぎます。この実験のレポートを削除する前に、元のレポートバージョンを明確に識別してください。コマンド置換で ID を保存し、この機密ではない識別子を表示します。

VERSION_ID=$(aws s3api \
  head-object \
  --bucket migration-daily-reports \
  --key report.txt \
  --query VersionId \
  --output text)
echo "$VERSION_ID"

識別したその使い捨てのバージョンを削除し、その後で業務リソースを削除します。これらのコマンドは、前のステップで保持を確認した後に限り、意図的にレポートの提供を終了します。

aws s3api \
  delete-object \
  --bucket migration-daily-reports \
  --key report.txt \
  --version-id "$VERSION_ID"
terraform destroy -auto-approve

-auto-approve は確認プロンプトを省略します。ここでは、直前に確認した単一の使い捨て業務用バケットにだけ使用してください。1 destroyed と表示されるはずです。

その管理記録が引き続きバックエンドに存在することを確認します。

aws s3api \
  head-object \
  --bucket maintenance-team-state \
  --key reports/production.tfstate

バックエンドは残り、管理対象の業務リソースがない状態を保持しています。財務チームの参照用ストレージも引き続き利用できなければなりません。スタックを削除しても、そのバックエンドが使うストレージは削除されません。所有者のためにバックエンドをそのまま保持してください。通常の apply をもう一度実行すると、設定が要求する業務用バケットを再作成してしまうため、実行しないでください。

バックエンド設定と標準のロックファイルについては、S3 バックエンドのドキュメントを参照してください。

まとめ

プロバイダーとバックエンドの役割を区別し、既存の対応付けをバックアップして S3 に移行し、状態のバージョンを観察して、独立して所有されるバックエンドを削除せずに業務スタックを削除しました。