Terraformのworkspaceと-var-fileで環境を分離する方法|dev・stg・prodを1つのコードで管理する設計

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Terraform > Terraformのworkspaceと-var-fileで環境を分離する方法|dev・stg・prodを1つのコードで管理する設計
「devのつもりでterraform applyしたら、prodのEC2を上書きしてしまった」
「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」が最多事故パターンで対策が必要


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

Terraformで複数環境を管理する前に知っておくこと

「Makefileでmake dev-applymake 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

workspaceには組み込み変数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(変数宣言)では、型と説明を明示します。デフォルト値は設定しないのがおすすめです。-var-fileを必ず指定させることで、「どの環境の設定で動かしているか」を常に意識させられます。

# 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には開発環境の値を記述します。

# 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には本番環境の値を記述します。

# environments/prod.tfvars instance_type = "m5.large" db_instance_class = "db.m5.large" min_capacity = 3 max_capacity = 10 domain = "example.com"

機密情報(DBパスワード・APIキー等)は.tfvarsに書かず、AWS Systems Manager Parameter StoreやHashiCorp Vaultから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

「workspace selectとvar-fileのペアを毎回手で入力するのはミスが怖い」という場合は、Makefileでラップするのが定番です。

# 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つのアプローチを役割で分けるのがポイントです。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、Terraform workspaceとvar-file設計から、CI/CDパイプラインでのマルチ環境デプロイまで、ハンズオン形式で体系的に学べるセミナーを開催しています。
>> 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バックエンド使用時に自動でパスが分かれる
workspaceはtfstateを分離し、-var-fileはパラメータを分離します。この2つを明確に役割分担させることで、1セットのHCLコードでdev・stg・prodを安全に管理できます。コード内の条件分岐を最小限に抑えつつ、環境ごとの差分を.tfvarsファイルで宣言的に管理するのが現場で長く使えるIaC設計の基本です。

次のステップとして、CI/CDパイプラインでworkspace切り替えとvar-file指定を自動化し、GitHub Actionsから安全に各環境へデプロイするフローも参考にしてみてください。

Terraformのtfstate管理とS3バックエンド設定|チーム運用で壊さないための基礎
TerraformのHCL変数設計|variable・locals・output・data sourceで構成を整理する方法
Terraformのlifecycleブロックで本番リソースを誤削除から守る方法
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、Terraform workspace環境分離設計から-var-fileを使ったマルチ環境管理まで、ハンズオン形式で体系的に学べるセミナーを開催しています。
>> Terraform実践セミナーの詳細はこちら

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。