근묵자흑
Terraform Module 본문
인프라를 코드로 관리하다 보면 비슷한 패턴의 코드가 자주 반복되는 것을 발견하게 됩니다. 예를 들어 개발 환경과 운영 환경에서 동일한 구조의 VPC를 생성하거나, 여러 리전에 비슷한 구성의 웹 서버를 배포해야 할 수 있습니다. 이런 상황에서 테라폼의 모듈(Module) 기능을 활용하면 코드의 재사용성을 높이고 유지보수를 쉽게 만들 수 있습니다.
테라폼 모듈이란?
테라폼 모듈은 여러 리소스를 하나의 논리적 단위로 패키징한 것입니다. 마치 프로그래밍 언어의 함수처럼, 입력값을 받아 정의된 로직에 따라 리소스를 생성하고 필요한 값을 출력할 수 있습니다. 잘 설계된 모듈은 다음과 같은 장점을 제공합니다:
- 코드 재사용을 통한 생산성 향상
- 일관된 인프라 구성 유지
- 리소스 생성 로직의 캡슐화
- 인프라 변경의 용이성
모듈의 기본 구조
가장 기본적인 테라폼 모듈은 다음과 같은 파일들로 구성됩니다:
modules/web_server/
├── main.tf # 주요 리소스 정의
├── variables.tf # 입력 변수 정의
├── outputs.tf # 출력 값 정의
└── README.md # 모듈 사용 설명서
예를 들어 EC2 웹 서버를 생성하는 모듈을 만들어보겠습니다:
# main.tf
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = var.instance_type
tags = {
Name = "${var.environment}-web-server"
}
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
EOF
}
resource "aws_security_group" "web" {
name = "${var.environment}-web-sg"
description = "Security group for web server"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
모듈 입력 변수 설계하기
모듈의 재사용성을 높이기 위해서는 적절한 입력 변수를 정의하는 것이 중요합니다. variables.tf 파일에서 다음과 같이 변수를 정의할 수 있습니다:
# variables.tf
variable "environment" {
description = "배포 환경 (예: dev, prod)"
type = string
}
variable "ami_id" {
description = "사용할 AMI ID"
type = string
}
variable "instance_type" {
description = "EC2 인스턴스 타입"
type = string
default = "t2.micro" # 기본값 설정
}
variable "vpc_id" {
description = "VPC ID"
type = string
}
변수 정의 시 고려사항:
- 필수 변수와 선택적 변수를 구분 (default 값 유무로 구분)
- 적절한 변수 타입 지정 (string, number, bool, list, map 등)
- 명확한 설명 추가 (description 필드 활용)
- 가능한 경우 validation 규칙 추가
모듈의 지역 변수 활용
모듈 내부에서만 사용되는 값들은 locals 블록을 통해 관리할 수 있습니다:
locals {
# 공통으로 사용되는 태그 정의
common_tags = {
Environment = var.environment
ManagedBy = "Terraform"
Project = var.project_name
}
# 인스턴스 이름 생성 규칙
instance_name = "${var.project_name}-${var.environment}-server"
# 보안 그룹 규칙 정의
security_group_rules = {
http = {
port = 80
cidr_blocks = ["0.0.0.0/0"]
}
https = {
port = 443
cidr_blocks = ["0.0.0.0/0"]
}
}
}
지역 변수를 활용하면:
- 반복되는 값들을 한 곳에서 관리할 수 있습니다
- 복잡한 표현식을 단순화할 수 있습니다
- 모듈 내부 로직을 더 명확하게 표현할 수 있습니다
모듈 출력 설계하기
모듈은 생성된 리소스의 중요 정보를 출력할 수 있습니다. outputs.tf 파일에서 다음과 같이 정의합니다:
# outputs.tf
output "instance_id" {
description = "생성된 EC2 인스턴스 ID"
value = aws_instance.web.id
}
output "public_ip" {
description = "EC2 인스턴스의 공개 IP 주소"
value = aws_instance.web.public_ip
}
output "security_group_id" {
description = "생성된 보안 그룹 ID"
value = aws_security_group.web.id
}
출력값 설계 시 고려사항:
- 외부에서 필요한 정보만 선별적으로 노출
- 명확한 설명 추가
- 민감한 정보는 sensitive = true 설정
모듈 사용하기
정의된 모듈은 다음과 같이 사용할 수 있습니다:
# 개발 환경 웹 서버
module "web_server_dev" {
source = "./modules/web_server"
environment = "dev"
ami_id = "ami-12345678"
instance_type = "t2.micro"
vpc_id = module.vpc.vpc_id
}
# 운영 환경 웹 서버
module "web_server_prod" {
source = "./modules/web_server"
environment = "prod"
ami_id = "ami-12345678"
instance_type = "t2.large" # 운영 환경은 더 큰 인스턴스 사용
vpc_id = module.vpc.vpc_id
}
모듈 버전 관리
테라폼 모듈의 버전 관리는 GitHub의 태그 기능을 활용합니다. 이는 모듈의 안정적인 배포와 버전 추적을 가능하게 합니다.
Git 태그를 이용한 버전 관리
시맨틱 버저닝(Semantic Versioning)을 따라 Git 태그를 생성합니다:
# 태그 생성
git tag -a v1.0.0 -m "Initial stable release"
# 태그 푸시
git push origin v1.0.0
버전 번호 체계:
- MAJOR.MINOR.PATCH (예: v1.2.3)
- MAJOR: 호환성이 깨지는 변경사항 (예: 필수 변수 추가)
- MINOR: 하위 호환성이 있는 기능 추가 (예: 선택적 변수 추가)
- PATCH: 버그 수정 (기존 기능 수정)
태그된 모듈 사용
GitHub 저장소의 특정 태그를 참조하여 모듈을 사용:
module "web_server" {
source = "github.com/username/repo//modules/web_server?ref=v1.2.3"
}
# 특정 메이저 버전의 최신 릴리스 사용
module "web_server" {
source = "github.com/username/repo//modules/web_server?ref=v1.2.3"
}
모듈 작성 시 주의사항
1. 파일 경로 참조
모듈의 source 속성에는 다양한 형태의 경로를 지정할 수 있습니다:
# 로컬 경로
module "example" {
source = "./modules/example" # 상대 경로
source = "/modules/example" # 절대 경로
}
# Git 저장소
module "example" {
source = "github.com/username/repo//modules/example" # GitHub
source = "git::https://example.com/repo.git//modules/example" # 일반 Git
}
# Terraform Registry
module "example" {
source = "hashicorp/consul/aws" # 공식 레지스트리
version = "0.1.0"
}
# S3 버킷
module "example" {
source = "s3::https://s3-eu-west-1.amazonaws.com/examplebucket/example.zip"
}
주의할 점:
- 로컬 경로 사용 시 상대 경로 권장 (이식성)
- Git 저장소 참조 시 특정 태그나 커밋 지정 권장
- 외부 모듈 사용 시 반드시 버전 명시
2. 인라인 블록 사용
테라폼에서는 일부 리소스 설정을 인라인 블록으로 정의할 수 있습니다. 하지만 모듈에서는 인라인 블록 사용을 주의해야 합니다:
# 좋지 않은 예 - 인라인 블록 사용
resource "aws_security_group" "example" {
# ... 기타 설정 ...
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
# 좋은 예 - 독립적인 리소스로 분리
resource "aws_security_group" "example" {
# ... 기타 설정 ...
}
resource "aws_security_group_rule" "ingress_http" {
type = "ingress"
security_group_id = aws_security_group.example.id
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
인라인 블록 사용 시 주의사항:
- 변경이 어려움 (전체 리소스를 재생성해야 할 수 있음)
- 동적 구성이 제한적
- 상태 관리가 복잡해짐
3. 단일 책임 원칙
- 하나의 모듈은 하나의 논리적 단위만 담당
- 너무 많은 기능을 하나의 모듈에 넣지 않기
4. 적절한 추상화 수준
- 너무 세부적이면 사용성이 떨어짐
- 너무 추상적이면 유연성이 떨어짐
5. 문서화
- README.md 파일에 사용 방법 상세히 기술
- 예제 코드 포함
- 변수와 출력값에 대한 설명 추가
6. 테스트
- terraform plan을 통한 기본 검증
- 다양한 입력값으로 테스트
- 가능하다면 자동화된 테스트 추가
결론
테라폼 모듈은 인프라 코드의 재사용성과 유지보수성을 크게 향상시킬 수 있는 강력한 도구입니다. 하지만 좋은 모듈을 만들기 위해서는 신중한 설계와 지속적인 관리가 필요합니다. 위에서 설명한 사항들을 고려하여 모듈을 작성한다면, 보다 효율적이고 안정적인 인프라 관리가 가능할 것입니다.
'IaC > terraform' 카테고리의 다른 글
프로덕션 수준의 테라폼 코드 (3) | 2025.01.19 |
---|---|
테라폼 팁과 요령: 반복문, if문, 배포 및 주의사항 (3) | 2025.01.12 |
Terraform State (3) | 2024.12.29 |
테라폼 로드밸런서 배포 (5) | 2024.12.22 |
왜 테라폼 인가? (4) | 2024.12.15 |