[Terraform] Module

도은호·2025년 9월 30일

terraform

목록 보기
29/32
  • Module = 재사용 가능한 인프라 함수(디렉터리 하나). 입력/출력 인터페이스를 명확히 하고 버전 고정.
  • 루트에서 Provider를 정의하고 자식 모듈이 상속. 지역/계정이 다르면 별칭(provider alias) 으로 주입.

1) 개념과 구조

modules/
  vpc-basic/
    main.tf
    variables.tf
    outputs.tf
live/
  dev/
    main.tf   # 여기서 module "vpc" 호출

호출 구조 이미지

flowchart LR
  A[루트 모듈] --> B[자식 모듈: vpc-basic]
  A --> C[자식 모듈: app]
  B -->|outputs| A
  C -->|outputs| A
  • A → B, A → C: 루트 모듈(프로젝트 최상위 main.tf)에서 자식 모듈 두 개(vpc-basic, app)를 호출한다.

  • B →|outputs| A, C →|outputs| A: 각 자식 모듈이 출력값(outputs) 을 내보내고, 루트 모듈이 그 값을 받아 다른 리소스나 모듈 인자로 재사용한다.

즉, 루트가 자식 모듈을 호출하고, 자식은 결과를 outputs로 루트에 돌려준다 → 루트는 그 값을 다음 단계의 입력으로 쓴다.

.
├─ main.tf                 # 루트 모듈(여기서 자식 모듈 호출)
├─ variables.tf
├─ outputs.tf
└─ modules/
   ├─ vpc-basic/           # VPC 만드는 모듈
   │   ├─ main.tf
   │   ├─ variables.tf
   │   └─ outputs.tf
   └─ app/                 # EC2 등 앱 리소스 모듈
       ├─ main.tf
       ├─ variables.tf
       └─ outputs.tf

2) 모듈 호출 예시

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"

  name   = "demo"
  cidr   = "10.0.0.0/16"
  azs    = ["ap-northeast-2a","ap-northeast-2c"]
  public_subnets  = ["10.0.1.0/24","10.0.2.0/24"]
  private_subnets = ["10.0.11.0/24","10.0.12.0/24"]
}

output "vpc_id" { value = module.vpc.vpc_id }

Git 소스 고정

module "svc" {
  source = "git::https://github.com/org/repo.git//modules/svc?ref=v1.2.3"
}

3) 입력/출력 인터페이스

# variables.tf
variable "name" { type = string }
variable "tags" { type = map(string); default = {} }

# outputs.tf
output "id" { value = aws_vpc.main.id }
  • 입력은 타입/검증(validation)으로 가드레일을 두고,
  • 출력은 필요한 식별자만 노출(모듈의 공개 API).

4) Provider와 별칭 주입

provider "aws" { alias = "seoul"; region = "ap-northeast-2" }

module "svc" {
  source    = "./modules/service"
  providers = { aws = aws.seoul }   # 별칭 주입
}

5) 여러 개 생성: count/for_each

module "bucket" {
  for_each = toset(["logs","assets"])
  source   = "./modules/s3-bucket"
  name     = "my-${each.key}"
}

6) 리팩터링: 주소 변경은 moved

# count → for_each 전환 예시
moved { from = aws_subnet.public[0] to = aws_subnet.public["ap-northeast-2a"] }
moved { from = aws_subnet.public[1] to = aws_subnet.public["ap-northeast-2c"] }
  • 파괴 없이 State 주소만 이전.

7) 베스트 프랙티스

  • 모듈은 작고 단일 책임으로, 입력/출력을 명확히
  • 버전 고정(version "~>") + .terraform.lock.hcl 커밋
  • 공통 네이밍/태그/룩업테이블은 locals로 표준화
  • 문서(README), 예제(examples/), 테스트(가능하면) 포함

🔗 관련 소스

1) 모듈 사용 예시 — 06-module-traning/06-01-basic/main.tf

module "mypw1" {
  source = "../modules/terraform-random-pwgen"
}

module "mypw2" {
  source = "../modules/terraform-random-pwgen"
  isDB   = true
}

output "mypw1" {
  value = module.mypw1
}

output "mypw2" {
  value = module.mypw2
}

원문: https://github.com/jsh0911/terraform_code/blob/4961c81b4966a6275da285bc9beb6490fe2576c1/06-module-traning/06-01-basic/main.tf

2) 모듈 본체 — modules/terraform-random-pwgen

main.tf

resource "random_pet" "name" {
  keepers = {
    ami_id = timestamp() # 현재 시간을 id로 만들기
  }
}

resource "random_password" "password" {
  length           = var.isDB ? 16 : 10
  special          = var.isDB ? true : false
  override_special = "!#$%*?"
}

variables.tf

variable "isDB" {
  type        = bool
  default     = false
  description = "패스워드 대상의 DB 여부"
}

outputs.tf

output "id" { value = random_pet.name.id }
output "pw" { value = nonsensitive(random_password.password.result) }

원문:

3) EC2 모듈 본체 — modules/terraform-aws-ec2

main.tf

terraform {
  required_providers {
    aws = { source = "hashicorp/aws" }
  }
}

resource "aws_default_vpc" "default" {}

data "aws_ami" "default" {
  most_recent = true
  owners      = ["amazon"]

  filter { name = "owner-alias"; values = ["amazon"] }
  filter { name = "name";        values = ["amzn2-ami-hvm-*"] }
}

resource "aws_instance" "default" {
  depends_on    = [aws_default_vpc.default]
  ami           = data.aws_ami.default.id
  instance_type = var.instance_type
  tags = { Name = var.instance_name }
}

variables.tf

variable "instance_type" { description = "vm 인스턴스 타입 정의"; default = "t2.micro" }
variable "instance_name" { description = "vm 인스턴스 이름 정의"; default = "user07_ec2" }

outputs.tf

output "private_ip" { value = aws_instance.default.private_ip }

원문:

4) 멀티 리전/멀티 프로바이더 예시 — 06-module-traning/multi_provider_for_module/main.tf

provider "aws" {
  region = "us-west-1" # 켈리포니아 리전
}

provider "aws" {
  alias  = "seoul"     # 두번째 리전부터 alias 필요
  region = "ap-northeast-2"
}

module "ec2_califonia" {
  source = "../modules/terraform-aws-ec2"
}

module "ec2_seoul" {
  source    = "../modules/terraform-aws-ec2"
  providers = { aws = aws.seoul }
  instance_type = "t2.nano"
}

원문: https://github.com/jsh0911/terraform_code/blob/4961c81b4966a6275da285bc9beb6490fe2576c1/06-module-traning/multi_provider_for_module/main.tf


profile
`•.¸¸.•´´¯`••._.• 🎀 𝒸𝓇𝒶𝓏𝓎 𝓅𝓈𝓎𝒸𝒽💞𝓅𝒶𝓉𝒽 🎀 •._.••`¯´´•.¸¸.•`

0개의 댓글