Terraform Workspace とは? – 複数環境管理の新標準
Terraform Workspaceは、同一のTerraformコード構成から複数の異なるインフラ環境を管理するための機能です。開発(dev)、ステージング(staging)、本番(prod)といった複数の環境を、コードの重複なく効率的に管理できます。
workspace が解決する 3 つの課題
- コード管理の複雑さ
- 従来:環境ごとに異なるディレクトリやリポジトリが必要
- 解決後:同一コードベースで複数環境を管理可能
- メリット:コードの一元管理による保守性向上
- リソース分離の確実性
- 従来:環境の分離にタグや命名規則のみを使用
- 解決後:workspace単位で完全な論理分離を実現
- メリット:誤った環境へのデプロイを防止
- 状態管理の煩雑さ
- 従来:環境ごとに異なるstate fileを手動管理
- 解決後:workspaceが自動的にstate管理を実施
- メリット:状態管理の自動化によるヒューマンエラー防止
従来の環境管理との比較
| 管理項目 | 従来の方式 | Workspace方式 | メリット |
|---|---|---|---|
| コード管理 | 環境ごとにディレクトリ作成 | 単一コードで複数環境 | メンテナンス工数削減 |
| 環境分離 | 命名規則による論理分離 | workspace単位の完全分離 | セキュリティ向上 |
| 設定値管理 | 環境変数やファイル | workspace変数 | 一元管理が容易 |
| デプロイ管理 | 手動での環境選択 | workspaceでの自動制御 | オペレーションミス防止 |
実務での具体的な活用例:
# workspace変数を使用した環境別設定
locals {
env = terraform.workspace
instance_type = {
default = "t2.micro"
staging = "t2.medium"
production = "t2.large"
}
}
resource "aws_instance" "app_server" {
instance_type = local.instance_type[local.env]
tags = {
Environment = local.env
}
}
この方式により、同一のコードベースから環境に応じた適切なリソースをデプロイできます。コードの重複を避けながら、各環境の要件に合わせたカスタマイズが可能となります。
Terraform Workspace の基本的な使い方
workspace 作成から削除までの流れ
基本的なworkspaceのライフサイクル管理コマンド:
# 現在のworkspace一覧を表示 $ terraform workspace list * default # 新しいworkspaceの作成 $ terraform workspace new staging Created and switched to workspace "staging"! # workspace切り替え $ terraform workspace select production # workspace削除(すべてのリソースが破棄された後のみ可能) $ terraform workspace delete staging
環境変数の便利な使い方
workspaceに応じた設定値の管理方法:
# variables.tf
variable "instance_sizes" {
type = map(string)
default = {
default = "t2.micro"
staging = "t2.medium"
production = "t2.large"
}
}
# main.tf
resource "aws_instance" "web" {
instance_type = var.instance_sizes[terraform.workspace]
tags = {
Name = "${terraform.workspace}-web-server"
Environment = terraform.workspace
}
}
環境変数による制御:
# 環境別の変数設定 $ export TF_WORKSPACE=staging $ export TF_VAR_region="ap-northeast-1" # 特定環境のみで実行する場合の条件分岐 $ [ "$TF_WORKSPACE" = "production" ] && terraform apply
状態管理の基礎知識
状態ファイルの管理ベストプラクティス:
- バックエンド設定
terraform {
backend "s3" {
bucket = "terraform-states"
key = "project/terraform.tfstate"
region = "ap-northeast-1"
# workspace毎に異なるDynamoDBテーブルでロック管理
dynamodb_table = "terraform-locks"
}
}
- 状態の確認方法
# 現在の状態を確認 $ terraform show # 状態ファイルのバックアップ $ terraform state pull > backup.tfstate # 特定リソースの状態確認 $ terraform state list $ terraform state show aws_instance.web
- 状態管理の重要ポイント
| 項目 | 推奨設定 | 理由 |
|---|---|---|
| バックエンド | S3 + DynamoDB | 状態の永続化とロック機能 |
| 暗号化 | 必須 | セキュリティ確保 |
| バージョニング | 有効 | 復旧可能性の確保 |
| アクセス制御 | IAMポリシー | 権限の最小化 |
これらの基本操作を理解することで、複数環境の効率的な管理が可能になります。特に本番環境では、状態管理の設定を慎重に行うことが重要です。
実践的なWorkspace活用術
本番・ステージング・開発環境の分離
# environments/main.tf
locals {
environment_config = {
default = {
instance_type = "t2.micro"
instance_count = 1
backup_retention = 7
}
staging = {
instance_type = "t2.medium"
instance_count = 2
backup_retention = 14
}
production = {
instance_type = "t2.large"
instance_count = 3
backup_retention = 30
}
}
config = local.environment_config[terraform.workspace]
}
resource "aws_instance" "app" {
count = local.config.instance_count
instance_type = local.config.instance_type
lifecycle {
prevent_destroy = terraform.workspace == "production"
}
}
環境ごとの設定値管理テクニック
- 階層化された変数管理
# config/common.tfvars
region = "ap-northeast-1"
project = "microservice-app"
# config/production.tfvars
environment = "production"
vpc_cidr = "10.0.0.0/16"
enable_monitoring = true
# 実行コマンド
terraform plan \
-var-file="config/common.tfvars" \
-var-file="config/${terraform.workspace}.tfvars"
- 条件付きリソースプロビジョニング
resource "aws_cloudwatch_metric_alarm" "high_cpu" {
count = terraform.workspace == "production" ? 1 : 0
alarm_name = "${terraform.workspace}-high-cpu"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
threshold = "80"
}
バックエンドの共有戦略
- workspace対応のバックエンド設定
terraform {
backend "s3" {
bucket = "company-terraform-states"
key = "microservices/terraform.tfstate"
region = "ap-northeast-1"
encrypt = true
dynamodb_table = "terraform-locks"
workspace_key_prefix = "environments" # 環境ごとに異なるキープレフィックス
}
}
- 状態共有のベストプラクティス
| 共有項目 | 推奨設定 | 注意点 |
|---|---|---|
| State格納 | 環境別のS3パス | キーの重複防止 |
| ロック管理 | 共通DynamoDBテーブル | テーブル名の標準化 |
| 暗号化 | KMSによる暗号化 | 鍵の権限管理 |
| アクセス制御 | IAMロール制御 | 最小権限の原則 |
- 実装例:環境別の状態分離
# backends/workspace.tf
data "terraform_remote_state" "shared" {
backend = "s3"
config = {
bucket = "company-terraform-states"
key = "environments/${terraform.workspace}/shared.tfstate"
region = "ap-northeast-1"
}
}
# 共有リソースの参照
resource "aws_security_group" "app" {
vpc_id = data.terraform_remote_state.shared.outputs.vpc_id
tags = {
Environment = terraform.workspace
ManagedBy = "terraform"
}
}
このアプローチにより、環境分離とリソース共有の両立が実現できます。
Workspace のベストプラクティス
命名規則とタグ付けの標準化
locals {
standard_tags = {
Environment = terraform.workspace
Project = var.project_name
ManagedBy = "terraform"
Team = var.team_name
CostCenter = var.cost_center
}
}
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
tags = merge(
local.standard_tags,
{
Name = "${terraform.workspace}-main-vpc"
}
)
}
命名規則ガイドライン:
| 要素 | パターン | 例 |
|---|---|---|
| Workspace名 | {env}-{region}-{purpose} | prod-ap-northeast-1-app |
| リソース名 | {workspace}-{resource}-{count} | prod-web-server-01 |
| タグキー | PascalCase | CostCenter, Environment |
アクセス制御とセキュリティ対策
- IAMポリシー設定
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetObject",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::terraform-states",
"arn:aws:s3:::terraform-states/environments/${aws:username}/*"
],
"Condition": {
"StringEquals": {
"aws:RequestedWorkspace": ["staging", "development"]
}
}
}
]
}
- 環境別のセキュリティ制御
resource "aws_security_group" "app" {
name = "${terraform.workspace}-app-sg"
dynamic "ingress" {
for_each = terraform.workspace == "production" ? ["10.0.0.0/8"] : ["0.0.0.0/0"]
content {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = [ingress.value]
}
}
}
コスト最適化のためのワークスペース設計
- 環境別リソースサイジング
locals {
sizing = {
development = {
instance_type = "t3.micro"
autoscaling = {
min = 1
max = 2
}
}
production = {
instance_type = "t3.large"
autoscaling = {
min = 2
max = 10
}
}
}
}
resource "aws_autoscaling_group" "app" {
min_size = local.sizing[terraform.workspace].autoscaling.min
max_size = local.sizing[terraform.workspace].autoscaling.max
instance_type = local.sizing[terraform.workspace].instance_type
lifecycle {
create_before_destroy = true
}
}
- コスト管理ポリシー
resource "aws_budgets_budget" "cost_limit" {
count = terraform.workspace == "production" ? 1 : 0
name = "${terraform.workspace}-monthly-budget"
budget_type = "COST"
limit_amount = terraform.workspace == "production" ? "1000" : "100"
limit_unit = "USD"
time_period_start = "2024-01-01_00:00"
time_unit = "MONTHLY"
notification {
comparison_operator = "GREATER_THAN"
threshold = 80
threshold_type = "PERCENTAGE"
notification_type = "FORECASTED"
}
}
セキュリティとコスト最適化のチェックリスト:
- [ ] 環境別のIAMロールを使用
- [ ] S3バケットの暗号化を有効化
- [ ] セキュリティグループの制限を環境別に設定
- [ ] 自動スケーリングの上限を環境別に制御
- [ ] コストアラートを適切なしきい値で設定
- [ ] 未使用リソースの自動停止を設定
よくあるトラブルと解決策
stateロックのキャッシュ解消法
- ロック解除手順
# ロック状態の確認
$ terraform force-unlock -force LOCK_ID
# DynamoDBのロックエントリ確認
$ aws dynamodb get-item \
--table-name terraform-locks \
--key '{"LockID": {"S": "terraform-state/workspace-name"}}'
ロックトラブル対策:
terraform {
backend "s3" {
dynamodb_table = "terraform-locks"
lock_timeout = "5m"
# エラー時の再試行設定
retry_max = 5
retry_wait_min = 5
}
}
環境中の設定漏れ防止策
- 変数検証の実装
variable "environment_type" {
type = string
description = "Environment type (production/staging/development)"
validation {
condition = contains(["production", "staging", "development"], var.environment_type)
error_message = "環境タイプは production, staging, development のいずれかである必要があります。"
}
}
locals {
required_tags = {
Environment = terraform.workspace
Owner = var.owner
CostCenter = var.cost_center
}
# タグの存在チェック
validate_tags = [
for required_key in keys(local.required_tags) :
contains(keys(var.tags), required_key)
]
}
- 自動チェック用のnull_resource
resource "null_resource" "validation" {
count = terraform.workspace == "production" ? 1 : 0
lifecycle {
precondition {
condition = var.backup_retention_days >= 30
error_message = "本番環境ではバックアップ保持期間は30日以上必要です。"
}
}
}
リソース依存関係の管理方法
- 明示的な依存関係定義
# 依存関係の明示的な定義
resource "aws_instance" "web" {
depends_on = [aws_vpc.main, aws_subnet.public]
instance_type = "t3.micro"
subnet_id = aws_subnet.public.id
lifecycle {
create_before_destroy = true
prevent_destroy = terraform.workspace == "production"
}
}
# データソースを使用した依存関係管理
data "terraform_remote_state" "vpc" {
backend = "s3"
config = {
bucket = "terraform-states"
key = "vpc/${terraform.workspace}/terraform.tfstate"
}
}
- モジュール間の依存関係制御
module "database" {
source = "./modules/database"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
providers = {
aws = aws.primary
}
}
# クロスリージョン依存関係
provider "aws" {
alias = "dr"
region = "ap-northeast-2"
}
module "dr_database" {
source = "./modules/database"
providers = {
aws = aws.dr
}
depends_on = [module.database]
}
トラブルシューティングチェックリスト:
- [ ] State lockが残っていないか確認
- [ ] バックエンドの接続設定を確認
- [ ] 必須タグの設定漏れがないか確認
- [ ] リソース間の依存関係が適切か確認
- [ ] ライフサイクル設定が環境に適しているか確認