연재 시리즈

테라폼 시리즈 25편. Module

악분 2022. 11. 10. 21:13
반응형

module은 여러 테라폼 코드를 하나의 그룹으로 관리하는 방법입니다. 하나의 그룹은 폴더를 의미합니다. module의 장점은 재사용성입니다. 모듈은 여러 곳에서 import해서 사용할 수 있습니다.

 

Module 생성방법

module 생성방법은 간단합니다. 폴더를 만든 후, 생성한 폴더에 테라폼 코드를 작성하면 됩니다.

 

my-s3 module은 aws s3를 생성합니다. bucket이름을 입력받을 수 있도록 variable을 사용했습니다.

# variable.tf
variable "bucket_name" {
  description = "bucket name"
  type        = string
  sensitive   = true
  default = "akbun-t101-week4-local-example"
}

# s3.tf
resource "aws_s3_bucket" "mys3bucket" {
  bucket = var.bucket_name
}

 

Module 사용하기

module block으로 Module을 사용할 수 있습니다.

module "<NAME>" {
  source = "사용할 모듈 경로"
}

 

module 경로는 terraform 명령어를 실행하는 위치에 따라 달라질 수 있습니다. terraform 명령어를 실행하는 작업경로를 root module이라고 합니다. root module이 사용하는 module을 child module이라고 합니다.

 

module경로는 root module입장에서 child module위치를 생각하여 module.source를 적절히 설정하면 됩니다. 예제에서는 root module과 my-s3 module가 같은 위치에 있어 “./”로 경로를 설정했습니다.

module "my-s3" {
  source = "./my-s3"
}

 

terraform apply명령어로 코드를 인프라에 반영하려면 terraform init명령어로 모듈 초기화를 해야 합니다. module 초기화를 하지 않으면 terraform apply명령어를 수행하지 못합니다.

terraform init

 

Module provider 설정

module에는 provider를 제거하는 편이 좋습니다. module을 사용하는 root module이 provider를 설정하므로 module에는 provider설정이 불필요합니다.

 

Module 입력

예제코드 링크: https://github.com/sungwook-practice/terraform-study/tree/main/week4/module-example

module 입력은 모듈에서 사용하는 값을 외부에서 초기화할 때 사용합니다. module에서 variable block을 사용하면, module을 사용하는 입장에서 variable값을 초기화 할 수 있습니다.

 

s3를 생성하는 module을 생성할 때, 외부에서 초기화가 필요한 값은 bucket이름입니다. 아래 예제 코드는 bucket 이름을 외부에서 초기화 할 수도록 variable block을 사용했습니다.

# variable.tf
variable "bucket_name" {
  description = "bucket name"
  type        = string
  sensitive   = true
}

# s3.tf
resource "aws_s3_bucket" "mys3bucket" {
  bucket = var.bucket_name
}

 

module을 사용하는 입장에서는 모듈의 variable값을 초기화 가능합니다. variable이름과 값을 설정하여 간단히 초기화할 수 있습니다.

module "my-s3" {
  source = "./my-s3"

  # my-s3의 variable.tf
  bucket_name = "akbun-t101-week4-local-example"
}

 

Module 출력

예제코드 링크: https://github.com/sungwook-practice/terraform-study/tree/main/week4/module-output-example

module 출력은 module에서 output block에 설정된 값입니다. root module에서 module output을 받아 root output으로 설정하거나 다른 module의 input으로 사용할 수 있습니다.

 

module 출력을 사용하려면 module에서 output을 설정합니다. 그리고 module을 사용하는 쪽에서는 module.<name>.output으로 module ouput을 접근할 수 있습니다.

# module output
output "my_subnet1_id" {
  value       = aws_subnet.akbun-subnet1.id
  description = "subnet1"
}
module "my-vpc" {
  source = "./vpc"
}

resource "aws_instance" "example" {
  # module output 접근
  subnet_id  = module.my-vpc.my_subnet1_id
  ami           = "ami-0c76973fbe0ee100c"
  instance_type = "t2.nano"
  associate_public_ip_address = true

  tags = {
    Name = "t101-week4"
  }
}

 

vpc module에서 생성한 subnet을 참조하여 EC2 instance를 생성하는 예제를 살펴볼게요. 프로젝트 전체 구조는 아래와 같습니다.

 

vpc module의 output에는 생성한 subnet을 설정했습니다.

resource "aws_vpc" "akbun-vpc" {
  cidr_block       = "10.10.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "t101-study"
  }
}

resource "aws_subnet" "akbun-subnet1" {
  vpc_id     = aws_vpc.akbun-vpc.id
  cidr_block = "10.10.1.0/24"

  availability_zone = "ap-northeast-2a"

  tags = {
    Name = "t101-subnet1"
  }
}

resource "aws_internet_gateway" "akbun-igw" {
  vpc_id = aws_vpc.akbun-vpc.id

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

resource "aws_route_table" "myrt" {
  vpc_id = aws_vpc.akbun-vpc.id

  tags = {
    Name = "t101-rt"
  }
}

resource "aws_route_table_association" "myrtassociation1" {
  subnet_id      = aws_subnet.akbun-subnet1.id
  route_table_id = aws_route_table.myrt.id
}

resource "aws_route" "mydefaultroute" {
  route_table_id         = aws_route_table.myrt.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.akbun-igw.id
}

output "my_subnet1_id" {
  value       = aws_subnet.akbun-subnet1.id
  description = "subnet1"
}

 

root module의 main.tf에서는 vpc모듈 ouput를 참조하여 EC2 Instance를 생성합니다.

provider "aws" {
  region = "ap-northeast-2"
}

module "my-vpc" {
  source = "./vpc"
}

resource "aws_instance" "example" {
  subnet_id  = module.my-vpc.my_subnet1_id
  ami           = "ami-0c76973fbe0ee100c"
  instance_type = "t2.nano"
  associate_public_ip_address = true

  tags = {
    Name = "t101-week4"
  }
}

 

그림으로 표현하면 main.tf파일이 vpc모듈의 output에 정의된 값을 참조하고 있습니다.

 

Module과 레이아웃

module은 레이아웃과 같이 사용할 수 있습니다. 각 dev, stage, prod에서 사용하는 공통 리소스를 module로 관리합니다. 레이아웃을 사용할 때는 multi account를 사용하는 것을 권장합니다.

 

module file path

module을 사용해서 파일을 접근할 때 path설정이 중요합니다. 사용하는 module경로로 접근하려면 path.module을 사용합니다. 반대로 module을 사용하는 위치로 접근하려면 path.root 또는 path.cws를 사용하면 됩니다.

  • path.module : module이 위치한 경로를 리턴
  • path.root : root module 경로를 리턴
  • path.cwd : 현재 작업 중인 디렉터리의 경로를 리턴

 

예제에서는 root module에 foo.bar를 생성하는 module을 생성해보겠습니다

예제코드: https://github.com/sungwook-practice/terraform-study/tree/main/week4/path_module

 

프로젝트 구조는 아래와 같습니다. module 폴더 안에 module를 생성하고 dev, prd폴더에서 module을 사용합니다.

 

local_file_write module에는 local_file provider를 이용하여 foo.bar파일을 생성합니다. 생성경로는 모듈을 사용하는 root module에 생성할 수 있도록 path.root를 사용했습니다.

variable content {
  type        = string
  default     = "hello dev"
  description = "file content"
}

resource "local_file" "example" {
  content  = var.content
  filename = "${path.root}/foo.bar"
}

 

dev 또는 prd에서는 local_file_write module을 사용합니다.

module "name" {
  source  = "../module/local_file_write"
  content = "hello prd"
}

 

terraform apply명령어를 실행하면 각각 경로에foo.bar파일이 생성됩니다.

terraform apply

반응형