workspace — 同一コードで複数環境を管理する(と落とし穴)

1. 概要

  • terraform workspaceとは何か
  • workspaceの作成・切り替え・削除
  • terraform.workspace変数で環境を判定する
  • workspaceを使う場合と使わない場合の判断基準
  • 落とし穴と代替パターン

terraform workspaceは、同一のTerraformコードから複数の独立したstateを管理する機能です。devstgprdといった複数環境を1つのコードベースで管理できます。


2. 基本コマンド

# workspaceの一覧表示(*が現在のworkspace)
$ terraform workspace list
* default
  dev
  stg

# 新しいworkspaceを作成して切り替え
$ terraform workspace new dev

# workspaceを切り替え
$ terraform workspace select prd

# 現在のworkspaceを確認
$ terraform workspace show
prd

# workspaceを削除(切り替えてから削除)
$ terraform workspace select default
$ terraform workspace delete dev

3. terraform.workspace変数で環境を判定する

terraform {
  required_version = ">= 1.9"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

# terraform.workspaceでworkspace名を取得
locals {
  environment   = terraform.workspace
  is_production = terraform.workspace == "prd"

  instance_type = {
    default = "t3.micro"
    dev     = "t3.micro"
    stg     = "t3.small"
    prd     = "t3.medium"
  }

  volume_size = local.is_production ? 100 : 20
}

data "aws_ami" "amazon_linux_2023" {
  most_recent = true
  owners      = ["amazon"]
  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }
}

resource "aws_instance" "web" {
  ami           = data.aws_ami.amazon_linux_2023.id
  instance_type = lookup(local.instance_type, local.environment, local.instance_type["default"])

  root_block_device {
    volume_size = local.volume_size
    volume_type = "gp3"
    encrypted   = true
  }

  tags = {
    Name        = "${local.environment}-web"
    Environment = local.environment
    ManagedBy   = "terraform"
  }
}

resource "aws_s3_bucket" "app_data" {
  # workspaceごとに独立したバケット名
  bucket = "${local.environment}-myapp-data-${data.aws_caller_identity.current.account_id}"

  tags = {
    Name        = "${local.environment}-myapp-data"
    Environment = local.environment
    ManagedBy   = "terraform"
  }
}

data "aws_caller_identity" "current" {}

4. workspaceとstateの関係

workspaceを使うと、stateファイルがworkspace名ごとに分離されます。

# ローカルバックエンドの場合
terraform.tfstate.d/
  dev/
    terraform.tfstate
  stg/
    terraform.tfstate
  prd/
    terraform.tfstate

# S3バックエンドの場合
s3://my-bucket/
  env:/
    dev/
      terraform.tfstate
    stg/
      terraform.tfstate
  terraform.tfstate   ← defaultワークスペース

5. workspaceの落とし穴

❌ 問題1: コードの複雑化

terraform.workspaceで条件分岐が増えると、コードが読みにくくなります。

# 条件分岐が増えると管理が困難になる
instance_type = terraform.workspace == "prd" ? "t3.medium" : terraform.workspace == "stg" ? "t3.small" : "t3.micro"

❌ 問題2: 誤ったworkspaceでのapply

prd workspaceで作業しているつもりが dev workspaceだった、という事故が起きやすい。

❌ 問題3: モジュールとの相性

子モジュールは親のworkspaceを継承しますが、これが意図しない動作を生むことがあります。


6. workspaceの代替パターン

Terraformコミュニティでは、workspaceよりディレクトリ分離が推奨されています。

# ディレクトリ分離パターン(推奨)
environments/
  dev/
    main.tf       ← dev環境の設定
    terraform.tfvars
  stg/
    main.tf       ← stg環境の設定
    terraform.tfvars
  prd/
    main.tf       ← prd環境の設定
    terraform.tfvars
modules/
  compute/
    main.tf       ← 共通モジュール

7. workspaceを使うべき場面

向いている向いていない
短期的な機能ブランチのテスト長期的な複数環境の管理
同一インフラの一時的な複製dev/stg/prd の環境分離
個人開発での素早い切り替えチーム開発・CI/CD環境

8. 関連記事


9. まとめ

  • terraform workspaceで複数の独立したstateを同一コードで管理できる
  • terraform.workspace変数でworkspace名(環境名)を参照できる
  • stateはworkspaceごとに分離される
  • ただし、長期的な複数環境管理にはディレクトリ分離パターンが推奨
  • workspaceは「短期的なブランチテスト」や「一時的な複製」に向いている

動作確認バージョン: Terraform >= 1.9 公式ドキュメント: https://developer.hashicorp.com/terraform/cli/workspaces