왜 Terraform Workspace를 정확히 이해해야 하는가
Terraform을 사용하는 팀이 가장 먼저 부딪히는 질문은 “dev/staging/prod 환경을 어떻게 분리할 것인가”입니다. 많은 팀이 Terraform CLI의 Workspace 기능을 환경 분리 도구로 사용하지만, 공식 문서는 이에 대해 명확한 경고를 합니다.
이 글에서는 Terraform 공식 문서를 기준으로 Workspace의 실제 동작 원리를 파악하고, 언제 써야 하고 언제 쓰지 말아야 하는지, 그리고 환경 분리에 적합한 대안 구조를 다룹니다.
1. Workspace의 실제 동작: 같은 설정, 다른 State
공식 문서에 따르면, CLI Workspace는 “같은 Terraform 작업 디렉터리 안에서 별도의 State 데이터 인스턴스”입니다. 핵심은 설정(Configuration)이 하나이고, State만 분리된다는 점입니다.
# Workspace 기본 명령어
terraform workspace list # 현재 워크스페이스 목록
terraform workspace new staging # 새 워크스페이스 생성
terraform workspace select prod # 워크스페이스 전환
terraform workspace delete staging # 삭제
동작 원리:
- 모든 초기화된 작업 디렉터리는
default워크스페이스로 시작하며, 이 워크스페이스는 삭제할 수 없습니다. - 새 워크스페이스에서
terraform plan을 실행하면, 다른 워크스페이스의 리소스에 접근하지 않습니다. 해당 리소스는 물리적으로 존재하지만, 관리하려면 워크스페이스를 전환해야 합니다. - 로컬 State의 경우
terraform.tfstate.d/디렉터리에 워크스페이스별 State가 저장됩니다. - 원격 백엔드(S3, GCS 등)의 경우 워크스페이스 이름이 State 경로에 추가됩니다.
설정 내에서 terraform.workspace로 현재 워크스페이스 이름을 참조할 수 있습니다:
resource "aws_instance" "web" {
# default 워크스페이스에서는 5대, 그 외에는 1대
count = terraform.workspace == "default" ? 5 : 1
tags = {
Name = "web-${terraform.workspace}"
Environment = terraform.workspace
}
}
2. 공식 문서의 경고: Workspace를 쓰지 말아야 할 때
Terraform 공식 문서는 두 곳에서 일관되게 다음을 강조합니다:
“Workspaces are not appropriate for system decomposition or deployments requiring separate credentials and access controls.”
— Terraform 공식 문서 (State: Workspaces)
“Organizations commonly want to create a strong separation between multiple deployments of the same infrastructure serving different development stages or different internal teams. In this case, the backend for each deployment often has different credentials and access controls. CLI workspaces within a working directory use the same backend, so they are not a suitable isolation mechanism for this scenario.”
— Terraform 공식 문서 (CLI Workspaces)
요약하면:
| 상황 | Workspace 적합? | 이유 |
|---|---|---|
| 기능 브랜치에서 테스트용 인프라 복제 | ✓ 적합 | 같은 백엔드·자격증명, 임시 복사본 |
| dev/staging/prod 환경 분리 | ✗ 부적합 | 환경별 자격증명·접근제어 분리 불가 |
| 마이크로서비스별 인프라 분리 | ✗ 부적합 | 시스템 분해(decomposition)는 별도 설정이 적합 |
| 다른 팀이 관리하는 인프라 | ✗ 부적합 | 팀별 접근제어·State 격리 필요 |
3. Workspace의 실제 적합한 사용 사례
공식 문서가 제시하는 적합한 사용 사례는 “기능 브랜치에서 임시 인프라를 복제하여 테스트”하는 패턴입니다:
default워크스페이스는 main/trunk 브랜치에 대응 — 프로덕션 인프라의 의도된 상태- 개발자가 기능 브랜치를 만들 때 대응하는 워크스페이스도 생성
- 임시 워크스페이스에 메인 인프라의 복사본을 배포하여 변경사항을 테스트
- 변경이 merge되고 default 워크스페이스에 배포되면, 테스트 인프라를 destroy하고 임시 워크스페이스를 삭제
# 기능 브랜치 작업 흐름
git checkout -b feature/new-api
terraform workspace new feature-new-api
# 테스트 인프라 배포 (축소 버전)
terraform apply -var="instance_count=1"
# 테스트 완료 후 정리
terraform destroy
terraform workspace select default
terraform workspace delete feature-new-api
git checkout main
4. 환경 분리의 권장 대안: 디렉터리 + 모듈 구조
공식 문서는 환경 분리에 대해 “재사용 가능한 모듈로 공통 요소를 표현하고, 각 인스턴스를 별도 설정(Configuration)으로 관리”하는 것을 권장합니다.
디렉터리 구조 예시
infrastructure/
├── modules/
│ ├── vpc/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ ├── eks-cluster/
│ └── rds/
├── environments/
│ ├── dev/
│ │ ├── main.tf # 모듈 호출 + dev 백엔드
│ │ ├── backend.tf # dev 전용 S3 버킷/DynamoDB
│ │ ├── terraform.tfvars # dev 변수 값
│ │ └── providers.tf # dev AWS 자격증명
│ ├── staging/
│ │ ├── main.tf
│ │ ├── backend.tf # staging 전용 백엔드
│ │ ├── terraform.tfvars
│ │ └── providers.tf # staging 자격증명
│ └── prod/
│ ├── main.tf
│ ├── backend.tf # prod 전용 백엔드
│ ├── terraform.tfvars
│ └── providers.tf # prod 자격증명 (별도 IAM 역할)
환경별 루트 모듈 (environments/dev/main.tf)
module "vpc" {
source = "../../modules/vpc"
cidr_block = var.vpc_cidr
environment_name = "dev"
az_count = 2 # dev는 2개 AZ만
}
module "eks" {
source = "../../modules/eks-cluster"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
node_count = var.eks_node_count # dev: 2, prod: 6
instance_type = var.eks_instance_type # dev: t3.medium, prod: m5.xlarge
}
module "rds" {
source = "../../modules/rds"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.database_subnet_ids
instance_class = var.rds_instance_class
multi_az = var.environment == "prod" ? true : false
}
장점 비교
| 비교 항목 | Workspace 방식 | 디렉터리 + 모듈 방식 |
|---|---|---|
| State 격리 | 같은 백엔드, 경로만 분리 | 완전히 별도 백엔드 |
| 자격증명 분리 | 불가 (같은 백엔드 사용) | 환경별 독립 자격증명 |
| 접근 제어(IAM) | 같은 정책 | 환경별 다른 IAM 역할/정책 |
| 설정 차이 | terraform.workspace 조건문 |
terraform.tfvars로 명시적 |
| 실수로 prod 변경 위험 | 높음 (workspace select 실수) | 낮음 (별도 디렉터리에서 apply) |
| CI/CD 파이프라인 | workspace 전환 단계 필요 | 디렉터리 지정만으로 환경 결정 |
| 코드 중복 | 최소 (하나의 설정) | 루트 모듈만 중복 (모듈로 공유) |
5. 환경 간 데이터 공유: terraform_remote_state
별도 설정으로 환경을 분리하면, 한 환경의 출력값(예: VPC ID)을 다른 설정에서 참조해야 할 때가 있습니다. 공식 문서는 terraform_remote_state 데이터 소스를 제시합니다:
# environments/staging/data.tf
# shared-infra 설정의 출력값 참조
data "terraform_remote_state" "shared" {
backend = "s3"
config = {
bucket = "mycompany-terraform-shared"
key = "shared-infra/terraform.tfstate"
region = "ap-northeast-2"
}
}
# 참조 사용
resource "aws_instance" "app" {
subnet_id = data.terraform_remote_state.shared.outputs.private_subnet_id
}
공식 문서는 이 방식이 “설정 간 더 긴밀한 결합(tighter coupling)을 만든다”고 안내하며, 대안으로 DNS 레코드, 태깅 컨벤션, Consul KV 등을 제시합니다.
6. 실전 체크리스트: 환경 분리 설계 의사결정
| # | 질문 | Yes → 권장 | No → 권장 |
|---|---|---|---|
| 1 | 환경별 AWS 계정/자격증명이 다른가? | 디렉터리 분리 | Workspace 고려 가능 |
| 2 | 환경별 접근 제어(IAM)가 다른가? | 디렉터리 분리 | Workspace 고려 가능 |
| 3 | prod에 대한 변경 승인 프로세스가 필요한가? | 디렉터리 분리 (별도 CI/CD) | 어느 쪽이든 |
| 4 | 기능 브랜치에서 임시 테스트 인프라가 필요한가? | Workspace | 해당 없음 |
| 5 | 팀 규모가 3명 이상이고 동시 작업하는가? | 디렉터리 분리 (State 충돌 최소화) | 어느 쪽이든 |
7. 흔한 실수와 방지법
실수 1: workspace select를 잊고 prod에 apply
증상: dev에서 작업하려 했는데 prod 리소스가 변경됨
원인: 이전 세션에서 prod workspace를 선택한 채 터미널을 닫음
방지:
- CI/CD에서 workspace 대신 디렉터리 구조 사용
- 셸 프롬프트에 현재 workspace 표시:
export PS1="[tf:$(terraform workspace show)] $PS1" terraform plan출력에서 항상 리소스 이름의 환경 접두사를 확인
실수 2: workspace로 환경을 분리했더니 State 백엔드 권한이 동일
증상: 주니어 개발자가 prod workspace에서 destroy 실행
원인: 같은 백엔드를 사용하므로 모든 workspace에 동일한 권한
해결: 디렉터리 분리 + 환경별 IAM 역할로 전환
실수 3: terraform.workspace 조건문이 복잡해져서 유지보수 불가
# ❌ 안티패턴: workspace 분기가 설정 전체에 퍼짐
resource "aws_rds_instance" "db" {
instance_class = terraform.workspace == "prod" ? "db.r5.2xlarge" :
terraform.workspace == "staging" ? "db.r5.large" : "db.t3.medium"
multi_az = terraform.workspace == "prod" ? true : false
# ... 이런 조건이 수십 개
}
# ✓ 대안: terraform.tfvars로 환경 차이를 변수화
# environments/prod/terraform.tfvars
rds_instance_class = "db.r5.2xlarge"
rds_multi_az = true
# environments/dev/terraform.tfvars
rds_instance_class = "db.t3.medium"
rds_multi_az = false
마무리
Terraform Workspace는 강력하지만 범위가 제한된 도구입니다. 공식 문서가 반복적으로 경고하듯, 환경 분리(dev/staging/prod)에는 적합하지 않습니다. Workspace는 기능 브랜치의 임시 인프라 복제에 사용하고, 환경 분리는 디렉터리 + 모듈 구조로 설계하세요. 이 구조는 코드 중복을 최소화하면서도 자격증명·접근제어·State를 완전히 분리할 수 있습니다.