Terraform 기본 – Week 6: 첫 번째 Terraform 모듈 구축 및 사용
Source: Dev.to
이전 주 차 요약
지난 5주 동안 우리는 핵심 Terraform 개념을 배우면서 작지만 현실적인 Azure 환경을 구축했습니다. 첫 번째 VM을 배포하는 것으로 시작해 변수와 tfvars 파일을 도입해 구성의 유연성을 높였습니다. NSG와 동적 블록으로 보안을 추가하고, 마지막으로 출력 값을 통해 유용한 정보를 노출했습니다.
현재까지 구축한 인프라의 시각적 표현은 다음과 같습니다:
Visual Studio Code에서의 폴더 구조:
프로젝트 폴더의 주요 파일
nsg.tf– 네트워크 보안 그룹 및 연결 정의.outputs.tf– 출력 값.providers.tf– AzureRM 제공자 블록.resource-group.tf– 리소스 그룹 정의.terraform.tfvars– 프로젝트 변수 값.variables.tf– 변수 정의.virtual-machine.tf– 가상 머신 및 NIC 리소스.virtual-network.tf– 가상 네트워크 및 서브넷 리소스.
이 시점에서 우리는 완전하게 작동하고, 매개변수화되며, 보안이 적용된 VM 배포를 갖추었습니다. 구성이 커짐에 따라 반복되는 패턴이 눈에 띄게 되고, 유사한 리소스를 다수 관리하기가 어려워집니다. 바로 Terraform 모듈을 도입하기에 적절한 순간입니다.
이전 주 차
시리즈용 GitHub 저장소:
Terraform 모듈이란 무엇이며 왜 사용하나요?
Terraform 모듈은 재사용 가능한 단일 단위로 묶인 리소스들의 집합입니다. 각 배포마다 동일한 VM, NIC, NSG 블록을 다시 작성하는 대신, 모듈 안에 한 번 정의하고 필요할 때마다 해당 모듈을 호출합니다.
메인 Terraform 파일이 들어있는 폴더가 루트 모듈이며, .tf 파일이 들어있는 모든 하위 폴더는 자식 모듈이 되고 독립적으로 실행될 수 없습니다. 루트 모듈은 입력값을 제공하고, 자식 모듈은 출력값을 반환합니다. 이 관계를 통해 코드를 중복 없이 깔끔하게 재사용할 수 있습니다.
실제 환경에서는 모듈이 필수적입니다. 예를 들어, 개발, 스테이징, 프로덕션 환경에 걸쳐 10개의 VM을 관리하는 팀을 생각해 보세요. 모듈이 없으면 각 환경마다 동일한 리소스 블록을 복사해야 합니다. 태그를 업데이트하거나 NSG 규칙을 조정하는 간단한 변경이라도 여러 곳에 반복 적용해야 하므로 드리프트가 발생하고 유지 보수 비용이 증가합니다.
모듈에 로직을 중앙 집중화하면 다음을 달성할 수 있습니다:
- 환경 간 일관성 유지.
- 중복 감소.
- 인프라 유지 보수 및 확장 용이.
모듈 입력값과 출력값 이해하기
모듈 입력값
입력값은 모듈이 리소스를 생성하는 데 필요한 값입니다. 모듈 내부에서 변수로 정의되며, 루트 모듈이 모듈을 호출할 때 실제 값을 전달합니다. VM 모듈의 일반적인 입력값은 다음과 같습니다:
- 리소스 그룹 이름 및 위치
- 서브넷 ID
- VM 크기
- 관리자 인증 정보
- NIC 설정
- 허용 포트
모듈 출력값
출력값은 자식 모듈에서 루트 모듈로 값을 노출합니다. 이를 통해 루트 구성은 모듈 내부 리소스에 직접 접근하지 않고도 해당 정보를 사용할 수 있습니다. VM 모듈의 일반적인 출력값은 다음과 같습니다:
- VM ID
- NIC 이름
- 프라이빗 IP 주소
이러한 출력값은 구성 내 다른 곳에서 참조하거나 배포 후 표시할 수 있습니다.
첫 번째 Terraform 모듈 만들기
Note: 기존 코드를 재사용 가능한 모듈로 리팩터링하는 과정이며, 처음부터 모듈을 만드는 것이 아닙니다. 실제 상황에서 일련의 리소스를 재사용 가능한 컴포넌트로 전환하는 일반적인 시나리오를 반영합니다.
우리는 VM, NIC, NSG 리소스를 modules/vm 폴더로 이동하고, 리소스 그룹, 가상 네트워크, 서브넷은 루트 구성에 그대로 둡니다. 기존 variables.tf, outputs.tf, terraform.tfvars는 루트에 남아 모듈에 값을 계속 제공합니다.
Step 1: 모듈 폴더 구조 만들기
modules/
└── vm/
├── main.tf
├── variables.tf
└── outputs.tf
Step 2: 모듈의 main.tf 채우기
원본 virtual-machine.tf와 nsg.tf 파일에서 가상 머신, NIC, NSG 및 NSG 연결에 해당하는 리소스 블록을 복사해 modules/vm/main.tf에 붙여넣습니다.
(이미지는 복사된 리소스 정의를 보여줍니다.)
Step 3: 모듈 변수 정의
modules/vm/variables.tf를 생성하고 모듈이 필요로 하는 모든 입력값(resource_group_name, subnet_id, vm_size 등)을 선언합니다. 변수 이름과 타입은 루트 구성에 있던 것과 동일하게 사용합니다.
Step 4: 모듈 출력값 정의
modules/vm/outputs.tf를 만들어 VM ID, NIC 이름, 프라이빗 IP 주소와 같은 유용한 값을 노출합니다.
Step 5: 루트 구성에서 모듈 호출
루트 폴더에 module 블록을 추가합니다(예: main.tf 혹은 별도 vm-module.tf 파일). 새 모듈을 참조하고 필요한 변수를 전달합니다:
module "vm" {
source = "./modules/vm"
resource_group_name = var.resource_group_name
location = var.location
subnet_id = azurerm_subnet.main.id
vm_size = var.vm_size
admin_username = var.admin_username
admin_password = var.admin_password
allowed_ports = var.allowed_ports
}
루트에 기존 outputs.tf에서 이제 모듈의 출력값을 참조할 수 있습니다. 예:
output "vm_private_ip" {
value = module.vm.private_ip
}
모듈을 도입함으로써 전체 구성은 그대로 동작하면서 재사용성과 유지 보수성이라는 이점을 얻게 됩니다.


