모든 것을 만들지 말라: Terraform 데이터 소스의 예술
Source: Dev.to
소개
AWS 챌린지 13일 차이며, 오늘은 인프라스트럭처를 코드로 관리한다는 관점을 완전히 바꿔놓은 것을 배웠습니다: 모든 것을 직접 관리할 필요는 없습니다.
지금까지 제가 했던 모든 Terraform 작업은 리소스를 생성하는 것이었습니다—VPC, 서브넷, 보안 그룹 등. 실제 조직에서는 여러 팀이 인프라의 서로 다른 부분을 소유합니다. 네트워킹 팀은 VPC를 만들고, 보안 팀은 보안 그룹을 관리하며, 여러분의 역할은 그 기존 인프라에 애플리케이션을 배포하는 것입니다.
그때 등장하는 것이 바로 데이터 소스이며, 이는 완전히 게임 체인저입니다.
리소스 vs. 데이터 소스
리소스 블록
resource "aws_vpc" "my_vpc" {
cidr_block = "10.0.0.0/16"
# Terraform이 생성·업데이트·삭제를 담당합니다
}
데이터 블록
data "aws_vpc" "existing_vpc" {
filter {
name = "tag:Name"
values = ["shared-network-vpc"]
}
# Terraform은 읽기만 할 뿐, 절대 건드리지 않습니다
}
구분은 간단합니다:
- 리소스 – “이것은 내가 소유한다. 전체 수명 주기를 관리한다.”
- 데이터 소스 – “이것은 이미 존재한다. 나는 단지 참조만 하면 된다.”
그 의미는 엄청납니다.
왜 중요한가: 다팀 현실
귀사의 조직 구조
- 모든 VPC와 서브넷을 관리하는 네트워킹 팀
- 보안 그룹과 IAM 정책을 유지하는 보안 팀
- 애플리케이션을 배포하는 인프라 팀(바로 여러분!)
데이터 소스 없이
- 모든 팀의 Terraform 상태 파일에 접근해야 합니다(쉽지 않죠)
- ID를 직접 복사‑붙여넣기 해야 합니다
- 중복 리소스를 만들게 되어 충돌이 발생할 수 있습니다
데이터 소스와 함께
필요한 것을 간단히 조회하면 됩니다:
# 클라우드 네트워킹 팀이 만든 VPC 찾기
data "aws_vpc" "company_vpc" {
filter {
name = "tag:ManagedBy"
values = ["cloud-networking-team"]
}
}
# 보안 팀이 관리하는 보안 그룹 찾기
data "aws_security_group" "approved_sg" {
filter {
name = "tag:ManagedBy"
values = ["security-team"]
}
}
# 그들의 인프라를 활용해 애플리케이션 배포
resource "aws_instance" "my_app" {
ami = data.aws_ami.latest_amazon_linux.id
subnet_id = data.aws_subnet.app_subnet.id
vpc_security_group_ids = [data.aws_security_group.approved_sg.id]
}
결과: 깔끔하고 협업이 가능하며 충돌이 없는 환경.
직접 해보는 데모: 세 가지 필수 데이터 소스
설정: 기존 인프라 시뮬레이션
# 이것은 네트워킹 팀이 이미 배포한 것을 시뮬레이션합니다
resource "aws_vpc" "shared" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "shared-network-vpc"
}
}
resource "aws_subnet" "shared" {
vpc_id = aws_vpc.shared.id
cidr_block = "10.0.1.0/24"
tags = {
Name = "shared-primary-subnet"
}
}
이것을 적용한 뒤, 마치 큰 조직에서처럼 “존재한다는 것을 잊어버렸다”고 가정해 보세요.
데이터 소스 #1: VPC 찾기
data "aws_vpc" "shared" {
filter {
name = "tag:Name"
values = ["shared-network-vpc"]
}
}
동작 방식
- 지정된 태그를 가진 VPC를 AWS에 질의합니다
- VPC ID, CIDR 블록 및 기타 모든 속성을 반환합니다
terraform apply시마다 새로 고침됩니다
콘솔 테스트
terraform console
> data.aws_vpc.shared.id
"vpc-0a1b2c3d4e5f6"
> data.aws_vpc.shared.cidr_block
"10.0.0.0/16"
데이터 소스 #2: 서브넷 찾기 (체인!)
data "aws_subnet" "shared" {
filter {
name = "tag:Name"
values = ["shared-primary-subnet"]
}
vpc_id = data.aws_vpc.shared.id # VPC 데이터 소스를 사용
}
핵심 포인트
- 데이터 소스는 체인될 수 있으며, 하나가 다른 하나에 입력됩니다
vpc_id로 검색 범위를 좁혀, 동일한 태그를 가진 여러 서브넷이 있을 때 실수 매치를 방지합니다
데이터 소스 #3: 최신 AMI (동적)
data "aws_ami" "amazon_linux_2" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
왜 멋진가
most_recent = true로 항상 최신 매칭 AMI를 가져옵니다- 와일드카드(
*) 로 유연한 패턴 매칭이 가능합니다 - 여러 필터를 조합해 정확히 원하는 이미지만 얻어, 인스턴스를 자동으로 최신 상태로 유지합니다
모두 합치기: 최종 리소스
resource "aws_instance" "main" {
ami = data.aws_ami.amazon_linux_2.id
instance_type = "t2.micro"
subnet_id = data.aws_subnet.shared.id
private_ip = "10.0.1.50"
tags = {
Name = "day13-instance"
}
}
terraform plan 실행 결과:
Plan: 1 to add, 0 to change, 0 to destroy.
생성되는 리소스는 하나뿐—EC2 인스턴스. VPC와 서브넷은 단지 참조될 뿐 관리되지 않습니다.
강력한 팁: Terraform Console 테스트
terraform console
# VPC 데이터 소스 테스트
> data.aws_vpc.shared.id
"vpc-0a1b2c3d4e5f6"
# 서브넷 데이터 소스 테스트
> data.aws_subnet.shared.cidr_block
"10.0.1.0/24"
# AMI 데이터 소스 테스트
> data.aws_ami.amazon_linux_2.name
"amzn2-ami-hvm-2.0.20231218.0-x86_64-gp2"
콘솔을 활용해 실제 배포 전에 필터와 값을 검증하세요.
실제로 자주 쓰는 데이터 소스
네트워크 리소스
# VPC 조회
data "aws_vpc" "main" { ... }
# 서브넷 조회
data "aws_subnet" "main" { ... }
# 보안 그룹 조회
data "aws_security_group" "main" { ... }
# 현재 리전의 모든 가용 영역
data "aws_availability_zones" "available" {
state = "available"
}
컴퓨트 리소스
# 최신 AMI (엄청 흔함)
data "aws_ami" "latest" { ... }
# 기존 EC2 인스턴스
# data "aws_instance" "existing" { ... }
이러한 데이터 소스들은 기존 클라우드 리소스와 연동해야 하는 모든 Terraform 구성의 핵심이 됩니다.