(1/2)Terraformで作成してprd環境をstgとdevに拡張するお話
今までの記事
- TerraformでS3,CloudFront環境をアカウント跨ぎの移行
- (2/2)静的webサイトをS3にデプロイ!claude codeとGithub Actionsを用いて自動デプロイ!
- (1/2)静的webサイトをS3にデプロイ!claude codeとGithub Actionsを用いて自動デプロイ!
目次
現在
claude code
Plan モード
微妙
/infraを深く考えて調査し、下記の情報を適切にAWS構成図を.drawioファイルで作成してください。
・アイコン図形をAWS 2025を使用する
・アカウント、リージョンなどはAWS 2025 aws/groupsを使用する
・AWS 2025から使用したものは色はデフォルトをする
・リージョンはアカウント内に別配置
・角は直角にする
・リソース間の通信の流れ、データの流れを表す
・AWSアカウントや、リージョンなどの関係性を表す
・Terraformで使ってる
・Terraformデプロイの関係性表す(ユーザーが居てterraform実行踏み台アカウントがあって、そこから他のアカウントを操作してます的な)
・軽い説明を記載する(日本語で)
・カラーパレット:本番(#FF6B6B)、ステージング(#FFA500)、共通インフラ(#4A90E2)、開発(#95E77E)
・フォント:AWS標準フォントまたはArial
・背景色は透明度85%で設定
・矢印を装飾してください。
・Terraformデプロイフロー:紫の二重線矢印
インフラ構築お勉強
作りたいもの
前回ブログで作成した、prd環境と同じ環境をstgとdevで作成したい
ディレクトリ構造
tano1:infra tano$ tree
.
├── aws-architecture-0603game.drawio
├── backend-setup
│ ├── environments
│ │ ├── dev
│ │ │ ├── backend.tf
│ │ │ ├── main.tf
│ │ │ ├── outputs.tf
│ │ │ ├── provider.tf
│ │ │ ├── terraform.tf
│ │ │ ├── terraform.tfvars
│ │ │ └── variables.tf
│ │ ├── prd
│ │ │ ├── backend.tf
│ │ │ ├── main.tf
│ │ │ ├── outputs.tf
│ │ │ ├── provider.tf
│ │ │ ├── terraform.tf
│ │ │ ├── terraform.tfstate
│ │ │ ├── terraform.tfvars
│ │ │ └── variables.tf
│ │ └── stg
│ │ ├── backend.tf
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── provider.tf
│ │ ├── terraform.tf
│ │ ├── terraform.tfstate
│ │ ├── terraform.tfvars
│ │ └── variables.tf
│ └── modules
│ └── backend
│ ├── main.tf
│ ├── outputs.tf
│ └── variables.tf
├── modules
│ ├── acm-certificate
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── versions.tf
│ ├── cloudfront-oac
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ ├── route53-records
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── versions.tf
│ └── s3-private-bucket
│ ├── main.tf
│ ├── outputs.tf
│ └── variables.tf
└── static-website
└── environments
├── dev
│ ├── backend.tf
│ ├── locals.tf
│ ├── main.tf
│ ├── outputs.tf
│ ├── providers.tf
│ ├── terraform.tf
│ ├── terraform.tfvars
│ └── variables.tf
├── prd
│ ├── backend.tf
│ ├── locals.tf
│ ├── main.tf
│ ├── outputs.tf
│ ├── providers.tf
│ ├── terraform.tf
│ ├── terraform.tfvars
│ └── variables.tf
└── stg
├── backend.tf
├── locals.tf
├── main.tf
├── outputs.tf
├── providers.tf
├── terraform.tf
├── terraform.tfvars
└── variables.tf
18 directories, 64 files
tano1:infra tano$
2025/08/23~ stg環境用のバックエンドを構築
フェーズ1:IAMロールの準備
stgアカウントの実行ロールの作成
stgアカウント側で、Terraform実行踏み台アカウントが使うロールを作成する。
信頼されたエンティティはローカルのTerraformが使う、Terraform実行踏み台アカウントのロールを指定する。
許可ポリシーはAdministratorAccess。ほんとは用途で絞った方が良い。
Terraform実行踏み台アカウントでのAssumeRole権限の追加
IAM Identity Centerで作成したロールなので、コンソールから許可ポリシーを編集出来ない。
なので、IAM Identity Centerの管理コンソールから編集を行う。
許可セット→インラインポリシー
インラインポリシーに上記で作成したロールのARMをリソースとして記載する。
信頼されたエンティティ: 誰がこのロールになって良いか
インラインポリシー: このロールは何をどのリソースに出来るか。AssumeRoleを記載のARNに対して出来る。
フェーズ2:Backend-setup/stg用のTerraformコードの複製と修正
git操作(ファイル編集始まり)
これからファイルの編集を行うので、何か間違えた時にある地点に戻せるようにgitのブランチを切ってファイルの編集を行う
$ git status #現在のgit状況を確認
$ git branch #現在のブランチの状況を確認
$ git checkout -b chore/terraform-backend-setup-stg-clone-adjust #ブランチの作成
Backend-setup/prdディレクトリのコピー
モジュールを作成しているので、モジュールの方はコピー要らない。
書き換えが必要な箇所を書き換えて行く
$ cp -r infra/backend-setup/environments/prd infra/backend-setup/environments/stg
コピー後削除するファイル、ディレクトリ
terraform.tfstate
: Terraformが管理するリソースの現在の状態を記録するところ。plan``apply
の時に使う。コピー後、前の環境が残ってるので削除。
.terraform/
: terraform init
の成果物キャッシュ置き場。プロバイダの実行バイナリ、取得済みモジュール、バックエンド初期情報などなどが入る。コピー後、前の環境の残骸が残ってるので削除。
.terraform.lock.hcl
: プロバイダの厳密なバージョンとチェックサムを固定するロックファイル。チームや環境ごとに同じバージョンを強制できる。同じバージョンを強制したいなら残す。
下記生成AI(Claude code)
🎯 3つの関係性を図解
📊 環境コピー時の扱い方まとめ
ファイル/ディレクトリ | 何? | コピー時の扱い | 理由 |
---|---|---|---|
terraform.tfstate | インフラの状態記録 | 必ず削除 🔴 | 別環境の状態が混ざる |
.terraform/ | 作業用ディレクトリ | 必ず削除 🔴 | 接続先情報が残る |
.terraform.lock.hcl | バージョン固定 | 残してOK ✅ | 同じバージョンを使いたい |
$ rm -f terraform.tfstate*
$ rm -rf .terraform/
Backend-setup/stgディレクトリ内のファイル修正
backend-setup/stg/terraform.tfvars
環境固有の値をstg用に変更する。アカウントIDとタグのEnvironment
。
tano1:stg tano$ cat terraform.tfvars
project_name = "0603game"
environment = "stg"
# stgアカウントのID
account_id = "<stgアカウントのID>"
common_tags = {
ManagedBy = "Terraform"
Project = "0603game"
Environment = "stg"
}tano1:stg tano$
backend-setup/stg/provider.tf
使用するロールのARNを書き換え。
}tano1:stg tano$ cat provider.tf
provider "aws" {
region = "ap-northeast-1"
assume_role {
role_arn = "<stgで作成したロールのARN>"
session_name = "tf-session-0603game-stg-backend"
}
}tano1:stg tano$
backend-setup/stg/backend.tf
記載をまずはローカル指定に書き換え
}tano1:stg tano$ cat backend.tf
terraform {
backend "local" {
path = "terraform.tfstate"
}
}tano1:stg tano$
フェーズ3:stgバックエンドの実行
terraform init
.terraform
を削除しているし、基本行う。
terraform plan
問題無し
terraform apply
問題無し
ローカルバックエンドからリモートバックエンドへ移行
backend-setup/stg/backend.tf書き換え
terraform {
backend "s3" {
# applyで作成されたstg用のバケット名
bucket = "<applyで作成されたstg用のバケット名>"
# stg用のStateファイルのパス
key = "backend-setup/stg/terraform.tfstate"
region = "ap-northeast-1"
# applyで作成されたstg用のテーブル名
dynamodb_table = "<applyで作成されたstg用のテーブル名>"
encrypt = true
# stg用のロールARN
role_arn = "<stg用のロールARN>"
}
}
再初期化とStateの移行
内部で何が起きるか。
設定の読み込み比較、新バックエンドの初期化、stateのコピー。
$ terraform init -migrate-state
git操作(ファイル編集終わり)
一区切りのファイル編集が終わったので、その編集した変更をリモートのメインブランチへ反映させるため操作を行う
$ git status #現在のgit状況を確認
$ git branch #現在のブランチの状況を確認
$ cd <プロジェクトのルートディレクトリ>
$ git add . #gitの変更をステージングにあげる
$ git status #現在のgit状況を確認
$ git commit -m "terraform-backend-setup-stg-clone-adjust" #gitの変更をローカルブランチへ適用させる
$ git push origin chore/terraform-backend-setup-stg-clone-adjust #変更をリモートのブランチへ適用させる
# ここからGithubなどのリモート側の操作
# リモートでmainブランチとchore/terraform-backend-setup-stg-clone-adjustブランチがあるので、変更をmainブランチへ反映させるためにプルリクエストを行う
# プルリクエストを受けた側(自学習なら自分)は変更差分を見て問題無いか確認して、問題なければマージしてchore/terraform-backend-setup-stg-clone-adjustブランチを削除する
# Githubなどのリモート側の操作はここまで
$ git branch #現在のブランチの状況を確認
$ git checkout main #最新のブランチに変更。リモートではもうブランチが削除されてる
$ git branch #現在のブランチの状況を確認
$ git pull origin main # リモートで反映させた変更が、ローカルにも反映される
$ git branch -d chore/terraform-backend-setup-stg-clone-adjust #不要になったブランチを削除する
$ git branch #現在のブランチの状況を確認
stg環境用のウェブサイトを構築
フェーズ1:IAMロールの準備(追加設定)
DNS管理アカウントでの作業ロール
これは何もしなくていい。
prdの時にTerraform実行踏み台アカウントのロールを、DNS管理アカウントの信頼ポリシーに記載しているためstgで設定することはない。
フェーズ2:stg用へTerraformコードの複製と修正
git操作(ファイル編集始まり)フェーズ2:stg用へTerraformコードの複製と修正
これからファイルの編集を行うので、何か間違えた時にある地点に戻せるようにgitのブランチを切ってファイルの編集を行う
$ git status #現在のgit状況を確認
$ git branch #現在のブランチの状況を確認
$ git checkout -b feat/build-stg-website #ブランチの作成
static-website/prdのコピー
モジュールの方はコピーが要らない
これがTerraformのモジュールであることの良さ。
コピーして少し修正するだけで、スケール出来る。
$ cp -r infra/static-website/environments/prd infra/static-website/environments/stg
コピー後削除するファイル、ディレクトリ
コピー直後は削除が必要なファイルがある。それはprd環境の設定をそのままこっちで実行してしまうと破壊が起こる。
tfstate
ファイルが無い理由は今回prd環境ではBackend-setupでバックエンドリソースを作成して、それをprd環境のbackend.tfへ記載していて、それをコピーしてるから無い。
$ rm -rf .terraform/
static-website/stgディレクトリ内のファイル修正
static-website/stg/terraform.tfvars
tano1:stg tano$ cat terraform.tfvars
project = "0603game"
environment = "stg"
domain_name = "tanoyuusuke.com"
aws_account_id = "<stgアカウントID>"
common_tags = {
Project = "0603game"
Environment = "stg"
ManagedBy = "Terraform"
Owner = "tano"
}tano1:stg tano$
static-website/stg/providers.tf
tano1:stg tano$ cat providers.tf
# デフォルトプロバイダ
provider "aws" {
region = "ap-northeast-1"
assume_role {
role_arn = "<stgTerraform実行ロールARN>" # 変更
session_name = "tf-session-static-website-stg" # 変更
}
}
# ACM証明書用のプロバイダ
provider "aws" {
alias = "us-east-1"
region = "us-east-1"
assume_role {
role_arn = "<stgTerraform実行ロールARN>" # 変更
session_name = "tf-session-static-website-stg-acm" # 変更
}
}
# DNS操作用のプロバイダ (これは変更なし)
provider "aws" {
alias = "dns_master"
region = "ap-northeast-1"
assume_role {
role_arn = "<DNS管理アカウント実行ロールARN>"
session_name = "tf-session-dns-cross-account-stg" # session_nameだけ変更
}
}tano1:stg tano$
static-website/stg/backend.tf
}tano1:stg tano$ cat backend.tf
terraform {
backend "s3" {
# 作成したstg用のS3バケット
bucket = "<作成したstg用のS3バケット>" # 変更
# stgスタック専用のStateファイルのパス
key = "static-website/stg/terraform.tfstate" # 変更
region = "ap-northeast-1"
dynamodb_table = "<作成したstg用のDynamoDBバケット>" # 変更
encrypt = true
role_arn = "<stgのTerraform実行ロール>" # 変更
}
}tano1:stg tano$
git操作(ファイル編集終わり)フェーズ2:stg用へTerraformコードの複製と修正
これからファイルの編集を行うので、何か間違えた時にある地点に戻せるようにgitのブランチを切ってファイルの編集を行う
git操作(ファイル編集終わり)フェーズ2:stg用へTerraformコードの複製と修正
tano1:0603game tano$ git branch # 現在のブランチ状況を確認
* main
tano1:0603game tano$ git checkout main # 念の為mainに移動コマンド
Already on 'main'
Your branch is up to date with 'origin/main'.
tano1:0603game tano$ git pull # 念の為git pull
Already up to date. # 変更無し
tano1:0603game tano$ git checkout -b feat/build-stg-website # ローカルでブランチを作成する
Switched to a new branch 'feat/build-stg-website'
tano1:0603game tano$ git branch # 現在のブランチ確認。作成したブランチに今居てるのを確認
* feat/build-stg-website
main
tano1:0603game tano$
# ここからGithubなどのリモート側の操作
# リモートでmainブランチとfeature/terraform-backend-setupブランチがあるので、変更をmainブランチへ反映させるためにプルリクエストを行う
# プルリクエストを受けた側(自学習なら自分)は変更差分を見て問題無いか確認して、問題なければマージしてfeature/terraform-backend-setupブランチを削除する
# Githubなどのリモート側の操作はここまで
tano1:0603game tano$ git status # まず確認
On branch feat/build-stg-website
Your branch is up to date with 'origin/feat/build-stg-website'.
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: infra/aws-architecture-diagram.yaml
Untracked files:
(use "git add <file>..." to include in what will be committed)
infra/aws-architecture-diagram.drawio
infra/static-website/environments/prd/locals.tf
infra/static-website/environments/stg/
no changes added to commit (use "git add" and/or "git commit -a")
tano1:0603game tano$ git add . # ステージングされてないのでadd
tano1:0603game tano$ git status # そしてもう一度確認
On branch feat/build-stg-website
Your branch is up to date with 'origin/feat/build-stg-website'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: infra/aws-architecture-diagram.drawio
deleted: infra/aws-architecture-diagram.yaml
new file: infra/static-website/environments/prd/locals.tf
new file: infra/static-website/environments/stg/.terraform.lock.hcl
new file: infra/static-website/environments/stg/backend.tf
new file: infra/static-website/environments/stg/main.tf
new file: infra/static-website/environments/stg/outputs.tf
new file: infra/static-website/environments/stg/providers.tf
new file: infra/static-website/environments/stg/terraform.tf
new file: infra/static-website/environments/stg/terraform.tfvars
new file: infra/static-website/environments/stg/variables.tf
tano1:0603game tano$ git commit -m "build-stg-website" # ステージングされてるので、ローカルブランチに変更履歴を反映
[feat/build-stg-website 85f6d89] build-stg-website
11 files changed, 507 insertions(+), 112 deletions(-)
create mode 100644 infra/aws-architecture-diagram.drawio
delete mode 100644 infra/aws-architecture-diagram.yaml
create mode 100644 infra/static-website/environments/prd/locals.tf
create mode 100644 infra/static-website/environments/stg/.terraform.lock.hcl
create mode 100644 infra/static-website/environments/stg/backend.tf
create mode 100644 infra/static-website/environments/stg/main.tf
create mode 100644 infra/static-website/environments/stg/outputs.tf
create mode 100644 infra/static-website/environments/stg/providers.tf
create mode 100644 infra/static-website/environments/stg/terraform.tf
create mode 100644 infra/static-website/environments/stg/terraform.tfvars
create mode 100644 infra/static-website/environments/stg/variables.tf
tano1:0603game tano$ git status # もう一度確認
On branch feat/build-stg-website
Your branch is ahead of 'origin/feat/build-stg-website' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
tano1:0603game tano$ git status # もう一度確認
On branch feat/build-stg-website
Your branch is ahead of 'origin/feat/build-stg-website' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
tano1:0603game tano$ git branch # そう言えばブランチ確認してなかった
* feat/build-stg-website
main
tano1:0603game tano$ git push origin feat/build-stg-website # ブランチ確認して、問題無くてコミットも終わってるのでリモートリポジトリに変更履歴反映
Enumerating objects: 17, done.
Counting objects: 100% (17/17), done.
Delta compression using up to 8 threads
Compressing objects: 100% (11/11), done.
Writing objects: 100% (12/12), 4.86 KiB | 4.86 MiB/s, done.
Total 12 (delta 3), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
To https://github.com/YusukeTano/0603game-tano-public.git
fef40d1..85f6d89 feat/build-stg-website -> feat/build-stg-website
# ここからGithubなどのリモート側の操作
# リモートでmainブランチとchore/terraform-backend-setup-stg-clone-adjustブランチがあるので、変更をmainブランチへ反映させるためにプルリクエストを行う
# プルリクエストを受けた側(自学習なら自分)は変更差分を見て問題無いか確認して、問題なければマージしてchore/terraform-backend-setup-stg-clone-adjustブランチを削除する
# Githubなどのリモート側の操作はここまで
tano1:0603game tano$ git checkout main # リモートはmainが1つになって最新なので、ローカルのmainに反映させるためにブランチを変更する
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
tano1:0603game tano$ git branch # ブランチを確認
feat/build-stg-website
* main
tano1:0603game tano$ git pull # mainになってるので、リモートmainをローカルmainに反映
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (1/1), 980 bytes | 326.00 KiB/s, done.
From https://github.com/YusukeTano/0603game-tano-public
fef40d1..a87ead0 main -> origin/main
Updating fef40d1..a87ead0
Fast-forward
infra/aws-architecture-diagram.drawio | 224 ++++++++++++++++++++++++++++
infra/aws-architecture-diagram.yaml | 112 --------------
infra/static-website/environments/prd/locals.tf | 32 ++++
infra/static-website/environments/stg/.terraform.lock.hcl | 25 ++++
infra/static-website/environments/stg/backend.tf | 16 ++
infra/static-website/environments/stg/main.tf | 116 ++++++++++++++
infra/static-website/environments/stg/outputs.tf | 17 +++
infra/static-website/environments/stg/providers.tf | 30 ++++
infra/static-website/environments/stg/terraform.tf | 10 ++
infra/static-website/environments/stg/terraform.tfvars | 11 ++
infra/static-website/environments/stg/variables.tf | 26 ++++
11 files changed, 507 insertions(+), 112 deletions(-)
create mode 100644 infra/aws-architecture-diagram.drawio
delete mode 100644 infra/aws-architecture-diagram.yaml
create mode 100644 infra/static-website/environments/prd/locals.tf
create mode 100644 infra/static-website/environments/stg/.terraform.lock.hcl
create mode 100644 infra/static-website/environments/stg/backend.tf
create mode 100644 infra/static-website/environments/stg/main.tf
create mode 100644 infra/static-website/environments/stg/outputs.tf
create mode 100644 infra/static-website/environments/stg/providers.tf
create mode 100644 infra/static-website/environments/stg/terraform.tf
create mode 100644 infra/static-website/environments/stg/terraform.tfvars
create mode 100644 infra/static-website/environments/stg/variables.tf
tano1:0603game tano$ git status # 確認
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
tano1:0603game tano$ git branch -d feat/build-stg-website # ローカルの必要のないブランチを削除
Deleted branch feat/build-stg-website (was 85f6d89).
tano1:0603game tano$ git branch # ブランチが削除されていることを確認
* main
tano1:0603game tano$
問題発生(このままのコードだとstg,devだと上手く行かないのを修正)
問題点
prdと同じCNAMEを取りに行く
ディストリビューション作る時にCNAMEを設定する。
そのCNAMEがvar.domain_name
になっているので、stgでも同じ値になるので、同じCNAMEは設定出来なくてエラーとなる。
module "cloudfront_cdn" {
source = "../../../modules/cloudfront-oac"
# ACMモジュールの出力を入力として渡す
acm_certificate_arn = module.acm.certificate_arn
# S3モジュールの出力を入力として渡す
s3_origin_domain_name = module.s3_website.bucket_regional_domain_name
# ⭐ bucket_id を使用(既存の出力をそのまま使える!)
s3_bucket_id = module.s3_website.bucket_id
domain_aliases = ["${var.domain_name}", "www.${var.domain_name}"]
tags = var.common_tags
}
Route 53 ゾーン解決エラー
これ仮にdomain_nameをstg.tanoyuusuke.comにした場合、上記は解決するけどここでエラーになる。
ホストゾーンを探す時にstg.tanoyuusuke.comはありませんとなる。
module "dns" {
source = "../../../modules/route53-records"
providers = {
aws.dns_master = aws.dns_master
}
zone_name = var.domain_name
records = [
localsが必要かも
ドメイン系などの、stg,devあたりが実行出来ないことになったのでlocals
を導入。
git操作(ファイル編集始まり)localsが必要かも
これからファイルの編集を行うので、何か間違えた時にある地点に戻せるようにgitのブランチを切ってファイルの編集を行う
git操作(ファイル編集始まり)localsが必要かも
tano1:0603game tano$ git checkout -b refactor/prd-use-locals # 新しいブランチ作成
Switched to a new branch 'refactor/prd-use-locals'
tano1:0603game tano$ git branch # 作成されたブランチ確認
main
* refactor/prd-use-locals
tano1:0603game tano$
locals.tfを作成し、他ファイルもそれに合わす形にする
static-website/prd/locals.tf作成
locals.tf: 外部入力(variable)を元に、環境に依存する値や命名・タグなどを計算、整形して一元化する。
project = var.project
: なぜmainじゃなくてlocalsにわざわざ入れるのかは、locals内の計算にvariableを使える。ここではタグとバケット名OACに使っている。この環境固有のものはlocalsに集約すると、統一性と一貫性が保証される。最終的に環境ごとにtfvarsを変更するのみに出来る。また同じことを何回も書くならモジュールみたいな使い方が出来る。バケット名を何回も書くならlocalsに記載すれば、文字数が減る。
fqdn = local.env == "prd" ? local.base_domain : "${local.env}.${local.base_domain}"
: envがprdならlocal.base_domain(tanoyuusuke.com)
、prdじゃないなら"${local.env}.${local.base_domain}"
www_fqdn = local.env == "prd" ? "www.${local.base_domain}" : "www.${local.fqdn}"
: 上のfqdn
を"www.${local.fqdn}"
で指定している。
domain_aliases = var.include_www: これはtfvars
でtrue
とfalse
を使い分ける
tano1:prd tano$ cat locals.tf
locals {
project = var.project
env = var.env # "prd" | "stg" | "dev"
base_domain = var.base_domain # "tanoyuusuke.com"
fqdn = local.env == "prd" ? local.base_domain : "${local.env}.${local.base_domain}"
www_fqdn = local.env == "prd" ? "www.${local.base_domain}" : "www.${local.fqdn}"
domain_aliases = var.include_www ? [local.fqdn, local.www_fqdn] : [local.fqdn]
zone_name = local.base_domain: ホストゾーンは常に固定で参照したい
bucket_name = "bucket-variables
と組み合わせたbucket_name
length(local._oac) > 64: 条件式。local._oac
の文字数が64より大きいならture
、そうじゃないならfalse
。
length()関数: ()内の文字数をカウントする
substr(local._oac, 0, 64): substr()関数。substr(文字列, 開始位置, 長さ) 開始位置から長さ分の文字列にする。
例:substr("hello world", 6, 5) # → "world"
tags = merge(var.common_tags, {: 全環境共通で動かないものはlocals
に記載する。環境ごとに加えたいタグはtfvars
に記載する。
arn:aws:iam::
# 親ゾーンは常に固定
zone_name = local.base_domain
# 一意な名前(アカウントID入り)
bucket_name = "bucket-${local.project}-${local.env}-${var.aws_account_id}"
# OACは64文字制限に注意(長いなら切詰め)
_oac = "oac-${local.project}-${local.env}"
oac_name = length(local._oac) > 64 ? substr(local._oac, 0, 64) : local._oac
# 共通タグ合成
tags = merge(var.common_tags, {
Project = local.project
Environment = local.env
ManagedBy = "Terraform"
})
# ロールARNも “計算” に寄せられるなら寄せる(ばらつくなら var で渡す)
execution_role_arn = "arn:aws:iam::${var.aws_account_id}:role/TerraformExecutionRole-${local.env}"
dns_manager_role_arn = "arn:aws:iam::${var.dns_account_id}:role/Route53CrossAccountManagerRole"
}
tano1:prd tano$
static-website/prd/variables.tfを編集
variable "base_domain" {
: localsに合わせる形に編集
variable "base_domain" {
description = "ベースとなるドメイン名 (例: tanoyuusuke.com)"
type = string
}
static-website/prd/terraform.tfvarsを編集
}tano1:prd tano$ cat terraform.tfvars
project = "0603game"
env = "prd"
base_domain = "tanoyuusuke.com"
aws_account_id = "<prdアカウント>"
common_tags = {
ManagedBy = "Terraform"
}tano1:prd tano$
static-website/prd/main.tfを編集
local: ローカルと記載されてるものをもろもろ変更
}tano1:prd tano$ cat main.tf
module "acm" {
source = "../../../modules/acm-certificate"
providers = {
aws = aws.us-east-1
aws.dns_master = aws.dns_master
}
domain_name = local.fqdn
subject_alternative_names = [local.www_fqdn]
tags = local.tags
}
module "s3_website" {
source = "../../../modules/s3-private-bucket"
bucket_name = local.bucket_name
tags = local.tags
}
module "cloudfront_cdn" {
source = "../../../modules/cloudfront-oac"
acm_certificate_arn = module.acm.certificate_arn
s3_origin_domain_name = module.s3_website.bucket_regional_domain_name
# ⭐ bucket_id を使用(既存の出力をそのまま使える!)
s3_bucket_id = module.s3_website.bucket_id
domain_aliases = local.domain_aliases
tags = local.tags
}
resource "aws_s3_bucket_policy" "website_bucket_policy" {
bucket = module.s3_website.bucket_id
policy = jsonencode({
Version = "2012-10-17",
Statement = [ {
Effect = "Allow",
Principal = { Service = "cloudfront.amazonaws.com" },
Action = "s3:GetObject",
Resource = "${module.s3_website.bucket_arn}/*",
Condition = {
StringEquals = { "AWS:SourceArn" = module.cloudfront_cdn.distribution_arn }
}
} ]
})
}
module "dns" {
source = "../../../modules/route53-records"
providers = {
aws.dns_master = aws.dns_master
}
zone_name = local.zone_name
records = [
{
name = local.fqdn, type = "A",
alias = {
name = module.cloudfront_cdn.domain_name
zone_id = module.cloudfront_cdn.hosted_zone_id
}
},
{
name = local.www_fqdn, type = "A",
alias = {
name = module.cloudfront_cdn.domain_name
zone_id = module.cloudfront_cdn.hosted_zone_id
}
},
{
name = local.fqdn, type = "AAAA",
alias = {
name = module.cloudfront_cdn.domain_name
zone_id = module.cloudfront_cdn.hosted_zone_id
}
},
{
name = local.www_fqdn, type = "AAAA",
alias = {
name = module.cloudfront_cdn.domain_name
zone_id = module.cloudfront_cdn.hosted_zone_id
}
}
]
}tano1:prd tano$
Terraform実行
terraform plan
var.include_www
とvar.dns_account_id
がvariablesで未定義なのでエラー
内容は、var.include_www
はディストリニューションにこの値がtrue
ならCNAMEをwww.付きにする。
var.dns_account_id
は、そもそもDNSアカウントとして定義して居なかった。DNSアカウントIDも変数として使えるようにvariablesに定義する。
そして2つとも、tfvarsに値を入れる。
variable "include_www" {
description = "Whether to include www subdomain"
type = bool
default = true # デフォルトはwww付き
}
# 2. dns_account_id の定義
variable "dns_account_id" {
description = "AWS Account ID for DNS management (Route53)"
type = string
# デフォルト値を設定するか、tfvarsで指定
# default = "<DNSアカウントID>" # オプション
}
dns_account_id = "<DNSアカウントID>" # 明示的に指定
include_www = true # www.tanoyuusuke.comも使用
╷
│ Error: Reference to undeclared input variable
│
│ on locals.tf line 8, in locals:
│ 8: domain_aliases = var.include_www ? [local.fqdn, local.www_fqdn] : [local.fqdn]
│
│ An input variable with the name "include_www" has not been declared. This variable can be
│ declared with a variable "include_www" {} block.
╵
╷
│ Error: Reference to undeclared input variable
│
│ on locals.tf line 29, in locals:
│ 29: dns_manager_role_arn = "arn:aws:iam::${var.dns_account_id}:role/Route53CrossAccountManagerRole"
│
│ An input variable with the name "dns_account_id" has not been declared. Did you mean
│ "aws_account_id"?
╵
tano1:prd tano$
terraform apply
問題無し
prdロール名をlocalsの命名規則に沿って作成し編集する
prdロール作成
prdアカウントのIAMロールを作成する
命名規則はlocalsに沿って作成
arn:aws:iam::${var.aws_account_id}:role/TerraformExecutionRole-${local.env}
Terraform実行踏み台アカウントの許可セット作成
下記のようにlocalsに沿う形で編集
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": [
"arn:aws:iam::<アカウントID>:role/TerraformExecutionRole-dev",
"arn:aws:iam::<アカウントID>:role/TerraformExecutionRole-stg",
"arn:aws:iam::<アカウントID>:role/TerraformExecutionRole-prd",
"arn:aws:iam::<アカウントID>:role/Route53CrossAccountManagerRole"
]
}
]
}
static-website/prd/providers.tf編集
下記のようにrole_arn
とsession_name
にlocalsを使用
tano1:prd tano$ cat providers.tf
# デフォルトプロバイダ
provider "aws" {
region = "ap-northeast-1"
assume_role {
role_arn = local.execution_role_arn
session_name = "tf-session-static-website-${local.env}"
}
}
# ACM証明書用のプロバイダ
provider "aws" {
alias = "us-east-1"
region = "us-east-1"
assume_role {
role_arn = local.execution_role_arn
session_name = "tf-session-static-website-${local.env}-acm"
}
}
# DNS操作用のプロバイダ
provider "aws" {
alias = "dns_master"
region = "ap-northeast-1"
assume_role {
role_arn = local.dns_manager_role_arn
session_name = "tf-session-dns-cross-account-${local.env}"
}
}tano1:prd tano$
static-website/prd/backend.tf編集
terraform init
時のエラーで修正
backend.tfのロール名も変更
tano1:prd tano$ cat backend.tf
terraform {
backend "s3" {
# backend-setupで作成したS3バケット
bucket = "0603game-prd-tfstate-002540791269"
# このスタック専用のStateファイルのパス
key = "static-website/terraform.tfstate"
region = "ap-northeast-1"
dynamodb_table = "0603game-prd-tfstate-lock"
encrypt = true
# 新しい記法 + 正しいロール名
assume_role = {
role_arn = "arn:aws:iam::002540791269:role/TerraformExecutionRole-prd"
}
}
}
tano1:prd tano$
terraform init
backend.tfのロールの名称を修正してなかったので修正
│ Error: Cannot assume IAM Role
│
│ IAM Role (arn:aws:iam::002540791269:role/TerraformExecutionRole) cannot be assumed.
│
│ There are a number of possible causes of this - the most common are:
│ * The credentials used in order to assume the role are invalid
│ * The credentials do not have appropriate permission to assume the role
│ * The role ARN is not valid
│
│ Error: operation error STS: AssumeRole, https response error StatusCode: 403, RequestID:
│ 66114a78-169c-4b24-8c8a-9886c9a5ecff, api error AccessDenied: User:
│ arn:aws:sts::318574063927:assumed-role/AWSReservedSSO_0603game-TerraformOperator_c6f75dbe8448194d/tano-sso-user
│ is not authorized to perform: sts:AssumeRole on resource:
│ arn:aws:iam::002540791269:role/TerraformExecutionRole
│
╵
tano1:prd tano$
backend.tfのファイルが変更があったためエラー
terraform init -migrate-state
: stateファイルを移動するとき
terraform init -reconfigure
: stateファイルを移動していなくて、ファイルの中が変更になったとき
terraform init -reconfigure
を実行し、解消
╷
│ Error: Backend configuration changed
│
│ A change in the backend configuration has been detected, which may require migrating existing
│ state.
│
│ If you wish to attempt automatic migration of the state, use "terraform init -migrate-state".
│ If you wish to store the current configuration with no changes to the state, use "terraform
│ init -reconfigure".
╵
tano1:prd tano$
terraform plan
差分無し
git操作(ファイル編集終わり)localsが必要かも
一区切りのファイル編集が終わったので、その編集した変更をリモートのメインブランチへ反映させるため操作を行う
git操作(ファイル編集終わり)localsが必要かも
tano1:0603game tano$ git branch # 現在のブランチを確認
main
* refactor/prd-use-locals
tano1:0603game tano$ git status # 今の状況確認して、addが必要なことを確認
On branch refactor/prd-use-locals
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: infra/aws-architecture-diagram.drawio
modified: infra/static-website/environments/prd/backend.tf
modified: infra/static-website/environments/prd/main.tf
modified: infra/static-website/environments/prd/providers.tf
modified: infra/static-website/environments/prd/terraform.tfvars
modified: infra/static-website/environments/prd/variables.tf
no changes added to commit (use "git add" and/or "git commit -a")
tano1:0603game tano$ git add . # addする
tano1:0603game tano$ git status # addできたことを確認
On branch refactor/prd-use-locals
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: infra/aws-architecture-diagram.drawio
modified: infra/static-website/environments/prd/backend.tf
modified: infra/static-website/environments/prd/main.tf
modified: infra/static-website/environments/prd/providers.tf
modified: infra/static-website/environments/prd/terraform.tfvars
modified: infra/static-website/environments/prd/variables.tf
tano1:0603game tano$ git commit -m "prd-use-locals" # add出来たのでコミットする
[refactor/prd-use-locals 3b5e895] prd-use-locals
6 files changed, 190 insertions(+), 224 deletions(-)
tano1:0603game tano$ git status # コミット出来たことを確認
On branch refactor/prd-use-locals
nothing to commit, working tree clean
tano1:0603game tano$ git push origin refactor/prd-use-locals # ローカルブランチに変更履歴を反映させたので、リモートブランチへ反映させる
Enumerating objects: 23, done.
Counting objects: 100% (23/23), done.
Delta compression using up to 8 threads
Compressing objects: 100% (11/11), done.
Writing objects: 100% (12/12), 5.54 KiB | 5.54 MiB/s, done.
Total 12 (delta 6), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (6/6), completed with 6 local objects.
remote:
remote: Create a pull request for 'refactor/prd-use-locals' on GitHub by visiting:
remote: https://github.com/YusukeTano/0603game-tano-public/pull/new/refactor/prd-use-locals
remote:
To https://github.com/YusukeTano/0603game-tano-public.git
* [new branch] refactor/prd-use-locals -> refactor/prd-use-locals
tano1:0603game tano$
# ここからGithubなどのリモート側の操作
# リモートでmainブランチとfeature/terraform-backend-setupブランチがあるので、変更をmainブランチへ反映させるためにプルリクエストを行う
# プルリクエストを受けた側(自学習なら自分)は変更差分を見て問題無いか確認して、問題なければマージしてfeature/terraform-backend-setupブランチを削除する
# Githubなどのリモート側の操作はここまで
tano1:0603game tano$ git branch # 現在のブランチ位置を確認
main
* refactor/prd-use-locals
tano1:0603game tano$ git checkout main # mainにブランチを変更
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
tano1:0603game tano$ git branch # ブランチを変更出来たことを確認
* main
refactor/prd-use-locals
tano1:0603game tano$ git pull # リモートのmainブランチが最新なので、最新をローカルのmainブランチへ反映
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (1/1), 896 bytes | 298.00 KiB/s, done.
From https://github.com/YusukeTano/0603game-tano-public
a87ead0..e74db64 main -> origin/main
Updating a87ead0..e74db64
Fast-forward
infra/aws-architecture-diagram.drawio | 259 ++++++++++++++++-------------------
infra/static-website/environments/prd/backend.tf | 6 +-
infra/static-website/environments/prd/main.tf | 80 ++++-------
infra/static-website/environments/prd/providers.tf | 24 ++--
infra/static-website/environments/prd/terraform.tfvars | 15 +-
infra/static-website/environments/prd/variables.tf | 30 +++-
6 files changed, 190 insertions(+), 224 deletions(-)
tano1:0603game tano$ git branch -d refactor/prd-use-locals # 要らなくなったブランチを削除
Deleted branch refactor/prd-use-locals (was 3b5e895).
tano1:0603game tano$ git branch # 削除出来たことを確認
* main
tano1:0603game tano$
フェーズ3:stg用ウェブサイトの実行
git操作(ファイル編集始まり)フェーズ3:stg用ウェブサイトの実行
これからファイルの編集を行うので、何か間違えた時にある地点に戻せるようにgitのブランチを切ってファイルの編集を行う
git操作(ファイル編集始まり)フェーズ3:stg用ウェブサイトの実行
tano1:0603game tano$ git branch # 現在のブランチ状況を確認
* main
tano1:0603game tano$ git status # 現在のgit状況を確認
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
tano1:0603game tano$ git checkout -b feat/create-stg-environment # 新たに作業に基づいたローカルブランチを作成
Switched to a new branch 'feat/create-stg-environment'
tano1:0603game tano$ git branch # 作成されたブランチを確認
* feat/create-stg-environment
main
tano1:0603game tano$
static-website/prdから作って、またコピーする
prdディレクトリのコピー
コピーして一部のファイルの編集して使える。これがモジュールの良いところ
cp -r infra/static-website/environments/prd infra/static-website/environments/stg
不要なファイル、ディレクトリを削除
tfstateがある場合はそれも削除する。
.terraform.lock.hclはプロバイダー情報などを他環境とも同じのを使いたい場合はこのファイルは残す
$ rm -rf .terraform/
static-website/stg/terraform.tfvars編集
stg環境で使うものを編集
ennv,aws_account_idとか
tano1:stg tano$ cat terraform.tfvars
project = "0603game"
env = "stg"
base_domain = "tanoyuusuke.com"
aws_account_id = "<stgのアカウントID>" # stgのアカウントID
# stgではwwwドメインは使使わないのでfalse
include_www = false
# DNS管理アカウントはprdと同じ
dns_account_id = "<DNS管理アカウントID>"
common_tags = {
ManagedBy = "Terraform"
}tano1:stg tano$
static-website/stg/backend.tf編集
ここもbackend-setupでstg用に作成したリソースを記載
}tano1:stg tano$ cat backend.tf
# infra/static-website/environments/stg/backend.tf
terraform {
backend "s3" {
# パート1で作成したstg用のS3バケット
bucket = "0603game-stg-tfstate-086266612383"
# stgスタック専用のStateファイルのパス
key = "static-website/stg/terraform.tfstate"
region = "ap-northeast-1"
# パート1で作成したstg用のDynamoDBテーブル
dynamodb_table = "0603game-stg-tfstate-lock"
encrypt = true
# stg用の実行ロールARN
assume_role = {
role_arn = "arn:aws:iam::<stgアカウントID>:role/TerraformExecutionRole-stg"
}
}
}tano1:stg tano$
stg用ウェブサイトのTerraform実行
Terraform init
backend.tfのasuumeの構文エラー
assume_role {
に=を追加assume_role = {
で解決。
╷
│ Error: Unsupported block type
│
│ on backend.tf line 19, in terraform:
│ 19: assume_role {
│
│ Blocks of type "assume_role" are not expected here. Did you mean to define argument
│ "assume_role"? If so, use the equals sign to assign it a value.
╵
Terraform plan
prd環境では、domain_nameがtanoyuusuke.comなのでホストゾーン検索にも使用してたし、証明書発行とかにも使って居た。
stg環境になるとdomain_nameがstg.tanoyuusuke.comになるのでそんなホストゾーンは無いよとエラー。
一番影響無く解決したいので、モジュール側でdomain_nameと、ホストゾーン検索用のbase_domainを用意しモジュールメインに記載。
呼び出し側メインでは、local.base_domainを作ってるので、それをbase_domainとして受け渡す。
この修正で解決
static-website/stg/main.tf
:
}
domain_name = local.fqdn
+ base_domain = local.base_domain # "tanoyuusuke.com"(ゾーン検索用)
subject_alternative_names = [local.www_fqdn]
tags = local.tags
}
modules/acm-certificate/main.tf
:
data "aws_route53_zone" "main" {
provider = aws.dns_master
+ name = var.base_domain
- name = var.domain_name
}
modules/acm-certificate/variables.tf
:
+ variable "base_domain" {
+ description = "Route53ホストゾーンの親ドメイン名(例: tanoyuusuke.com)"
+ type = string
+ }
エラー内容
╷
│ Error: no matching Route 53 Hosted Zone found
│
│ with module.acm.data.aws_route53_zone.main,
│ on ../../../modules/acm-certificate/main.tf line 2, in data "aws_route53_zone" "main":
│ 2: data "aws_route53_zone" "main" {
│
╵
tano1:stg tano$
Terraform apply
成功
残タスク、prd側も上記の修正をする
static-website/prd/main.tf編集
providers = {
aws = aws.us-east-1
aws.dns_master = aws.dns_master
}
domain_name = local.fqdn
+ base_domain = local.base_domain
subject_alternative_names = [local.www_fqdn]
tags = local.tags
}
git操作(ファイル編集終わり)フェーズ3:stg用ウェブサイトの実行
一区切りのファイル編集が終わったので、その編集した変更をリモートのメインブランチへ反映させるため操作を行う
git操作(ファイル編集終わり)フェーズ3:stg用ウェブサイトの実行
tano1:stg tano$ git branch
* feat/create-stg-environment
main
tano1:stg tano$ git status
On branch feat/create-stg-environment
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: ../../../modules/acm-certificate/main.tf
modified: ../../../modules/acm-certificate/variables.tf
modified: ../prd/main.tf
modified: backend.tf
modified: main.tf
modified: providers.tf
modified: terraform.tfvars
modified: variables.tf
Untracked files:
(use "git add <file>..." to include in what will be committed)
locals.tf
no changes added to commit (use "git add" and/or "git commit -a")
tano1:stg tano$ git add .
tano1:stg tano$ git status
On branch feat/create-stg-environment
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: backend.tf
new file: locals.tf
modified: main.tf
modified: providers.tf
modified: terraform.tfvars
modified: variables.tf
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: ../../../modules/acm-certificate/main.tf
modified: ../../../modules/acm-certificate/variables.tf
modified: ../prd/main.tf
tano1:stg tano$ cd
direnv: unloading
tano1:~ tano$ cd 0603game/
direnv: loading ~/0603game/.envrc
direnv: export +AWS_PROFILE ~XPC_SERVICE_NAME
tano1:0603game tano$ git add .
tano1:0603game tano$ git status
On branch feat/create-stg-environment
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: infra/modules/acm-certificate/main.tf
modified: infra/modules/acm-certificate/variables.tf
modified: infra/static-website/environments/prd/main.tf
modified: infra/static-website/environments/stg/backend.tf
new file: infra/static-website/environments/stg/locals.tf
modified: infra/static-website/environments/stg/main.tf
modified: infra/static-website/environments/stg/providers.tf
modified: infra/static-website/environments/stg/terraform.tfvars
modified: infra/static-website/environments/stg/variables.tf
tano1:0603game tano$ git commit -m "create-stg-environment"
[feat/create-stg-environment e8631a9] create-stg-environment
9 files changed, 123 insertions(+), 88 deletions(-)
create mode 100644 infra/static-website/environments/stg/locals.tf
tano1:0603game tano$ git push origin create-stg-environment
error: src refspec create-stg-environment does not match any
error: failed to push some refs to 'https://github.com/YusukeTano/0603game-tano-public.git'
tano1:0603game tano$ git branch
* feat/create-stg-environment
main
tano1:0603game tano$ git push origin feat/create-stg-environment
Enumerating objects: 29, done.
Counting objects: 100% (29/29), done.
Delta compression using up to 8 threads
Compressing objects: 100% (14/14), done.
Writing objects: 100% (15/15), 2.23 KiB | 2.23 MiB/s, done.
Total 15 (delta 8), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (8/8), completed with 7 local objects.
remote:
remote: Create a pull request for 'feat/create-stg-environment' on GitHub by visiting:
remote: https://github.com/YusukeTano/0603game-tano-public/pull/new/feat/create-stg-environment
remote:
To https://github.com/YusukeTano/0603game-tano-public.git
* [new branch] feat/create-stg-environment -> feat/create-stg-environment
tano1:0603game tano$
# ここからGithubなどのリモート側の操作
# リモートでmainブランチとfeature/terraform-backend-setupブランチがあるので、変更をmainブランチへ反映させるためにプルリクエストを行う
# プルリクエストを受けた側(自学習なら自分)は変更差分を見て問題無いか確認して、問題なければマージしてfeature/terraform-backend-setupブランチを削除する
# Githubなどのリモート側の操作はここまで
tano1:0603game tano$ git checkout main
D public/assets/game.js
D public/assets/styles.css
M public/index.html
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
tano1:0603game tano$ git branch
feat/create-stg-environment
* main
tano1:0603game tano$ git pull
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (1/1), 896 bytes | 224.00 KiB/s, done.
From https://github.com/YusukeTano/0603game-tano-public
e74db64..28483a4 main -> origin/main
Updating e74db64..28483a4
Fast-forward
infra/modules/acm-certificate/main.tf | 2 +-
infra/modules/acm-certificate/variables.tf | 11 ++++-
infra/static-website/environments/prd/main.tf | 3 +-
infra/static-website/environments/stg/backend.tf | 15 +++++--
infra/static-website/environments/stg/locals.tf | 32 ++++++++++++++
infra/static-website/environments/stg/main.tf | 81 +++++++++++-------------------------
infra/static-website/environments/stg/providers.tf | 16 +++----
infra/static-website/environments/stg/terraform.tfvars | 21 ++++++----
infra/static-website/environments/stg/variables.tf | 30 +++++++++----
9 files changed, 123 insertions(+), 88 deletions(-)
create mode 100644 infra/static-website/environments/stg/locals.tf
tano1:0603game tano$ git branch -d feat/create-stg-environment
Deleted branch feat/create-stg-environment (was e8631a9).
tano1:0603game tano$ git branch
* main
tano1:0603game tano$
次回へ!!!
Discussion