모듈이란
Modules are containers for multiple resources that are used together. A module consists of a collection of .tf
and/or tf.json files kept together in a directory.
Terraform 모듈은 인프라 코드를 재사용 가능하고 효율적으로 관리할 수 있도록 구성한 코드 블록입니다. 모듈은 여러 리소스를 하나의 단위로 묶어 처리할 수 있으며, 대규모 인프라를 관리할 때 코드의 중복을 줄이고 유지보수를 쉽게 합니다. 모듈은 작은 단위의 작업(예: VPC 생성, EC2 인스턴스 배포 등)을 수행하도록 설계되며, 필요에 따라 호출하여 사용할 수 있습니다.
-> 모듈을 이용해서 반복되는 코드를 제거하고 효율적으로 인프라 유지보수가 가능해진다.
요약하면,
입력 값을 받아 리소스를 생성하고, 생성된 리소스에서 필요한 정보를 출력하는 구조
입력값 -> 리소스 생성 -> 출력값
루트 모듈 (root module)
main working directory의 .tf파일로 정의된 모듈, 모든 테라폼 설정은 최소 하나의 루트 모듈을 가지고 있다.
우리가 테라폼을 실행하는 디렉토리의 main.tf에 정의된 모듈이라 생각하면 된다.
자식 모듈(child module)
테라폼 모듈을 다른 모듈을 호출할 수 있으며, 이때 호출되는 모듈을 자식 모듈이라 부른다. 자식 모듈을 동일한 구성에서 여러 번 호출이 가능하며, 여러 구성에서 동일한 자식 모듈을 호출할 수 있다.
게시된 모듈 (published module)
테라폼 모듈은 공개, 비공개 레지스트리에 게시하여, 불러와서 사용이 가능하다. 이 때, 공개된 레지스트리 (terraform registry...)에 등록되어 공개적으로 사용할 수 있는 모듈을 published module이라 한다.
표준 모듈 구조
기본적으로 표준 모듈 구조에 필수적인 요소는 루트 모듈 뿐이다.
terraform 파일은 반드시 레포지토리의 루트 디렉토리에 위치해야 한다.
다음은 권장 및 선택 사항이다.
- README : 루트 모듈과 중첩된 모든 모듈에는 README 파일이 존재해야 한다. README 파일에는 모듈에 대한 설명과 용도가 있어야 하며, 해당 모듈을 다른 리소스와 함께 사용하는 방법에 대한 예를 포함하기 위해선 example 디렉토리에 넣어야 한다. 예시
terraform-aws-consul/examples at master · hashicorp/terraform-aws-consul
A Terraform Module for how to run Consul on AWS using Terraform and Packer - hashicorp/terraform-aws-consul
github.com
- 라이센스 : 해당 모듈이 제공되는 라이센스 정보
- main.tf, variables.tf, outputs.tf 해당 파일들은 빈 내용일지라도 최소 모듈에 권장되는 파일이다. main.tf의 경우 모든 리소스가 생성되거나 나뉘어진 리소스들에 대해 nested module의 호출은 항상 main파일에서 일어나야 한다.
- main.tf : 모듈의 주요 리소스 정의 파일
- variables.tf : 모듈에 전달할 입력 변수 정의
- outputs.tf : 모듈에서 반환할 출력 값 정의
- Nested Modules : modules/ 하위 디렉토리 에 위치해야 하며, README.md가 존재하는 경우, 외부 사용자가 사용할 수 있는 것으로 간주, 없으면 내부 사용으로만 간주된다.
다음은 표준 구조를 따르는 최소 권장 모듈 구조이다.
$ tree minimal-module/
.
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
다음은 완전한 모듈의 예시 구조이다.
$ tree complete-module/
.
├── README.md
├── main.tf
├── variables.tf
├── outputs.tf
├── ...
├── modules/
│ ├── nestedA/
│ │ ├── README.md
│ │ ├── variables.tf
│ │ ├── main.tf
│ │ ├── outputs.tf
│ ├── nestedB/
│ ├── .../
├── examples/
│ ├── exampleA/
│ │ ├── main.tf
│ ├── exampleB/
│ ├── .../
모듈 사용 예시
s3-module/
├── main.tf
├── variables.tf
├── outputs.tf
main.tf
resource "aws_s3_bucket" "example" {
bucket = var.bucket_name # 입력 변수 bucket_name
acl = var.acl # 입력 변수 acl
}
variables.tf
variable "bucket_name" {
description = "The name of the S3 bucket" # 변수 설명
type = string # 데이터 유형 : 문자열
}
variable "acl" {
description = "The ACL for the S3 bucket"
type = string
default = "private" # 기본값 : private
}
outputs.tf
# 모듈에서 반환할 값 정의
output "bucket_arn" {
description = "The ARN of the S3 bucket"
value = aws_s3_bucket.example.arn
}
모듈 호출하여 사용하기
module "s3_bucket" {
source = "./s3-module" # 모듈 경로
bucket_name = "my-example-bucket" # 입력 변수 bucket_name 전달
acl = "public-read" # 입력 변수 acl 전달
}
# 모듈에서 반환된 "bucket_arn"을 출력으로 설정
output "s3_bucket_arn" {
value = module.s3_bucket.bucket_arn
}
흐름
모듈 s3_bucket을 호출 ->
입력 값으로 bucket_name과 acl 변수를 전달 ->
해당 변수를 기반으로 리소스 생성 ->
리소스 생성 결과 output으로 출력
Meta Arguments - providers
provider configuration은 AWS 리전, 인증 정보 등 구체적인 설정 값을 정의한다.
provider "aws" {
region = "us-west-1"
}
이러한 provider configuration은 암묵적으로 자식 모듈로 상속된다.
provider requirements는 해당 모듈에서 어떤 provider를 사용하고, 어떤 버전이 필요한지 정의한다.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "2.7.0"
}
}
}
이러한 요구사항은 부모 모듈에서 자동으로 상속되지 않기에, 직접 정의해야 한다.
만약 부모 모듈에서 여러 provider configuration을 정의하였거나, 자식 모듈이 부모 모듈과 다른 설정을 사용해야 하는 경우, 부모 모듈은 명시적으로 provider configuration을 자식 모듈에 전달해야 한다.
# The default "aws" configuration is used for AWS resources in the root
# module where no explicit provider instance is selected.
provider "aws" {
region = "us-west-1"
}
# An alternate configuration is also defined for a different
# region, using the alias "usw2".
provider "aws" {
alias = "usw2"
region = "us-west-2"
}
# An example child module is instantiated with the alternate configuration,
# so any AWS resources it defines will use the us-west-2 region.
module "example" {
source = "./example"
providers = {
aws = aws.usw2
}
}
- provider의 기본 동작은 부모 모듈에서 정의한 provider 설정은 기본적으로 자식 모듈로 상속된다.
- 하지만, 다른 provider를 자식 모듈에서 사용하고 싶다면, providers meta arguments를 사용하여 provider를 명시적으로 연결이 가능하다.
- default "aws" provider가 정의되어 있고, 그 밑에 "usw2"라는 alias를 가진 provider가 정의되어있다.
- 이 때, 자식 모듈에서는 default provider가 아닌 usw2 provider를 상속받고 싶다면, providers 인수를 통해 가능하다.
- 일반적으로, 이러한 상황은 동일한 클라우드 provider의 여러 다른 리전에서의 리소스를 관리하기 위해 하나의 구성을 사용할 때 발생한다.
provider "aws" {
alias = "usw1"
region = "us-west-1"
}
provider "aws" {
alias = "usw2"
region = "us-west-2"
}
module "tunnel" {
source = "./tunnel"
providers = {
aws.src = aws.usw1
aws.dst = aws.usw2
}
}
위와 같이 드물지만, 단일 모듈에 동일한 provider의 여러 구성이 필요할 수 있다.
예를 들면, 두 aws 리전의 네트워크 간 연결을 구성하는 모듈은 source와 destination이 모두 필요할 것이기 때문이다.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 2.7.0"
}
}
}
이 테라폼 모듈 provider 구성은 aws provider를 참조하며, 상세 정보는 "hashicorp/aws"의 버전 2.7.0 이상이 요구된다.
AWS 리전과 같이 엔드포인트를 결정하는 구성 설정(configuration settings)은 지정하지 않는다. 그 이유는 바로 위의 예시에서 알 수 있다.
모듈은 provider를 요구하지만, provider의 설정은 모듈 외부에서 정의한다.
Module sources
local path
module "consul" {
source = "./consul"
}
- 로컬 경로는 모듈 레지스트리 주소와 구별하기 위해 ./ 혹은 ../ 로 시작해야 한다.
- 테라폼은 '절대 파일 시스템 경로'(슬래시, 드라이브 문자 등으로 시작하는 경로)를 로컬 경로로 사용하지 않는다.
- 또한, 모듈을 참조하는데 '절대 파일 시스템 경로' 사용을 권장하지 않는다. 이는 구성을 특정 컴퓨터 파일시스템과 결합하기 때문이다.
terraform regitstry
module "consul" {
source = "hashicorp/consul/aws"
version = "0.1.0"
}
- 테라폼 모듈을 배포하는 기본적인 방벙이며, 공개적으로 공유되는 모듈이다.
- 주소의 형식은 다음과 같다. <NAMESPACE>/<NAME>/<PROVIDER>
Generic git repository
module "vpc" {
source = "git::https://example.com/vpc.git"
}
module "storage" {
source = "git::ssh://username@example.com/storage.git"
}
- git:: 이라는 특수한 접두사를 붙여 사용할 수 있다.
- git clone 을 실행하여 모듈을 설치한다.
- 이 때, 얕은 클론을 이용하여 큰 저장소의 경우 오래 걸리는 시간을 단축시킬 수 있다.
module "vpc" {
source = "git::https://example.com/vpc.git?depth=1&ref=v1.2.0"
}
S3 bucket
module "consul" {
source = "s3::https://s3-eu-west-1.amazonaws.com/examplecorp-terraform-modules/vpc.zip"
}
- us-east-1 리전의 경우 hostname으로 s3-us-east-1.amazonaws.com 대신 s3.amazonaws.com 을 사용해야 한다.
- 모듈 설치 프로그램은 다음의 위치에서 AWS 자격 증명을 찾고, 아래의 목록의 순서의 위치를 선호하게 된다.
- 환경변수 AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY
- 홈 디렉토리에 존재하는 default profile의 위치인 .aws/credentials
- EC2 인스턴스에서 실행하는 경우, 인스턴스 IAM 인스턴스 프로필과 연결된 임시 자격 증명
모듈 구성의 모범사례
테라폼은 기본적으로 Flat한 구조를 가지고 있다.
resource "aws_vpc" "example" {
cidr_block = "10.1.0.0/16"
}
resource "aws_subnet" "example" {
vpc_id = aws_vpc.example.id
availability_zone = "us-west-2b"
cidr_block = cidrsubnet(aws_vpc.example.cidr_block, 4, 1)
}
- aws_vpc 리소스에서 CIDR 블록을 설정
- aws_subnet 리소스에서 VPC의 ID를 가져와 서브넷을 연결
해당 구조는 리소스가 한 레벨에서 정의되며, 서로 간의 관계를 aws_vpc.example.id로 연결하는 평면적(Flat)인 구조이다.
여기에서 모듈을 도입하게 되면 구성이 평면적이기 보다는 계층적으로 변하는 경향이 있다.
module "vpc" {
source = "./modules/vpc"
cidr_block = "10.1.0.0/16"
}
module "subnet" {
source = "./modules/subnet"
vpc_id = module.vpc.vpc_id
}
- VPC를 생성하는 모듈은 독립적으로 관리된다.
- subnet을 생성하는 모듈은 VPC 모듈에서 생성된 vpc_id를 받아오게 된다.
- 두 모듈은 의존성(vpc -> subnet)이 생기게 되면서 계층 구조가 생기게된다.
- 리소스가 많아지게 된다면, 이러한 구조는 점차 복잡해질 것이다.
따라서, 테라폼은 모듈을 도입하더라도 Flat한 구조를 권장한다.
module "network" {
source = "./modules/aws-network"
base_cidr_block = "10.0.0.0/8"
}
module "consul_cluster" {
source = "./modules/aws-consul-cluster"
vpc_id = module.network.vpc_id
subnet_ids = module.network.subnet_ids
}
어떠한 특별한 기술이 도입된건 아니다.
단지, network라는 새로운 모듈을 구성하고, 이 모듈에서 VPC와 subnet을 동시에 생성하도록 하여 또다른 모듈에 출력값을 전달하는 구조이다.
- 각 모듈이 독립적으로 동작하도록 만든다. / 모듈은 다른 모듈에 종속적이지 않고, 입/출력 값만 주고 받는다.
- 루트 모듈이 모든 관계를 조정 : 의존성을 루트 모듈에서 관리해 복잡성을 줄인다.
자식 모듈끼리 얽히고 종속성이 생기는 구조에서 자식 모듈 -> 루트 모듈의 구조 (중앙 집중화)로 변경하여 Flat한 구조를 만든 것이다.
이런 구조를 도입하면
- 유지보수가 용이함 - 각 모듈이 독입적이고, 루트 모듈에서 관계를 관리하므로, 코드가 간결해지며 추적하기 쉽다.
- 재사용성 증가 - 모듈이 독립적이므로, 다른 프로젝트에서 재사용하기 쉽다.
- 복잡성 감소 - 디버깅과 관리가 쉽다.
이와 같은 장점을 가질 수 있다.
(예정) - 대규모 시스템 구성에 유용한 구체적인 구성 패턴
https://developer.hashicorp.com/terraform/language/modules/develop/composition
Module Composition | Terraform | HashiCorp Developer
Module composition allows infrastructure to be described from modular building blocks.
developer.hashicorp.com
'IaC' 카테고리의 다른 글
테라폼 스터디 6주차 (0) | 2025.01.12 |
---|---|
스터디 5주차 - 모듈 추가 내용 (0) | 2025.01.05 |
테라폼 스터디 - 4주차 (1) | 2024.12.29 |
테라폼 스터디 - 3주차 추가내용 (0) | 2024.12.22 |
테라폼 스터디 3주차 (1) | 2024.12.22 |