데이터 엔지니어링 팀에서 Terraform을 도입할 때 가장 첫 번째로 마주하는 근본적인 질문이 있습니다.
"우리의 인프라 코드를 어떻게 구조화할 것인가?"
하나의 거대한 Terraform 프로젝트로 모든 것을 관리할 것인가, 아니면 작은 모듈들로 나누어 관리할 것인가?
이는 단순한 코드 구조 문제를 넘어서 팀의 협업 방식, 배포 전략, 그리고 장기적인 유지보수성까지 결정하는 중요한 아키텍처 결정입니다.
Monolithic 접근법: 하나로 통합하는 철학
Monlithic 접근법은 전체 데이터 인프라를 하나의 큰 Terraform 프로젝트로 관리하는 방식입니다.
모든 리소스가 단일 상태 파일에서 관리되며, 하나의 `terraform apply`명령으로 전체 인프라가 배포됩니다.
# monolithic-data-infra/
├── main.tf
├── variables.tf
├── outputs.tf
├── vpc.tf
├── s3.tf
├── redshift.tf
├── glue.tf
├── airflow.tf
└── monitoring.tf
장점
- 의존성 관리의 명확성
- 모든 리소스가 하나의 컨텍스트에 있기 때문에 리소스 간 의존성을 직접적으로 참조할 수 있습니다.
Redshift 클러스터가 VPC의 서브넷을 참조하고, Glue작업이 S3버킷을 참조하는 모든 관계가 명시적으로 드러납니다.
- 모든 리소스가 하나의 컨텍스트에 있기 때문에 리소스 간 의존성을 직접적으로 참조할 수 있습니다.
resource "aws_redshift_cluster" "data_warehouse" {
cluster_identifier = "main-dw"
subnet_group_name = aws_redshift_subnet_group.main.name
vpc_security_group_ids = [aws_security_group.redshift.id]
}
- 배포의 일관성
- 전체 인프라가 하나의 단위로 배포되기 때문에 부분적 배포로 인한 불일치 상태를 피할 수 있습니다.
모든 변경사항이 원자적으로 (atomically) 적용되거나 실패합니다.
- 전체 인프라가 하나의 단위로 배포되기 때문에 부분적 배포로 인한 불일치 상태를 피할 수 있습니다.
- 상태 관리의 단순성
- 하나의 상태 파일만 관리하면 되므로 상태 파일 간 동기화 문제나 분산 상태 관리의 복잡성을 피할 수 있습니다.
단점
- 폭발 반경의 확대
- 하나의 실수가 전체 인프라에 영향을 미칠 수 있습니다.
개발자가 실수로 프로덕션 데이터베이스 설정을 변경했다가 전체 데이터 파이프라인이 중단될 수 있습니다.
- 하나의 실수가 전체 인프라에 영향을 미칠 수 있습니다.
- 협업의 병목
- 여러 팀원이 동시에 작업을 할 때 상태 파일 잠금으로 인한 대기시간이 발생합니다.
한 사람이 인프라 변경을 진행하는 동안 다른 팀원들은 기다려야 합니다.
- 여러 팀원이 동시에 작업을 할 때 상태 파일 잠금으로 인한 대기시간이 발생합니다.
- 배포 시간의 증가
- 전체 인프라를 대상으로 `terraform plan`을 실행하면 수백 개의 리소스를 확인해야 하므로 계획 수립 시간이 기하급수적으로 늘어납니다.
Modular 접근법: 분할 정복의 철학
Modular 접근법은 인프라를 논리적 단위로 분할하여 각각을 독립적인 Terraform 모듈로 관리하는 방식입니다.
각 모듈은 자체 상태 파일을 가지며, 필요에 따라 다른 모듈의 출력을 참조합니다.
# modular-data-infra/
├── modules/
│ ├── networking/
│ ├── storage/
│ ├── compute/
│ ├── data-warehouse/
│ └── orchestration/
├── environments/
│ ├── dev/
│ ├── staging/
│ └── prod/
└── shared/
└── global/
장점
- 격리된 실패 범위
- 각 모듈이 독립적으로 관리되므로 한 모듈의 문제가 다른 모듈에 직접적인 영향을 미치지 않습니다.
스토리지 모듈의 변경이 컴퓨팅 모듈에 영향을 주지 않습니다.
- 각 모듈이 독립적으로 관리되므로 한 모듈의 문제가 다른 모듈에 직접적인 영향을 미치지 않습니다.
- 병렬 개발 가능
- 각 팀이 담당하는 모듈을 독립적으로 개발하고 배포할 수 있습니다.
데이터 웨어하우스 팀과 스트리밍 팀이 동시에 각자의 인프라를 수정할 수 있습니다.
- 각 팀이 담당하는 모듈을 독립적으로 개발하고 배포할 수 있습니다.
- 재사용성과 표준화
- 잘 설계된 모듈은 다양한 환경과 프로젝트에서 재사용할 수 있습니다.
표준화된 VPC 모듈을 개발, 스테이징, 프로덕션 환경에서 동일하게 사용할 수 있습니다.
- 잘 설계된 모듈은 다양한 환경과 프로젝트에서 재사용할 수 있습니다.
module "vpc" {
source = "../../modules/networking"
environment = "prod"
cidr_block = "10.0.0.0/16"
enable_nat_gateway = true
enable_vpn_gateway = false
}
단점
- 의존성 관리의 복잡화
- 모듈 간 읜존성을 명시적으로 관리해야 합니다.
데이터 소스나 원격 상태를 통해 다른 모듈의 출력을 참조해야 하므로 코드가 복잡해집니다.
- 모듈 간 읜존성을 명시적으로 관리해야 합니다.
data "terraform_remote_state" "vpc" {
backend = "s3"
config = {
bucket = "company-terraform-state"
key = "networking/vpc/terraform.tfstate"
region = "us-west-2"
}
}
- 상태 관리의 복잡성
- 여러 상태 파일을 관리해야 하므로 백업, 복구, 동기화 등이 복잡해집니다.
상태 파일 간 참조가 깨질 위험도 있습니다.
- 여러 상태 파일을 관리해야 하므로 백업, 복구, 동기화 등이 복잡해집니다.
- 초기 설정 비용
- 모듈 구조를 설계하고 구현하는데 상당한 시간과 노력이 필요합니다.
작은 팀에서는 과도환 엔지니어링이 될 수 있습니다.
- 모듈 구조를 설계하고 구현하는데 상당한 시간과 노력이 필요합니다.
팀 규모별 적합한 전략
스타트업 단계 (2~5명 팀)
- 권장 : Monolithic 접근법
- 스타트업에서는 빠른 개발과 단순화 운영이 핵심입니다.
팀 규모가 작고 인프라도 상대적으로 단순하므로 Monolithic 접근법이 적합합니다.
- 스타트업에서는 빠른 개발과 단순화 운영이 핵심입니다.
# startup-data-infra/main.tf
resource "aws_s3_bucket" "data_lake" {
bucket = "startup-data-lake"
}
resource "aws_glue_catalog_database" "main" {
name = "main_db"
}
resource "aws_glue_job" "etl" {
name = "main-etl"
role_arn = aws_iam_role.glue.arn
glue_version = "3.0"
command {
script_location = "s3://${aws_s3_bucket.data_lake.bucket}/scripts/etl.py"
}
}
이 단계에서는 복잡한 모듈 구조보다는 모든 리소스를 한눈에 볼 수 있는 단순함이 더 가치있습니다.
성장 단계 (10~20명 팀)
- 권장 : 하이브리드 접근법
- 팀이 커지고 인프라가 복잡해지기 시작하면 부분적으로 모듈화를 시작하는 것이 좋습니다.
핵심 인프라는 Monolithic으로 유지하되, 반복되는 패턴은 모듈로 추출합니다.
- 팀이 커지고 인프라가 복잡해지기 시작하면 부분적으로 모듈화를 시작하는 것이 좋습니다.
# hybrid-approach/
├── core-infrastructure.tf # VPC, IAM, 핵심 보안 설정
├── data-pipeline.tf # 메인 데이터 파이프라인
├── modules/
│ ├── glue-job/ # 재사용 가능한 Glue 작업 모듈
│ └── s3-bucket/ # 표준화된 S3 버킷 모듈
엔터프라이즈 단계 (20명 + 팀)
- 권장 : 완전한 Modular 접근법
- 여러 팀이 독립적으로 작업해야 하고, 복잡한 인프라를 관리해야 하는 단계에서는 완전한 모듈화가 필요합니다.
# enterprise-structure/
├── modules/
│ ├── foundation/ # 네트워킹, 보안 기반
│ ├── data-lake/ # 데이터 레이크 구성요소
│ ├── streaming/ # 실시간 스트리밍 인프라
│ ├── batch/ # 배치 처리 인프라
│ └── monitoring/ # 모니터링과 알럿
├── environments/
│ ├── dev/
│ ├── staging/
│ └── prod/
└── shared/
└── global/ # 전역 설정 (IAM, Route53)
하이브리드 전략 : 현실적 절충안
실제 운영에서는 순수한 Monolithic이나 Modular 접근법보다는 둘을 조합한 하이브리드 전략이 효과적인 경우가 많습니다.
계층별 분리 전략
1. Foundation Layer (Monolithic)
- VPC, IAM 역할, 보안 그룹 등 기반 인프라
- 변경 빈도가 낮고 안정성이 중요한 리소스
2. Application Layer (Modular)
- 데이터 파이프라인, 분석 도구 등 애플리케이션 레벨 리소스
- 변경 빈도가 높고 팀별로 독립적 관리가 필요한 리소스
# foundation/main.tf (Monolithic)
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "data-platform-vpc"
}
}
# applications/data-warehouse/main.tf (Modular)
data "terraform_remote_state" "foundation" {
backend = "s3"
config = {
bucket = "terraform-state"
key = "foundation/terraform.tfstate"
}
}
resource "aws_redshift_cluster" "main" {
vpc_security_group_ids = [
data.terraform_remote_state.foundation.outputs.redshift_security_group_id
]
}
환경별 분리 전략
각 환경(dev, staging, prod)을 별로 모듈로 관리하되, 환경 내에서는 monolithic 구조를 유지하는 방법도 효과적입니다.
의사결정 프레임워크
1. 팀 구조와 규모
- 팀 크기: 5명 미만이면 Monolithic, 10명 이상이면 Modular 고려
- 전문 영역: 팀이 기능별로 나뉘어 있다면 Modular가 적합
- 협업 패턴: 동시 작업이 많다면 Modular 필요
2. 인프라 복잡도
- 리소스 수: 100개 미만이면 Monolithic 가능, 그 이상이면 Modular 고려
- 의존성 복잡도: 순환 의존성이 많다면 신중한 모듈 설계 필요
- 변경 빈도: 자주 변경되는 부분은 모듈로 분리
3. 운영 요구사항
- 배포 빈도: 빈번한 배포가 필요하면 Modular가 유리
- 롤백 복잡도: 부분 롤백이 필요하면 Modular 필수
- 보안 요구사항: 격리가 중요하면 Modular 선택
4. 기술적 성숙도
- Terraform 경험: 초보자는 Monolithic으로 시작
- DevOps 프랙티스: CI/CD가 잘 구축되어 있으면 Modular 활용 가능
- 도구와 프로세스: 상태 관리 도구가 준비되었는지 확인
마이그레이션 전략 : 단계적 접근
Monolithic → Modular 마이그레이션
기존 Monolithic 구조를 Modular로 전환할 때는 단계적 접근이 필요합니다
1단계: 영향도가 낮은 부분부터 분리
# 모니터링 리소스 분리 예시
terraform state mv aws_cloudwatch_dashboard.main monitoring_module.aws_cloudwatch_dashboard.main
2단계: 안정화 후 핵심 리소스 분리 3단계: 환경별 분리 적용
- 주의사항과 리스크 관리
- 상태 파일 백업 : 마이그레이션 전 반드시 백업
- 점진적 적용 :한 번에 모든 것을 바꾸지 말고 단계별 진행
- 테스트 환경 우선 : 개발 환경에서 먼저 검증 후 적용
결론 : 상황에 맞는 전략 선택
Monolithic과 Modular 접근법 중 어떤 것이 "정답"인지에 대한 일률적인 답은 없습니다. 중요한 것은 현재 팀의 상황과 미래의 성장 계획을 고려하여 적절한 전략을 선택하고, 필요에 따라 유연하게 전환할 수 있는 능력을 갖추는 것입니다.
작은 팀과 단순한 인프라에서는 Monolithic의 단순함이 더 큰 가치를 제공합니다. 큰 팀과 복잡한 인프라에서는 Modular의 유연성과 격리성이 필수적입니다.
가장 현실적인 접근법은 Monolithic으로 시작해서 팀과 인프라가 성장함에 따라 점진적으로 Modular 구조로 전환하는 것입니다. 이 과정에서 팀의 역량도 함께 성장하고, 각 단계에서 최적의 구조를 찾아갈 수 있습니다.
'Data Engineer' 카테고리의 다른 글
| Apache Airflow란? (3) | 2025.07.29 |
|---|---|
| Data Driven 이란? (3) | 2025.07.28 |
| 메타데이터 관리 전략: SSOT vs Federated, 무엇이 정답일까? (1) | 2025.07.18 |
| PySpark에서 NULL이 많을 때 filter가 안 먹히는 이유 (0) | 2025.04.24 |
| '정규화(Normalization)'를 과도하게 적용하면 Spark 성능이 저하될까? (0) | 2025.04.24 |
