의존성 이해: 암시적·명시적 의존성과 리소스 생성 순서
Terraform은 리소스 간 의존 관계를 파악해 올바른 순서로 생성/삭제합니다. 이 개념을 이해하면 “왜 이 리소스가 먼저 만들어지는가"를 설명할 수 있습니다.
암시적 의존성 (Implicit Dependency)
리소스 속성에서 다른 리소스를 참조하면, Terraform이 자동으로 의존 관계를 파악합니다.
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id # ← VPC ID를 참조 → 암시적 의존성 생성
cidr_block = "10.0.1.0/24"
}
resource "aws_instance" "web" {
ami = "ami-12345678"
instance_type = "t3.micro"
subnet_id = aws_subnet.public.id # ← 서브넷 참조 → 또 다른 암시적 의존성
}Terraform이 자동으로 파악하는 생성 순서:
aws_vpc.main먼저 생성aws_subnet.public생성 (VPC 필요)aws_instance.web생성 (서브넷 필요)
삭제 순서는 반대입니다:
aws_instance.web먼저 삭제aws_subnet.public삭제aws_vpc.main삭제
리소스 의존성 그래프
graph TD
VPC["aws_vpc.main\n10.0.0.0/16"]
IGW["aws_internet_gateway.main"]
SUBNET_PUB["aws_subnet.public\n10.0.1.0/24"]
SUBNET_PRV["aws_subnet.private\n10.0.10.0/24"]
RT_PUB["aws_route_table.public"]
SG["aws_security_group.web"]
EC2["aws_instance.web"]
RDS["aws_db_instance.main"]
VPC --> IGW
VPC --> SUBNET_PUB
VPC --> SUBNET_PRV
VPC --> SG
IGW --> RT_PUB
RT_PUB --> SUBNET_PUB
SUBNET_PUB --> EC2
SG --> EC2
SUBNET_PRV --> RDS
SG --> RDS
style VPC fill:#10b981,color:#fff
style EC2 fill:#3b82f6,color:#fff
style RDS fill:#ef4444,color:#fff
terraform graph 명령어로 실제 의존성 그래프를 시각화할 수 있습니다:
terraform graph | dot -Tsvg > graph.svg명시적 의존성: depends_on
속성 참조가 없지만 실행 순서를 보장해야 할 때 사용합니다.
# IAM 정책이 EC2에 연결된 후에 애플리케이션을 배포해야 할 때
resource "aws_iam_role_policy_attachment" "app_policy" {
role = aws_iam_role.app.name
policy_arn = aws_iam_policy.app.arn
}
resource "aws_instance" "app" {
ami = "ami-12345678"
instance_type = "t3.micro"
iam_instance_profile = aws_iam_instance_profile.app.name
# IAM 정책이 완전히 연결된 후 EC2 생성
depends_on = [aws_iam_role_policy_attachment.app_policy]
}depends_on이 필요한 경우:
- IAM 권한이 완전히 적용된 후 리소스 생성 필요
- 데이터베이스가 준비된 후 마이그레이션 리소스 실행
- S3 버킷 정책 설정 후 객체 업로드
depends_on은 최후의 수단입니다. 가능하면 리소스 참조(암시적 의존성)를 사용하세요.
depends_on은 Terraform이 의존성을 추론하지 못할 때만 사용합니다.실무 사례: VPC → Subnet → EC2 전체 구성
# 1. VPC (가장 먼저 생성)
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
}
# 2. 인터넷 게이트웨이 (VPC 생성 후)
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id # ← VPC 참조
}
# 3. 퍼블릭 서브넷 (VPC 생성 후)
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id # ← VPC 참조
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-2a"
map_public_ip_on_launch = true
}
# 4. 라우팅 테이블 (IGW 생성 후)
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id # ← IGW 참조
}
}
# 5. 라우팅 테이블 연결 (서브넷 + 라우팅 테이블 생성 후)
resource "aws_route_table_association" "public" {
subnet_id = aws_subnet.public.id # ← 서브넷 참조
route_table_id = aws_route_table.public.id # ← RT 참조
}
# 6. Security Group (VPC 생성 후)
resource "aws_security_group" "web" {
name = "web-sg"
vpc_id = aws_vpc.main.id # ← VPC 참조
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# 7. EC2 (서브넷 + SG 생성 후)
resource "aws_instance" "web" {
ami = "ami-12345678"
instance_type = "t3.micro"
subnet_id = aws_subnet.public.id # ← 서브넷 참조
vpc_security_group_ids = [aws_security_group.web.id] # ← SG 참조
}Terraform이 위 코드에서 자동으로 파악한 생성 순서:
aws_vpc.mainaws_internet_gateway.main,aws_subnet.public,aws_security_group.web(병렬 생성 가능)aws_route_table.publicaws_route_table_association.publicaws_instance.web
의존성 관련 자주 발생하는 문제
문제 1: 순환 의존성 (Circular Dependency)
# 잘못된 예: A가 B를 참조하고 B가 A를 참조
resource "aws_security_group" "a" {
ingress {
security_groups = [aws_security_group.b.id] # B 참조
}
}
resource "aws_security_group" "b" {
ingress {
security_groups = [aws_security_group.a.id] # A 참조 → 순환!
}
}오류: Error: Cycle: aws_security_group.a, aws_security_group.b
해결: Security Group Rule을 분리하거나, 하나의 SG만 먼저 생성 후 나머지를 참조.
문제 2: 삭제 순서 오류
Error: Error deleting VPC: DependencyViolation:
The vpc 'vpc-xxx' has dependencies and cannot be deleted.Terraform 외부(콘솔 등)에서 VPC 내에 리소스를 수동 생성했을 때 발생합니다.
해결: 수동으로 생성한 리소스를 먼저 삭제하거나, terraform import로 Terraform 관리에 편입.
문제 3: 타임아웃
일부 리소스는 생성 완료까지 시간이 걸립니다. 기본 타임아웃이 충분하지 않을 때 설정합니다.
resource "aws_eks_cluster" "main" {
name = "my-cluster"
role_arn = aws_iam_role.eks.arn
timeouts {
create = "30m" # 기본 25분에서 30분으로 연장
delete = "15m"
}
}→ 다음 단계: 3단계: 재사용 가능한 코드