상세 컨텐츠

본문 제목

[Terraform] 리소스 모듈화 - Terraform 가이드 (4)

Development

by 12기통엔진 2024. 7. 16. 21:46

본문

반응형

지난 게시글에서, 빠르게 결과물을 보려고 main.tf 파일에 다 때려넣었는데

각 리소스의 역할에 맞게 파일을 구분해 유지/보수에 유리하게 구조를 변경하자.

 

  1. variables.tf, provider.tf 분리
  2. network.tf 분리
  3. security.tf 분리
  4. rds.tf 분리
  5. 결과 확인
  6. 마무리

 

이전 글까지 따라했다면 아래의 상태일텐데,

/project_root
│
├── terraform
│   ├── main.tf
│   ├── .terraform.lock.hcl
│   ├── terraform.tfstate
│   ├── terraform.tfstate.backup
│   ├── .terraform
│   │   ├── ...

 

오늘의 목표는 이렇게 바꾸는 것이다.

 

/project_root
│
├── terraform
│   ├── main.tf			// 컨트롤 타워
│   ├── variable.tf 		// 민감한 정보 저장
│   ├── provider.tf 		// region 등 배포에 필요한 제공자 저장
│   ├── common 			// util resource
│   │   ├── network
│   │   │   ├── network.tf	// network resource
│   │   ├── security
│   │   │   ├── security.tf	// security resource
│   ├── rds
│   │   ├── rds.tf		// rds resource
│   ├── .terraform.lock.hcl
│   ├── .terraform
│   │   ├── ...

AWS에서 구분한 기능에 맞게 파일을 전부 나누고, 연결시켜 줄 것이다.

 

variables.tf, provider.tf 분리


in terraform/variables.tf,

# Basic Info
variable "region" {
  description = "The AWS region"
  default     = {your_region}
}

# RDS
variable "db_instance_name" {
  description = "The name of the RDS instance"
  type        = string
  default     = {your_instance_name}
}

variable "db_username" {
  description = "Master username for the RDS cluster"
  type        = string
  default     = {your_username}
}

variable "db_password" {
  description = "Master password for the RDS cluster"
  type        = string
  sensitive   = true
  default     = {your_password}
}

variable "db_name" {
    description = "The name of database"
    type = string
    default = {your_db_name}
}

 

in terraform/provider.tf

provider "aws" {
  region = var.region
}

 

  • variables.tf, provider.tf 파일을 생성함에 따라, 기존 main.tf 파일을 수정한다.

in terraform/main.tf,

# # Provider
# provider "aws" {
#   region = {your_region}
# }
# Provider 정의 제거

...

# DB Instance
resource "aws_db_instance" "db_instance" {
  identifier              = var.db_instance_name # varialbe.tf에서 불러오도록 변경
...
  username                = var.db_username
  password                = var.db_password
  db_name                 = var.db_name
...
}

 

network.tf 분리


 

network 관련 리소스: VPC, Subnet, Internet Gateway, Route Table, Route Table Association, Subnet Group

  • 새로운 파일을 만들어 옮겨준다.

in terraform/common/network/network.tf,

# DB Network
data "aws_availability_zones" "available" {}

resource "aws_vpc" "db_vpc" {
  cidr_block = "10.0.0.0/16" 
  
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "db-vpc"
  }
}

resource "aws_subnet" "db_subnet" {
  count             = 2
  vpc_id            = aws_vpc.db_vpc.id
  cidr_block        = element(["10.0.1.0/24", "10.0.2.0/24"], count.index)
  availability_zone = element(data.aws_availability_zones.available.names, count.index)

  tags = {
    Name = "db-subnet-${count.index}"
  }
}

resource "aws_internet_gateway" "db_igw" {
  vpc_id = aws_vpc.db_vpc.id

  tags = {
    Name = "db-igw"
  }
}

resource "aws_route_table" "db_route_table" {
  vpc_id = aws_vpc.db_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.db_igw.id
  }

  tags = {
    Name = "db-route-table"
  }
}

resource "aws_route_table_association" "db_route_table_assoc" {
  count          = 2
  subnet_id      = element(aws_subnet.db_subnet[*].id, count.index)
  route_table_id = aws_route_table.db_route_table.id
}

resource "aws_db_subnet_group" "db_subnet_group" {
  name       = "db-subnet-group"
  subnet_ids = aws_subnet.db_subnet[*].id

  tags = {
    Name = "db-subnet-group"
  }
}
  • 이 중, vpc id, subnet group name 은 security, rds에서 필요로 하니 output으로 따로 지정해줘야 한다.

in terraform/common/network/network.tf,

...
output "db_vpc_id" {
  value = aws_vpc.db_vpc.id
}

output "db_subnet_group_name" {
  value = aws_db_subnet_group.db_subnet_group.name
}
  • 마지막으로 루트 디렉토리의 main.tf 에서 network와 관련된 부분을 변경하고
  • vpc id, subnet group id 받아오는 문법을 교체한다.

in terraform/main.tf,

# DB Network
module "network" { # 기존 코드를 교체
  source = "./common/network"
}

# DB Security
resource "aws_security_group" "db_sg" {
...
  vpc_id = module.network.db_vpc_id # 교체
...
}

# DB Instance
resource "aws_db_instance" "db_instance" {
...
  db_subnet_group_name    = module.network.db_subnet_group_name # 교체
...
}

 

security.tf 분리


이번엔 network 때와 다르게 main.tf에 정의할 module에 db_vpc_id 라는 input이 있다.

기존 main.tf의 코드를 옮기고, rds resource에서 사용할 security group id 를 output으로 내놓는 것까진 동일하다.

 

in terraform/common/security/security.tf,

# DB Security
resource "aws_security_group" "db_sg" {
  description = "Allow DB instance access"
  vpc_id = module.network.db_vpc_id

  ingress {
    from_port   = 3306
    to_port     = 3306
    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 = "db-sg"
  }
}

output "db_sg_id" {
  value = aws_security_group.db_sg.id
}

 

이제 network module의 output을 security module의 input으로 받아들일 수 있는 구조로 변경하자.

terraform/common/security 디렉토리에 variables.tf 파일을 만들자.

 

in terraform/common/security/variables.tf,

variable "db_vpc_id" {
  description = "The ID of the VPC for DB"
  type        = string
}

 

그리고 security.tf 의 module.network.db_vpc_id 부분을 변경하자.

 

in terraform/common/security/security.tf,

# DB Security
resource "aws_security_group" "db_sg" {
...
  vpc_id = var.db_vpc_id
...
}

 

security 디렉토리의 variables.tf에 "db_vpc_id"가 정의되었으므로,

해당 디렉토리를 기준으로 생성되는 모듈에서는 "db_vpc_id" 값을 반드시 필요로 한다.

마지막으로 main.tf 의 security 부분을 교체한다.

 

in terraform/main.tf

...
# DB Security
module "security" {
  source     = "./common/security"
  db_vpc_id  = module.network.db_vpc_id # Resource Input
}

# DB Instance
resource "aws_db_instance" "db_instance" {
...
  vpc_security_group_ids  = [module.security.db_sg_id]
...
}

 

rds.tf 분리


이제 감을 잡았을 것이다. 해야할 것은 크게 4가지

  1. 세부 디렉토리, 파일로 기존 코드 이동
  2. 다른 모듈에서 필요한 정보는 output {} 으로 정의해주기
  3. input에 필요한 정보는 해당 디렉토리에 variables.tf 파일을 만들어 정의
  4. main.tf 파일에서 module {} 문법으로 교체, 3번에서 정의한 input 집어 넣어 주기

한 번에 가보자.

 

in terraform/rds/rds.tf

# DB Instance
resource "aws_db_instance" "db_instance" {
  identifier              = var.db_instance_name
  instance_class          = "db.t3.micro"
  engine                  = "mysql"
  engine_version          = "8.0.34"
  username                = var.db_username
  password                = var.db_password
  db_name                 = var.db_name
  allocated_storage       = 20
  db_subnet_group_name    = var.db_subnet_group_name
  vpc_security_group_ids  = [var.db_sg_id]
  skip_final_snapshot     = true
  publicly_accessible     = true
}

 

in terraform/rds/variables/tf

variable "db_sg_id" {
    description = "Security group id for db instance"
    type = string
}

variable "db_instance_name" {
  description = "The name of the RDS instance"
  type        = string
}

variable "db_username" {
    description = "Root user name"
    type = string
}

variable "db_password" {
    description = "Root user password"
    type = string
}

variable "db_name" {
    description = "The name of database"
    type = string
}

variable "db_subnet_group_name" {
    description = "Subnet group name for db"
    type = string
}

 

in terraform/main.tf

...
# DB instance
module "rds" {
  source = "./rds"
  db_sg_id             = module.security.db_sg_id
  db_instance_name     = var.db_instance_name
  db_username          = var.db_username
  db_password          = var.db_password
  db_name              = var.db_name
  db_subnet_group_name = module.network.db_subnet_group_name
}

 

결과 확인


terraform init
terraform validate

terraform apply

지난 게시글에서와 동일하게 10개의 리소스를 배포한다고 한다. 구조만 변경한 것이니 당연하다.

 

마무리


디렉토리는 아래처럼 바뀌었다.

/project_root
│
├── terraform
│   ├── main.tf
│   ├── variable.tf
│   ├── provider.tf
│   ├── common
│   │   ├── network
│   │   │   ├── network.tf
│   │   ├── security
│   │   │   ├── security.tf
│   │   │   ├── variables.tf
│   ├── rds
│   │   ├── rds.tf
│   │   ├── variables.tf
│   ├── .terraform.lock.hcl
│   ├── .terraform
│   │   ├── ...

 

앞으로 새로운 유형의 리소스를 추가할 때도 디렉토리를 추가해 조각 조각 관리하자.

역할이 구분되어있어 맥락을 파악하기 쉽다.

 

마지막으로 .gitignore에 일부 파일을 등록하자.

in /.gitignore

...
# Ignore infra
terraform/.terraform/*
terraform/variables.tf
terraform/*.tfstate
terraform/*.tfstate.*
terraform/*.hcl
terraform/variables.tf.bak

 

끝! 다음 게시글에서는 ecr, ecs 리소스를 추가하는 과정을 다루겠다.

반응형

관련글 더보기