非公開のレポートストアをパラメーター化する

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

はじめに

チームには、内容の異なる開発用とプレビュー用のレポートストアが必要です。1 つの設定を再利用し、バケットからオブジェクトへの参照をたどり、独立した 2 つのルートがそれぞれ異なる AWS リソースを管理することを確かめます。

最初の AWS Terraform 実験と、変数や出力についての既存の知識を基に進めます。ツール、アクセス設定、プロバイダーの接続は準備済みです。以前の VM のリソースは再利用しません。

認定試験との関連

認定資格 試験のタスク 演習内容
Cloud Practitioner (CLF-C02) Task 3.1 再現可能なインフラストラクチャ定義と、運用時のリソース照会を使用します。
Developer – Associate (DVA-C02) Task 3.3, Skill 3.3.4 インフラストラクチャ定義をデプロイする基礎演習です。
DevOps Engineer – Professional (DOP-C02) Task 2.1 IaC 定義を通じてリソースを管理する基礎演習です。

この実験で実際に扱うリソースと、保持する対象の境界を示す概念図。

開発用ストアをデプロイする

このステップでは、入力変数とリソース参照を使って、1 つの設定から開発用のレポートストアを作成します。

準備済みの 2 つのルート、report-dev と report-preview は、プロバイダーの接続ファイル以外は空の状態で始まります。それぞれのルートが独自のローカル状態を保持します。これは、単一のルートで入力を変更することとは異なります。単一のルートは、そのルートの状態にすでに記録されているリソースを引き続き管理します。

開発用ルートに移動し、リソースのテンプレートを作成します。environment と report は文字列の入力変数です。${var.environment} は、環境名をバケット名に挿入します。オブジェクトの bucket 引数はバケットリソースの ID を参照するため、Terraform は依存関係を認識してバケットを先に作成できます。content_type は、読み取り側がバイト列をどう解釈するかを示します。

cd /home/labex/project/report-dev
cat > main.tf <<'EOF'
variable "environment" { type = string }
variable "report" { type = string }

resource "aws_s3_bucket" "reports" {
  bucket = "terraform-reports-${var.environment}"
  tags = {
    Project     = "TerraformReports"
    Environment = var.environment
  }
}

resource "aws_s3_object" "report" {
  bucket       = aws_s3_bucket.reports.id
  key          = "reports/current.csv"
  content      = var.report
  content_type = "text/csv"
}

output "bucket_name" { value = aws_s3_bucket.reports.id }
output "report_key" { value = aws_s3_object.report.key }
EOF

この環境用の変数ファイルを作成します。エスケープシーケンス \n は、レポート文字列内の改行を表します。値を分離しておくことで、同じリソーステンプレートを再利用できます。

cat > dev.tfvars <<'EOF'
environment = "dev"
report      = "orders,12\n"
EOF

このルートを初期化し、検証して、プランを確認します。-var-file は値のファイルを選択するものであり、別の状態を選択するものではありません。

terraform init
terraform validate
terraform plan -var-file=dev.tfvars

バケットとそのレポートオブジェクトの 2 つのリソースが追加されるはずです。同じ入力を使って適用し、確認を求められたら yes を入力します。

terraform apply -var-file=dev.tfvars

出力は、バケットとオブジェクトキーを識別します。コマンドの出力を取り込む $(...) を使って、これらの値を保存して表示します。-raw は、Terraform の引用符を付けずに文字列の出力を表示します。

BUCKET=$(terraform output -raw bucket_name)
echo "$BUCKET"
KEY=$(terraform output -raw report_key)
echo "$KEY"

出力や状態のエントリーだけをデータの証拠とせず、AWS を通じて実際に保存されたレポートを読み取ります。レスポンスには ContentType: text/csv が含まれ、保存先のファイルには実際のバイト列が格納されます。

aws s3api \
  get-object \
  --bucket "$BUCKET" \
  --key "$KEY" \
  dev-downloaded.csv
cat dev-downloaded.csv

orders,12 と表示されるはずです。AWS View でも terraform-reports-dev 内の reports/current.csv を展開できます。別に用意されたチームの参照用レポートは変更せずに残してください。 デプロイ後の AWS View:作成したストレージが、保持された参照用レポートの隣に表示されています。

独立した状態でテンプレートを再利用する

このステップでは、開発用ストアを保持しながら、同じテンプレートをプレビュー用の入力でデプロイします。

準備済みのプレビュー用ルートに、リソースのテンプレートだけをコピーします。この演習では、準備済みの各ルートを個別に初期化するため、コピーするのは main.tf だけです。別の環境を作るために、terraform.tfstate や初期化済みの .terraform/ ディレクトリを複製してはいけません。元のリソースやバックエンドへの対応付けが引き継がれる場合があります。依存関係のロックファイル .terraform.lock.hcl は別のものです。プロバイダーのバージョンとチェックサムを記録し、設定と一緒に共有したりコミットしたりでき、環境のリソースの対応付けは含みません。プレビュー用ルートには、すでに独自のプロバイダー接続ファイルがあります。

cp /home/labex/project/report-dev/main.tf /home/labex/project/report-preview/main.tf
cd /home/labex/project/report-preview
cat > preview.tfvars <<'EOF'
environment = "preview"
report      = "orders,25\n"
EOF

このルートを初期化し、プレビュー用のプランを確認します。

terraform init
terraform plan -var-file=preview.tfvars

再び 2 つの追加が提案され、バケット名は terraform-reports-preview になるはずです。予期しない開発用バケットの削除が提案された場合、誤った状態を再利用したことを示します。適用し、yes を入力します。

terraform apply -var-file=preview.tfvars

プレビュー用の出力とレポートを読み取ります。環境の入力は名前とタグを変更し、レポートの入力は実際に保存されるバイト列を変更します。

BUCKET=$(terraform output -raw bucket_name)
echo "$BUCKET"
aws s3api \
  get-object \
  --bucket "$BUCKET" \
  --key reports/current.csv \
  preview-downloaded.csv
cat preview-downloaded.csv

orders,25 と表示されるはずです。Terraform のグローバルオプション -chdir を使い、両方のルートの出力と状態の一覧を比較します。このオプションはシェルのディレクトリを変更せずに、指定したルートでコマンドを実行します。

terraform -chdir=/home/labex/project/report-dev output bucket_name
terraform -chdir=/home/labex/project/report-dev state list
terraform -chdir=/home/labex/project/report-preview output bucket_name
terraform -chdir=/home/labex/project/report-preview state list

両方のルートに aws_s3_bucket.reports などのアドレスがありますが、それぞれ異なる AWS バケットに対応付けられています。開発用のデータがそのまま保持されていることを確認します。

aws s3api \
  get-object \
  --bucket terraform-reports-dev \
  --key reports/current.csv \
  dev-retained.csv
cat dev-retained.csv

orders,12 と表示されるはずです。これらは独立したローカル状態であり、ワークスペースや共有バックエンドではありません。変数ファイルの選択について詳しくは、Terraform の入力変数のドキュメントを参照してください。 AWS View に、独立して作成した両方のレポートストアが、保持されたチームの参照用レポートの隣に表示されています。

作成した両方のストアを削除する

このステップでは、チームの参照用レポートを削除せずに、各ルートのリソースを削除します。

削除時にも、各ルート固有の入力が必要です。開発用の削除プランを確認してから、削除を実行して yes を入力します。Terraform は依存関係を把握しているため、バケットより先にオブジェクトを削除します。

terraform -chdir=/home/labex/project/report-dev plan -destroy -var-file=dev.tfvars
terraform -chdir=/home/labex/project/report-dev destroy -var-file=dev.tfvars

次に、プレビュー用ルートのリソースだけを削除し、再び yes で確認します。

terraform -chdir=/home/labex/project/report-preview destroy -var-file=preview.tfvars

それぞれの削除で、2 つのリソースを削除したと表示されます。両方の対応付けが空になり、管理対象ではない参照用レポートが引き続き存在することを検証します。

terraform -chdir=/home/labex/project/report-dev state list
terraform -chdir=/home/labex/project/report-preview state list
aws s3api \
  list-buckets \
  --query 'Buckets[].Name'
aws s3api \
  head-object \
  --bucket team-reference-reports \
  --key keep.txt \
  --query ContentLength

参照用バケットだけが残ります。認証に成功して取得できた一覧は対象が存在しないことを証明しますが、アクセスやネットワークの失敗は証明になりません。最後のチェックが完了するまで、準備済みの認証情報を保持してください。

まとめ

2 つの変数ファイルでバケットとオブジェクトのテンプレートを再利用し、実際のレポートのバイト列と Content-Type を読み取り、各ルートの状態を独立して保持して、作成した 2 つの環境だけを削除しました。