「workspace切り替えだけでは、インスタンスタイプやドメイン名の環境差分を管理しきれない」
terraform workspaceはtfstateを分離するための仕組みですが、workspaceを切り替えるだけでは「どの環境の変数値を使うか」まで制御できません。dev・stg・prodでインスタンスタイプ、DBのサイズ、ドメイン名が異なる現場では、workspaceと-var-fileを組み合わせて初めて完全な環境分離が実現します。
この記事では、terraform workspace 環境分離の設計として、workspaceと-var-fileを組み合わせたdev・stg・prodの管理方法を解説します。実行環境はTerraform 1.8(RHEL 9.4 / Ubuntu 24.04 LTS)で動作確認済みです。
この記事のポイント
・workspaceはtfstateを分離し、-var-fileはパラメータを分離する役割を担う
・2つを組み合わせることで1セットのHCLで3環境を安全に管理できる
・S3バックエンド使用時はworkspaceごとにtfstateのパスが自動で分かれる
・「workspace selectを忘れたまま apply」が最多事故パターンで対策が必要
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
Terraformで複数環境を管理する前に知っておくこと
「Makefileでmake dev-applyやmake prod-applyを作ってworkspaceを自動で切り替えるようにしたい」こうした相談を私のTerraformセミナーでもよく受けます。その前提として、環境分離に必要な軸を2つ理解しておく必要があります。
・tfstateの分離:どの環境のインフラを管理しているかを記録するファイルを環境ごとに分ける
・パラメータの分離:インスタンスタイプ・DBサイズ・ドメイン名などの環境差分を変数ファイルで管理する
workspaceはtfstateの分離を担い、-var-fileはパラメータの分離を担います。この役割分担を理解してから設計に入ることが重要です。
terraform workspaceだけで「環境別の変数値」まで制御しようとすると、HCLコード内に
terraform.workspace == "prod" ? "m5.large" : "t3.micro"のような条件分岐が増殖します。これは読みにくく、後から変更が難しいコードになります。-var-fileを組み合わせれば、この問題を根本から解消できます。terraform workspaceとは何か|仕組みと基本コマンド
terraform workspaceは「同一のHCLコードから複数のtfstateを管理する仕組み」です。Terraformをインストールした直後は"default"というworkspaceが1つ存在しています。基本的なworkspace操作は以下のコマンドで行います。
# 現在のworkspace一覧(*が現在のworkspace) $ terraform workspace list * default # dev・stg・prod workspaceを作成する $ terraform workspace new dev Created and switched to workspace "dev"! $ terraform workspace new stg $ terraform workspace new prod # workspace一覧を再確認 $ terraform workspace list default * dev prod stg # workspaceを切り替える $ terraform workspace select prod Switched to workspace "prod" # 現在のworkspaceを確認する $ terraform workspace show prod
terraform.workspaceがあり、現在のworkspace名を文字列として参照できます。タグやリソース名にworkspace名を埋め込むのに便利です。# main.tf(workspace名をタグに使う例) resource "aws_instance" "web" { ami = data.aws_ami.amazon_linux.id instance_type = var.instance_type # -var-fileから取得 tags = { Name = "web-${terraform.workspace}" Environment = terraform.workspace } }
var.instance_typeは-var-fileから取得し、環境を示すタグだけworkspace変数を使うのが設計の基本です。-var-fileで環境別パラメータを分離する
-var-fileオプションは、terraform apply実行時に変数値を外部ファイルから読み込む仕組みです。環境ごとに異なる値をHCLコード内にハードコードせず、.tfvarsファイルとして管理します。推奨ディレクトリ構造は以下です。
project/ ├── main.tf # リソース定義 ├── variables.tf # variable宣言 ├── outputs.tf # output定義 ├── backend.tf # バックエンド設定 └── environments/ ├── dev.tfvars # dev環境の変数値 ├── stg.tfvars # stg環境の変数値 └── prod.tfvars # prod環境の変数値
# variables.tf variable "instance_type" { type = string description = "EC2インスタンスタイプ(環境ごとに異なる)" } variable "db_instance_class" { type = string description = "RDSインスタンスクラス" } variable "min_capacity" { type = number description = "Auto Scalingの最小台数" } variable "max_capacity" { type = number description = "Auto Scalingの最大台数" } variable "domain" { type = string description = "サービスのドメイン名" }
# environments/dev.tfvars instance_type = "t3.micro" db_instance_class = "db.t3.micro" min_capacity = 1 max_capacity = 2 domain = "dev.example.com"
# environments/prod.tfvars instance_type = "m5.large" db_instance_class = "db.m5.large" min_capacity = 3 max_capacity = 10 domain = "example.com"
dataソースで取得するのが現場のベストプラクティスです。.tfvarsファイルはGitリポジトリへのコミット前に.gitignoreに*.tfvarsを追加しておきましょう。workspaceと-var-fileを組み合わせた設計パターン
workspaceと-var-fileを組み合わせた実際の運用コマンドは以下です。# dev環境へのデプロイ $ terraform workspace select dev $ terraform plan -var-file=environments/dev.tfvars $ terraform apply -var-file=environments/dev.tfvars # stg環境へのデプロイ $ terraform workspace select stg $ terraform plan -var-file=environments/stg.tfvars $ terraform apply -var-file=environments/stg.tfvars # prod環境へのデプロイ $ terraform workspace select prod $ terraform plan -var-file=environments/prod.tfvars $ terraform apply -var-file=environments/prod.tfvars
# Makefile ENV ?= dev .PHONY: plan apply plan: terraform workspace select $(ENV) terraform plan -var-file=environments/$(ENV).tfvars apply: terraform workspace select $(ENV) terraform apply -var-file=environments/$(ENV).tfvars # 使い方 # make plan ENV=stg # make apply ENV=prod
ENV変数を明示しないとdevがデフォルトになるため、誤って本番を変更するリスクを下げられます。さらに
localsブロックでworkspace名とvar-fileの変数を組み合わせると、環境ごとの設定を一元管理できます。# main.tf(locals活用例) locals { env = terraform.workspace is_prod = terraform.workspace == "prod" name_prefix = "${var.project_name}-${local.env}" # prod環境では削除保護を有効にする deletion_protection = local.is_prod ? true : false } resource "aws_db_instance" "main" { identifier = "${local.name_prefix}-db" instance_class = var.db_instance_class deletion_protection = local.deletion_protection # ...省略 }
var.db_instance_classはvar-fileから取得し、削除保護のようなworkspace名で自動判定できる設定はlocal.is_prodで制御します。2つのアプローチを役割で分けるのがポイントです。
>> Terraform実践セミナーの詳細はこちら
tfstateの分離戦略|workspaceとS3バックエンドの関係
チーム開発ではtfstateをS3バックエンドで管理するのが標準です。S3バックエンドとworkspaceを組み合わせると、tfstateのS3上のパスが自動で環境ごとに分離される仕組みがあります。# backend.tf terraform { backend "s3" { bucket = "my-company-terraform-state" key = "services/api/terraform.tfstate" region = "ap-northeast-1" dynamodb_table = "terraform-state-lock" encrypt = true } }
keyに指定したパスはworkspace名によって自動的にプレフィックスが付与されます。# S3上でのtfstate実際のパス(workspace使用時) # defaultワークスペース s3://my-company-terraform-state/services/api/terraform.tfstate # devワークスペース s3://my-company-terraform-state/env:/dev/services/api/terraform.tfstate # stgワークスペース s3://my-company-terraform-state/env:/stg/services/api/terraform.tfstate # prodワークスペース s3://my-company-terraform-state/env:/prod/services/api/terraform.tfstate
env:/{workspace名}/というプレフィックスが自動で付きます。defaultワークスペースだけは例外で、このプレフィックスなしの元のパスに保存されます。この仕組みを知っておくと、AWSコンソールのS3バケットを開いたときに「どのworkspaceのtfstateか」がパスから判断できます。また、
terraform state listで確認できるリソースはworkspace切り替えに連動して変わるため、別のworkspaceで誤ってstate rmするリスクも防げます。DynamoDBのステートロックについても確認しておきます。DynamoDBのロックキーにはworkspace名が含まれるため、devとprodが同時に
terraform applyを実行してもロックが競合しません。これはCI/CDパイプラインで並列デプロイを行う際の重要な前提です。よくある落とし穴と対処法
1. workspace selectを忘れたまま apply してしまう
最も多い事故パターンです。以前stgでapplyした後、workspace selectを実行せず、var-file=environments/prod.tfvarsだけ指定してapplyすると、stg環境のtfstateを使ってprodのパラメータを適用してしまいます。対策として前述のMakefileパターンか、以下のシェル関数でworkspace確認を強制するのが有効です。
# ~/.bashrc または ~/.zshrc に追加 tf-apply() { local env="${1}" if [ -z "${env}" ]; then echo "ERROR: 環境名(dev/stg/prod)を引数で指定してください" return 1 fi echo "workspace: $(terraform workspace show) → ${env}に切り替えます" terraform workspace select "${env}" && \ terraform plan -var-file="environments/${env}.tfvars" && \ echo "--- plan完了。applyを実行しますか?(Ctrl+Cで中断)---" && \ read -r && \ terraform apply -var-file="environments/${env}.tfvars" } # 使い方 # tf-apply prod
2. .tfvarsファイルにシークレットを書いてGitにcommitしてしまう
DBパスワードやAPIキーを.tfvarsに書いてリポジトリにpushするのは重大なセキュリティ事故です。.gitignoreに*.tfvarsと*.tfvars.jsonを追加し、シークレットは必ず外部ストアから取得してください。# .gitignore *.tfvars *.tfvars.json .terraform/ terraform.tfstate terraform.tfstate.backup .terraform.lock.hcl
3. defaultワークスペースをprod運用に使ってしまう
「defaultでapplyしたらenv:/プレフィックスが付かない」という点が落とし穴です。後からworkspaceを導入しようとすると、既存のtfstateをdefaultパスからenv:/prod/パスへ移行する作業が発生します。プロジェクト開始時点からworkspaceを作成しておくことをお勧めします。defaultワークスペースはあくまでTerraform自体のテスト・学習用に限定し、実運用では明示的に作成したworkspace(dev・stg・prod)のみを使うのが安全です。
4. -var-fileを複数指定したときの優先順位
-var-fileは複数回指定でき、後から指定したファイルが先に指定した値を上書きします。共通設定をbase.tfvarsに置き、環境固有の値でオーバーライドする設計も可能です。# 共通設定を先に読み、prod固有設定で上書きする $ terraform apply \ -var-file=environments/common.tfvars \ -var-file=environments/prod.tfvars
まとめ
workspaceと-var-fileを組み合わせた環境分離設計のポイントを整理します。| 役割 | 担当する仕組み | 具体的な内容 |
|---|---|---|
| tfstateの分離 | terraform workspace | dev/stg/prodでtfstateファイルを自動分離 |
| パラメータの分離 | -var-file | environments/*.tfvarsで環境ごとの変数を管理 |
| 環境名の参照 | terraform.workspace | タグやリソース名への環境名の埋め込み |
| 操作ミス防止 | Makefileまたはシェル関数 | workspace selectとvar-file指定を自動でセット |
| tfstateのS3パス | env:/{workspace}/key | S3バックエンド使用時に自動でパスが分かれる |
次のステップとして、CI/CDパイプラインでworkspace切り替えとvar-file指定を自動化し、GitHub Actionsから安全に各環境へデプロイするフローも参考にしてみてください。
・Terraformのtfstate管理とS3バックエンド設定|チーム運用で壊さないための基礎
・TerraformのHCL変数設計|variable・locals・output・data sourceで構成を整理する方法
・Terraformのlifecycleブロックで本番リソースを誤削除から守る方法
>> Terraform実践セミナーの詳細はこちら
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。
登録無料・いつでも解除できます