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)
}