본문 바로가기
IaC

[IaC] Terraform Module 작성 및 사용방법

by cloudraw 2024. 12. 3.

안녕하세요, 클라우드로입니다!

 

이번 글에서는 테라폼 코드를 재사용 가능한 구성요소로 관리할 수 있는 모듈화, 즉 terraform module에 대해 알아보겠습니다.

 

 

Terraform Module이란?

 

테라폼 모듈(Terraform Module)은 기본적으로 테라폼 코드의 재사용 가능한 리소스의 집합을 의미합니다. 모듈이라는 단어에는 한 번 정의된 내용 혹은 정의된 인프라의 특정 부분을 여러 곳에서 재사용할 수 있음을 내포하고 있습니다.

 

즉 테라폼 모듈은 관련있는 리소스를 한 폴더에 모아 하나의 템플릿으로 생성하여 사용할 수 있도록 하는 테라폼의 기능이라고 이해할 수 있습니다.

 

원하는 리소스들을 모아 캡슐화하면 복잡한 인프라를 작고 독립적인 모듈로 작성할 수 있고 이를 통해 코드 중복을 줄일 수 있습니다. 가독성을 높여 유지보수를 용이하게 할 수 있다는 장점이 있으며, 필요에 따라 다른 프로젝트에서 재사용할 수 있습니다.

 

Terraform Module은 두가지의 종류로 구분할 수 있습니다.

 

Root Module

 

terraform 명령어를 실행하는 작업 경로에 선언한 module로, 실제로 배포할 리소스들이 선언된 곳입니다. module 블록이 선언되지 않았더라도 terraform 명령어가 실행되는 .tf 파일은 root module이 됩니다.

 

Child Module

 

Root Module이 호출하여 사용하는 module로 동일한 구성에서 여러 번 호출될 수 있습니다.

 

 

Terraform Module 사용법

 

Root Module

 

먼저, 예시를 통해 module 블록을 사용한 Root Module을 살펴보겠습니다.

module 블록도 다른 타입의 블록과 같이 유니크한 이름을 설정해야 합니다. 예시에서는 "my_vpc"로 설정하겠습니다. 또한 resource 블록과 마찬가지로 meta argument인 count, for_each, providers, depends_on을 사용할 수 있습니다.

# project/main.tf

# Root Module
module "my_vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.16.0"

  name = var.vpc_name
  cidr = var.vpc_cidr
}

 

module 블록의 argument들을 살펴보겠습니다.

 

sourceroot module이 사용할 child module의 위치를 선언하는 필수 argument입니다. 따라서 module 블록을 사용하여 root module을 작성할 경우, child module 역시 존재해야 합니다.

 

version은 source에서 지정한 모듈의 버전을 지정하는 argument입니다. 주의해야 할 점은 child module이 Terraform Registry에서 지원하는 module인 경우에만 사용 가능한 argument라는 점입니다.

 

그 아래로는 child module에서 선언된 argument들을 작성하면 됩니다.

 

 

다음으로, Child Module에 대해 알아보겠습니다. child module은 소스의 위치에 따라 Local Module과 Remote Module 두가지 유형으로 나눌 수 있습니다.

 

Local Module

 

root module 경로 내부나 로컬 파일 시스템에 존재하는 모듈입니다. 팀 내부에서 간단히 재사용할 모듈이 필요할 때 사용하기 좋습니다.

local module의 예시를 살펴보겠습니다. 직접 child module을 작성하거나 외부의 child module을 로컬에서 커스텀하여 사용합니다.

# project/vpc_module/vpc.tf

# Local Module
resource "aws_vpc" "vpc" {
  cidr_block = var.cidr
  tags = { Name = var.name }
}

variable "name" {
  default = ""
}

variable "cidr" {
  default = "10.0.0.0/16"
}
# project/main.tf

# Root Module
module "my-local-vpc" {
  source  = "./vpc_module"    # local module의 경로

  name = "local-vpc"    # local module에서 선언한 variable
}


# project 위치에서 terraform 명령어 실행

 

local module은 root module과 다른 경로에 정의하며, root module의 source에 local module의 경로를 작성하면 됩니다. 이때 로컬 경로인 것을 나타내기 위해 경로는 ./ 또는 ../로 시작해야합니다.

 

root module과 child module의 구조

 

 

root module에서 작성할 사용자 정의 argument는 local module에서 variable로 선언된 이름을 사용합니다. 예시에서는 namecidr을 argument로 선언했고 root module에서 name만 사용하여 vpc를 만들었습니다.

 

 

Remote Module

 

terraform 명령어를 실행하는 작업경로 외부에 존재하는 모듈입니다. 즉 네트워크 상에서 가져오는 모듈이라고 할 수 있습니다. Terraform Registry, Git Repository, Private Module Registry, AWS S3 Bucket 등의 저장소를 지원하며 버전 관리를 하거나 조직 간 공유가 필요한 경우에 적합합니다.

 

Terraform Registry에 공개된 Module들

 

 

# project/main.tf

# Root Module
module "remote-s3" {
  source  = "terraform-aws-modules/s3-bucket/aws"    # remote module 주소 (Terraform Registry)
  version = "4.22.0"

  bucket  = "example-bucket"
}

 

root module의 source에 remote module의 소스 주소를 작성하여 외부에서 공개된 모듈을 사용할 수 있습니다. 소스 주소는 외부 저장소의 타입에 따라 다른 형식을 입력합니다.

 

# Private Module Registry
module "vpc" {
  source  = "tf-cloud-org/vpc/aws"
  version = "3.0.0"
}


# GitHub
module "vpc" {
  source = "git::https://example.com/vpc.git"
}

module "storage" {
  source = "git::ssh://username@example.com/storage.git"
}


# S3 Bucket
module "consul" {
  source = "s3::https://s3-eu-west-1.amazonaws.com/examplecorp-terraform-modules/vpc.zip"
}

 

 

Terraform Module 사용법 심화

 

providers

 

child module을 작성할 때 2개 이상의 provider를 사용했다면, root module에서 providers argument를 사용하여 각 provider를 지정할 수 있습니다.

# project/vpc_module/vpc.tf

# Local Module
provider "aws" {
  alias = "second"
}

resource "aws_vpc" "vpc" {
  # default provider 사용
  cidr_block = var.cidr
  tags = { Name = var.name }
}

resource "aws_vpc" "vpc2" {
  provider = aws.second
  cidr_block = var.cidr
  tags = { Name = var.name }
}

variable "name" {
  default = null
}

variable "cidr" {
  default = "10.0.0.0/16"
}

 

예시를 살펴보면, child module에서 2개의 vpc에 서로 다른 provider를 지정한 것을 볼 수 있습니다. 첫번째 vpc는 provider를 지정하지 않았으므로 default provider를, 두번째 vpc는 "second"라는 alias를 가진 provider를 사용하게 됩니다.

 

# project/main.tf

# Root Module
provider "aws" {
  region     = "ap-northeast-2"
  access_key = var.access_key
  secret_key = var.secret_key
}

provider "aws" {
  alias = "tokyo"
  region     = "ap-northeast-3"
  access_key = var.access_key
  secret_key = var.secret_key
}

module "my-local-vpc" {
  source  = "./local_module"
  providers = {
    aws.second = aws.tokyo
  }

  name = "local-vpc"
}



child module에서 provider의 alias만 지정했기 때문에 root module에서 실제로 사용할 사용자 인증키를 입력합니다. default provider와 "tokyo" alias를 가진 provider를 선언합니다.

 

providers를 사용하여 child module의 "second" provider에 "tokyo" provider를 할당합니다. 이제 root module을 배포하면 서울과 도쿄 리젼에 vpc가 1개씩 생성된 것을 확인할 수 있습니다.

 

하나의 모듈에서 global 리소스와 regional 리소스가 함께 있는 경우, 리소스마다 사용자 혹은 환경을 분리해야 하는 경우 등을 위해 사용하는 argument라고 볼 수 있습니다.

 

child module의 provider에 region이나 사용자 인증키 등을 지정할 수도 있지만, 모듈의 재사용성이라는 장점이 사라지기 때문에 권장하지 않습니다.

 

 

이상으로 terraform module의 개념과 사용법에 대해 알아보았습니다.

감사합니다.

 


 

    

 

Cloudraw는 쉽게 클라우드 인프라를 그리고 사용할 수 있는 서비스를 제공하기 위해 노력하고 있습니다.

 

클라우드가 있는 곳 어디든 Cloudraw가 함께합니다.

 

📨 help@cloudraw.kr