0. 회사에선 AWS 기본 모듈 대신, 자체 모듈을 사용하는 이유
항목 | 설명 |
커스터마이징 | - 사내 보안정책, 네이밍 규칙, 태깅 전략 등 요구사항에 맞춰 커스텀 가능 - 사내 인프라 특징, 워크로드에 맞춰 모듈을 작성하고 최적화시킬 수 있음 |
버전관리 | - 모듈의 버전 관리를 내부적으로 가능 |
재사용성 | - 사내 인프라에 적합한 재사용가능한 모듈 작성을 통해 재사용성 향상 가능 |
비즈니스 로직 | - 사내 비즈니스 로직이나 규칙을 인프라 프로비저닝에 포함 가능 |
1. 루트, 자식 모듈
- 루트 모듈 (Root Module)
- 테라폼을 실행하는 기본 작업 디렉토리에 있는 모듈
- 다른 모듈을 호출하고 전체 인프라 구성을 조정
- 자식 모듈 (Child Module)
- 루트 모듈에서 호출되는 재사용 가능한 모듈
- 특정 인프라 구성요소를 캡슐화
my_terraform_project/ ├── main.tf # 루트 모듈 ├── variables.tf # 루트 모듈의 변수 정의 ├── outputs.tf # 루트 모듈의 출력 정의 └── modules/ └── vpc/ ├── main.tf # VPC 자식 모듈 ├── variables.tf └── outputs.tf └── ec2/ ├── main.tf # EC2 자식 모듈 ├── variables.tf └── outputs.tf
2. 테라폼 모듈 작성 기본 원칙
- 네이밍 규칙: terraform-<프로바이더>-<모듈명> 형식 사용
- 모듈화 중심: 재사용과 확장을 고려한 구조 설계
- 독립성 유지: 각 모듈을 독립적으로 관리하고 호출
- 참고 및 학습: 공개 레지스트리의 모듈 구조와 기능 참조
- 공유 및 개선: 모듈을 팀/커뮤니티와 공유하고 피드백 반영
# 네이밍 규칙 수정 버전 terraform-aws-project/ ├── main.tf ├── variables.tf ├── outputs.tf └── modules/ ├── terraform-aws-vpc/ │ ├── main.tf │ ├── variables.tf │ └── outputs.tf └── terraform-aws-ec2/ ├── main.tf ├── variables.tf └── outputs.tf
# 각 모듈을 독립적으로 관리 및 호출 / ├── modules/ │ └── terraform-random-pwgen/ │ ├── main.tf │ ├── output.tf │ └── variable.tf ├── projects/ │ └── 06-module-training/ │ └── 06-01-basic/ │ └── main.tf └── README.md
# 각 모듈을 독립적으로 관리 및 호출 Project/ └── Environment/ └── AWS/ ├── modules │ └── terraform-aws-vpc │ ├── locals.tf │ ├── main.tf │ ├── outputs.tf │ └── variable.tf ├── main.tf ├── outputs.tf ├── terraform.tfvars └── variables.tf
3. 모듈과 프로바이더 관계
특성 | 모듈 내부 프로바이더 정의 | 모듈 외부 프로바이더 정의 |
완결성 | 높음 (모듈이 독립적으로 작동) | 낮음 (외부 설정에 의존) |
유연성 | 낮음 (설정 변경이 어려움) | 높음 (사용자가 쉽게 조정 가능) |
재사용성 | 제한적 (특정 설정에 종속) | 높음 (다양한 환경에서 사용 가능) |
버전 관리 | 어려움 (모듈 내부에 고정) | 용이 (외부에서 관리) |
사용 편의성 | 높음 (추가 설정 불필요) | 중간 (사용자가 프로바이더 정의 필요) |
모듈 간 충돌 | 발생 가능성 높음 | 발생 가능성 낮음 |
테스트 용이성 | 높음 (독립적 테스트 가능) | 중간 (외부 설정 필요) |
권장 사용 사례 | 매우 특정한 용도의 모듈 | 범용적인 모듈 |
일반적으로 프로바이더는 모듈 외부에 정의하는 것이 권장됨.
모듈은 프로바이더 설정을 상속받아 사용한다.
# 루트 모듈에서 provider "aws" { region = "us-west-2" } module "example" { source = "./modules/example" # 프로바이더 설정이 자동으로 상속됨 }
4. 모듈 코드 예시

4-1. main.tf
provider "aws" { region = var.aws_region } module "vpc" { source = "./modules/vpc" vpc_cidr = var.vpc_cidr vpc_name = var.vpc_name azs = var.azs private_subnets = var.private_subnets public_subnets = var.public_subnets } module "ec2" { source = "./modules/ec2" instance_name = var.instance_name instance_type = var.instance_type subnet_id = module.vpc.public_subnet_ids[0] vpc_id = module.vpc.vpc_id }
4-2. output.tf
output "vpc_id" { description = "ID of the VPC" value = module.vpc.vpc_id } output "public_subnet_ids" { description = "IDs of the public subnets" value = module.vpc.public_subnet_ids } output "instance_public_ip" { description = "Public IP of the EC2 instance" value = module.ec2.instance_public_ip }
4-3. variables.tf
variable "aws_region" { description = "AWS region" default = "ap-northeast-2" } variable "vpc_cidr" { description = "CIDR block for VPC" default = "10.0.0.0/16" } variable "vpc_name" { description = "Name of VPC" default = "my-vpc" } variable "azs" { description = "Availability Zones" default = ["ap-northeast-2a", "ap-northeast-2c"] } variable "private_subnets" { description = "Private subnet CIDR blocks" default = ["10.0.1.0/24", "10.0.2.0/24"] } variable "public_subnets" { description = "Public subnet CIDR blocks" default = ["10.0.101.0/24", "10.0.102.0/24"] } variable "instance_name" { description = "Name of EC2 instance" default = "my-instance" } variable "instance_type" { description = "EC2 instance type" default = "t2.micro" }
4-4. modules/ec2/main.tf
data "aws_ami" "amazon_linux_2" { most_recent = true owners = ["amazon"] filter { name = "name" values = ["amzn2-ami-hvm-*-x86_64-gp2"] } } resource "aws_security_group" "this" { name = "${var.instance_name}-sg" description = "Security group for EC2 instance" vpc_id = var.vpc_id ingress { from_port = 22 to_port = 22 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"] } tags = { Name = "${var.instance_name}-sg" } } resource "aws_instance" "this" { ami = data.aws_ami.amazon_linux_2.id instance_type = var.instance_type subnet_id = var.subnet_id vpc_security_group_ids = [aws_security_group.this.id] tags = { Name = var.instance_name } }
4-5. modules/ec2/output.tf
output "instance_id" { description = "ID of the EC2 instance" value = aws_instance.this.id } output "instance_public_ip" { description = "Public IP of the EC2 instance" value = aws_instance.this.public_ip }
4-6. modules/ec2/variables.tf
variable "instance_name" { description = "Name of EC2 instance" } variable "instance_type" { description = "EC2 instance type" } variable "subnet_id" { description = "Subnet ID where the instance will be launched" } variable "vpc_id" { description = "VPC ID for the security group" }
4-7. modules/vpc/main.tf
resource "aws_vpc" "this" { cidr_block = var.vpc_cidr tags = { Name = var.vpc_name } } resource "aws_subnet" "private" { count = length(var.private_subnets) vpc_id = aws_vpc.this.id cidr_block = var.private_subnets[count.index] availability_zone = var.azs[count.index] tags = { Name = "Private Subnet ${count.index + 1}" } } resource "aws_subnet" "public" { count = length(var.public_subnets) vpc_id = aws_vpc.this.id cidr_block = var.public_subnets[count.index] availability_zone = var.azs[count.index] tags = { Name = "Public Subnet ${count.index + 1}" } } resource "aws_internet_gateway" "this" { vpc_id = aws_vpc.this.id tags = { Name = "${var.vpc_name}-igw" } } resource "aws_route_table" "public" { vpc_id = aws_vpc.this.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.this.id } tags = { Name = "${var.vpc_name}-public-rt" } } resource "aws_route_table_association" "public" { count = length(aws_subnet.public) subnet_id = aws_subnet.public[count.index].id route_table_id = aws_route_table.public.id }
4-8. modules/vpc/output.tf
output "vpc_id" { description = "ID of the VPC" value = aws_vpc.this.id } output "private_subnet_ids" { description = "IDs of the private subnets" value = aws_subnet.private[*].id } output "public_subnet_ids" { description = "IDs of the public subnets" value = aws_subnet.public[*].id }
4-9. modules/vpc/variables.tf
variable "vpc_cidr" { description = "CIDR block for VPC" } variable "vpc_name" { description = "Name of VPC" } variable "azs" { description = "Availability Zones" type = list(string) } variable "private_subnets" { description = "Private subnet CIDR blocks" type = list(string) } variable "public_subnets" { description = "Public subnet CIDR blocks" type = list(string) }