핵심 요약
Terraform 2.0 실무의 핵심은 모듈 경계 설계와 state 분리 전략이다. 이 둘이 엉키면 팀 확장이 막힌다.
모듈 계층 3단
- Primitive: 단일 리소스 + 기본값 (예: s3-bucket)
- Composite: 여러 Primitive 조합 (예: web-app)
- Service: 환경 값 주입한 최종 배포 (예: app-prod)
팀원 5명 이하는 2단이면 충분하다. 과도한 추상화는 독.
모듈 설계 규칙
- 출력(outputs)은 소비자가 필요한 것만. 내부 구현 세부 노출 금지.
- 입력(variables)은 기본값으로 안전망. 필수 입력은 최소화.
- 리소스 네이밍은
var.name_prefix강제 - 태그는
default_tags(provider)로 일원화
state 분리 기준
state는 "같이 apply되는가" 기준으로 쪼갠다.
- 공유 인프라(VPC, Route53): 별도 state
- 환경별(prod/stage): 반드시 분리
- 서비스별: 팀 경계에 따라 분리
- 실수 폭발 반경을 항상 한 팀 범위로 제한
state 백엔드 구성
terraform {
backend "s3" {
bucket = "tf-state-prod"
key = "services/api/terraform.tfstate"
region = "ap-northeast-2"
dynamodb_table = "tf-locks"
encrypt = true
}
}
CI 파이프라인
# .github/workflows/terraform.yml
jobs:
plan:
steps:
- uses: hashicorp/setup-terraform@v3
- run: terraform fmt -check -recursive
- run: terraform init
- run: terraform validate
- run: terraform plan -out=tfplan
- uses: actions/upload-artifact@v4
with: { name: tfplan, path: tfplan }
apply:
if: github.ref == 'refs/heads/main'
needs: plan
environment: production # manual approval
steps:
- run: terraform apply tfplan
드리프트 탐지
terraform plan -detailed-exitcode
# exit 0 = 동일, 1 = 에러, 2 = 변경 감지
일 1회 cron으로 이 값을 체크해 Slack 알림. 손으로 만진 리소스 탐지.
import와 리팩터링
- 기존 리소스 가져오기:
import블록 (1.5+)으로 계획 단계 포함 - 리소스 이름 변경:
moved블록으로 파괴 없이 이동 - 모듈 대이동:
terraform state mv또는 moved 블록
실무 함정
- count vs for_each: 키가 의미 있으면 for_each. count는 중간 제거 시 인덱스 시프트.
- provider alias: 멀티 리전/계정은 provider alias + 모듈 전달 필수.
- 민감 출력:
sensitive = true로 plan 노출 방지. - 타깃 apply 남발 금지. state 일관성 파괴.
자주 묻는 질문
OpenTofu로 이관해야 하나?
라이선스 이슈가 결정 요인. 기능·생태계는 당분간 Terraform이 우위. 신규 프로젝트라면 양쪽 다 검토 가치 있다.
Pulumi와 비교?
팀이 코드(TS/Python)에 익숙하면 Pulumi가 DX 좋음. 선언성·커뮤니티 모듈은 Terraform이 우세.
댓글 0