はじめに
2 人の保守担当者が、同じ環境の作業コピーを持っています。実際に共有状態へ書き込むプロセス、その標準のロックによって拒否される競合するプラン、正常にロックが解放された後にもう一方のディレクトリから作業が成功する様子を観察します。
S3 のリモート状態と、通常の Terraform の plan/apply 操作の知識が必要です。この新しい環境には、初期化済みの両方の作業コピー、時間を制御した変更、レポート用ストレージ、財務チームの参照用ストレージが用意されています。以前の VM や個人の AWS アカウントは不要です。
認定試験との関連
| 認定資格 | 試験のタスク | 演習内容 |
|---|---|---|
| CloudOps Engineer – Associate (SOA-C03) | Task 3.1, Skill 3.1.6 | 稼働中のリソースを保持しながら、確認済みの設定と状態の変更を通じてインフラストラクチャを保守する、Terraform の基礎演習です。 |
実験の概要

同じ環境の 2 つのコピーを識別する
このステップでは、2 つの作業ディレクトリが意図的に同じ環境を管理していることを確認します。これらは、別々の dev と preview のデプロイではありません。両方のバックエンド設定が、coordination-team-state 内の reports/shared.tfstate を選択します。
cd /home/labex/project/shared-state-operators
cat operator-a/shared.s3.tfbackend
cat operator-b/shared.s3.tfbackend
両方とも use_lockfile = true を使用します。書き込み処理の実行中、Terraform はこの状態と同じ保存先に標準の S3 ロックオブジェクトを作成し、別の書き込みプロセスが競合するスナップショットに基づいて操作しないようにします。
terraform -chdir=operator-a state show aws_s3_bucket.reports
terraform -chdir=operator-b state show aws_s3_bucket.reports
どちらも coordinated-daily-reports を示します。実際のレポートを読み取り、財務チームの参照用ストレージは変更せずに残します。
aws s3 \
cp s3://coordinated-daily-reports/report.txt -
Daily sales: 120 orders と表示されるはずです。用意された、動作時間を制御する変更を確認します。
cat operator-a/pending-change.tf
この演習に限り、terraform_data リソースは local-exec を通じて作成処理を 30 秒間停止します。この停止によって、実際の書き込みプロセスのロックを観察できます。通常のリソース更新もロックを保持しますが、人工的な待機を本番デプロイに推奨しているわけではありません。この制御された状態変更は両方の設定に含まれていますが、まだ適用されていません。
実際の競合と正常な解放を観察する
このステップでは、実際の書き込み処理を 1 つ実行し、2 つ目のディレクトリから競合するプランを実行します。読むための中断で観察時間を消費しないよう、次のブロック全体を 1 つの操作として実行してください。
& は operator A をバックグラウンドで開始し、$! はそのプロセス ID を取得します。2 つ目のオペレーターのエラーを読みやすくするため、出力はログに送られます。回数を制限したループは、起動時間を固定で仮定する代わりに、実際の S3 ロックを待ちます。if 文により想定されたプランの失敗を確認でき、wait は書き込みプロセスの実際の完了ステータスを返します。1 つの Terminal から起動していても、これらは独立した 2 つの Terraform プロセスです。
terraform -chdir=operator-a apply -auto-approve > /tmp/operator-a.log 2>&1 &
WRITER_PID=$!
echo "$WRITER_PID"
for attempt in $(seq 1 60); do
if aws s3api head-object \
--bucket coordination-team-state \
--key reports/shared.tfstate.tflock > /dev/null 2>&1; then
break
fi
sleep 1
done
aws s3api get-object \
--bucket coordination-team-state \
--key reports/shared.tfstate.tflock \
/tmp/current-lock.json
cat /tmp/current-lock.json
if terraform -chdir=operator-b plan -lock-timeout=0s; then
echo 'Unexpected: the competing plan acquired the lock.'
false
else
PLAN_EXIT=$?
echo "$PLAN_EXIT"
fi
wait "$WRITER_PID"
cat /tmp/operator-a.log
競合するプランは、Error acquiring the state lock とともに終了コード 1 で終了しなければなりません。認証や接続のエラーは、競合を示すものではありません。ロック情報は実際の書き込みプロセスのものです。ロックと同じ名前のファイルをアップロードしても、書き込みプロセス間の調整を確立したことにはなりません。
operator A は、制御された作成処理を正常に完了し、通常の手順でロックを解放するはずです。2 つ目のオペレーターを先に進めるために、ロックを無効化したり、活動中の書き込みプロセスのロックを削除したり、force-unlock を使ったりしてはいけません。AWS View では、その間もレポートストアを利用できます。ロックが調整するのは管理操作であり、レポートを読み取るアクセスではありません。
解放後にもう一方の作業コピーから続行する
このステップでは、書き込みプロセスが終了した後、operator B が通常どおりバックエンドを取得できるようにします。2 つ目の作業コピーは、リソースの別のコピーを独立して作成するのではなく、更新された共有状態を読み取るはずです。
terraform -chdir=operator-b plan -lock-timeout=5s
No changes と表示されるはずです。書き込み中にブロックされたのと同じコマンドが、今度は通常どおりロックを取得して解放できます。
両方のディレクトリから、完了後の状態を確認します。
terraform -chdir=operator-a state list
terraform -chdir=operator-b state list
どちらにも aws_s3_bucket.reports と terraform_data.coordination が表示されます。これは同じ環境と共有の管理記録であり、2 つのデプロイではありません。
aws s3 \
cp s3://coordinated-daily-reports/report.txt -
元の文面を引き続き読み取れます。状態のバージョン履歴を確認します。
aws s3api \
list-object-versions \
--bucket coordination-team-state \
--prefix reports/shared.tfstate
実際の状態には履歴があり、現在のオブジェクト一覧に活動中の .tflock が残っていてはいけません。過去のロックバージョンや削除マーカーは、活動中の書き込みプロセスのロックではありません。
terraform -chdir=operator-a plan
こちらでも No changes と表示されるはずです。バックグラウンドチェックは、実際の Terraform プロセス間の競合と手動で用意されたロックを区別し、元のレポートバージョン、正常な解放、その後のアクセス成功を検証します。共有ストレージとバックエンドは、所有者のために保持してください。
まとめ
同じ環境の 2 つの作業コピーと、別々の環境を区別し、実際の標準ロックの競合を観察して、活動中のロックを削除することなく、書き込みプロセスによる正常な解放後に安全に作業を続行しました。



