각 환경( 스테이징, 프로덕션 .. )의 인프라는 거의 동일하지만 미세한 차이가 있는 정도
⇒ 코드를 복사하여 붙여넣기
⇒ HCL에서 중복되는 코드를 모듈로 만들어서 여러 위치에서 재사용
( 범용프로그래밍 언어에서 동일한 코드를 함수내부에 배치하여 재사용하는 개념과 유사 )
코드 이전작업없이 모듈을 참조하여 동일한 코드환경을 가지게 됨( 재사용성 )
⇒ 모듈이란 여러환경에서 동일한 인프라환경을 구축하기 위해 사용하는 기술
기능 디렉토리별로 모듈을 만든다고 생각함( services/web-cluster, services/data-store 등 )
- root 모듈 : terraform apply 명령을 수행하는 위치, 직접 적용을 실행하는 모듈
- other 모듈 : 테라폼 구성파일세트, 루트 모듈 안에서 module 블록을 사용하여 하위 모듈을 참조하고 사용하는 대상 → 재사용가능 외부 디렉토리, terraform registry(공식 저장소), git 등에 존재함
모듈기본
(1) 모듈설정
- module이라는 최상위 폴더를 만들고 웹서버구축하는 테라폼 파일을 모두 배치
tfd이후 복사 cp -r stage module
stage/services/webserver-cluster의 모든 파일 → module/services/webservercluster의 경로로 이동
- 공급자 설정 제거 → 루트 모듈에서만 존재해야함
vi module/services/webserver-cluster/main.tf
provider “aws” 블럭제거 & 기존 리소스 정의내용 유지
(2) 모듈호출
[ 모듈호출구문 ]
module "<NAME>" {
source = "<SOURCE>"
[CONFIG ...]
}
- NAME : 테라폼 전체 코드에서 모듈을 참조하는 식별자
- source : 모듈코드를 찾을 수 있는 경로 새로운 모듈을 적용(apply)하기 전에 항상 terraform init명령을 실행( initializing modules = 다운로드 )
- config : 모듈과 관련된 인수 → 모듈에서 사용할 변수값을 지정( apply환경에 맞게 동적 설정 )
[ 루트모듈 : stage/services/webserver-cluster/main.tf ]
provider "aws" {
region = "ap-northeast-2"
}
module "webserver_cluster" {
source = "../../../modules/services/webserver-cluster"
}
⇒ 프로바이더는 caller(root module)에서 정의 & 나머지 리소스 정의 코드는 모듈을 호출하는 것으로 대체
module의 source : local의 모듈 경로 혹은 외부에서 사용할 모듈주소
모듈입력
[ 변수사용 메커니즘 ]
: 모듈 디렉토리 하에서 입력변수파일을 정의(variables.tf) & 사용(main.tf) → 루트 모듈에서 호출하여 사용할때 변수값 치환 및 지정가능
( 범용프로그래밍 언어의 함수가 매개변수를 가지는 것처럼 모듈에도 입력변수를 적용가능 )
(1) 데이터베이스 원격 상태에 대한 입력 변수 추가 ( 클러스터명, 공유저장소 버킷 영역 변수화 )
환경에 따라 다른 값으로 설정되는 변수( ex. 프로덕션 환경과 스테이지 환경에서 리소스 상태파일 저장소 루트(db_remote_state_key)는 상이함 )
모듈내 변수파일( modules/services/webserver-cluster/variables.tf )에서 변수로 선언
modules/services/webserver-cluster/variables.tf
variable "cluster_name" {
description = "The name to use for all the cluster resources"
type = string
}
variable "db_remote_state_bucket" {
description = "The name of the S3 bucket for the database's remote state"
type = string
}
variable "db_remote_state_key" {
description = "The path for the database's remote state in S3"
type = string
}
모듈내 실행파일(modules/services/webserver-cluster/main.tf)에서 변수참조식으로 이를 활용 ( var.변수명 )
(2) 리소스 환경 구성에 대한 입력변수 추가 ( 인스터스 타입, ASG 최대최소값 변수화 )
환경에 따라 다른 값으로 구축가능한 변수( ex. 스테이지 환경에서는 비용절감을 위해 더 적은 웹서버 클러스터 실행, 소규모 타입으로 구성 ↔ 실제 프로덕션 환경에서는 대량 트래픽을 처리하기 위해 많은 웹서버 클러스터 실행, 대규모 타입으로 구성 )
모듈내 변수파일( modules/services/webserver-cluster/variables.tf )에서 변수로 선언
모듈내 실행파일(modules/services/webserver-cluster/main.tf)에서 변수참조식으로 이를 활용 ( var.변수명 )
(3) 루트 모듈에서 반드시 선언한 변수값을 정의
stage/services/webserver-cluster/main.tf
해당모듈 내에 변수값을 정의
입력 변수는 모듈의 API로, 모듈이 다양한 환경에서 어떻게 작동할지 제어
모듈지역화
: 모듈내에서만 변수를 사용가능하도록 제어( 입력값의 오류방지 )
중복값에 대한 효율적인 처리를 위해 모듈변수를 사용하되( 코드를 DRY로 유지 ) 변수를 외부에 노출하고 싶지 않은 경우( 오류방지, 보안 등.. )
- 선언 : locals 블록항목에서 변수명&값 설정( main.tf하단 혹은 별도의 locals.tf로 분리 )
- 참조 : local.<NAME>
LB의 port = LB에 적용되는 security그룹의 ingress port = 80으로 지정
⇒ 변수로 설정( 하드코딩X ) 그러나 모듈 이외의 임의영역에서 접근 및 설정불가하도록 지정 ( 루트모듈에서도 설정불가 )
[ 로컬변수 실습 ]
(1) 모듈의 main.tf 하단에 지역변수를 선언 → 별도의 locals.tf를 구축하여 값을 지정 및 선언하는 것이 효과적임
~/terraform-demo/environment/modules/services/webserver-cluster/main.tf
....
locals {
http_port = 80
any_port = 0
any_protocol = "-1"
tcp_protocol = "tcp"
all_ips = ["0.0.0.0/0"]
}
(2) 로컬변수를 랜더링하도록 수정
~/terraform-demo/environment/modules/services/webserver-cluster/main.tf
*modules/services/webserver-cluster/variables.tf 에 정의한 변수들과는 상이함 : 외부 입력불가능, local.변수로 참조( ≠ var.변수 )
모듈 출력
모듈에서 출력하는 output 값 지정( 생성한 리소스에 대한 추가정보 ) → 루트 모듈에서 이를 참조하고 활용할 수 있도록 하면 효율적임
[ 모듈의 출력변수 정의 ] 모듈내 outputs.tf 혹은 main.tf
output "asg_name" {
value = aws_autoscaling_group.example.name
description = "The name of the Auto Scaling Group"
}
output.tf로 분리하여 정의가능하나 main.tf에 통합하여 정의하도록함
[ 모듈 출력변수 참조방식 ]
module . <MODULE_NAME> . <OUTPUT_NAME>
[ 모듈 출력변수 참조 ] 루트모듈 내 main.tf
해당 모듈의 해당 output변수값을 참조
output "alb_dns_name" {
value = module.webserver_cluster.alb_dns_name
description = "The domain name of the load balancer"
}
루트 모듈에서 terraform apply 실행시 출력변수가 제대로 출력된다.
모듈 고려사항
(1) 파일경로
Terraform의 경로참조 표현식 path.<TYPE>
- 경로.모듈 (path.module) : 표현식이 정의된 모듈의 파일 시스템 경로를 반환
- 경로.루트 (path.root) : 루트 모듈의 파일 시스템 경로를 반환
- 경로.cwd (path.cwd) : 현재 작업 디렉터리의 파일 시스템 경로를 반환 ( 일반적으로 path.root와 동일 )
templatefile함수에서 사용하는 파일은 항상 상대경로를 기준으로 지정(Terraform 코드는 각기 다른 디스크 레이아웃을 가진 여러 컴퓨터에서 실행될 수 있으므로 절대 파일 경로를 피하는게 좋음 )
Terraform은 현재 작업 디렉토리를 기준으로 경로를 해석 → 루트모듈이 존재하는 작업디렉토리에서 파일을 탐색하게 됨
resource "aws_launch_configuration" "example" {
image_id = "ami-024ea438ab0376a47"
instance_type = var.instance_type
security_groups = [aws_security_group.instance.id]
user_data = templatefile("user-data.sh",{
server_port = var.server_port
db_address = data.terraform_remote_state.db.outputs.address
db_port = data.terraform_remote_state.db.outputs.port
})
lifecycle {
create_before_destroy = true
}
}
root모듈에 모듈에서 사용하는 파일을 다운로드하여 직접 참조
하지만 이는 바람직하지 않음 모듈내에 참조할 파일이 함께 제공되는 것이 일반적이고 이를 사용해야함 → 모듈경로를 기준으로 상대경로로 참조 ( 변경 및 오류 대응가능, 효율적 )
먼저 루트모듈경로로 복사해온 모듈의 파일은 삭제한다 -> 모듈내의 해당 user_data.sh를 사용한다.
경로참조 표현식에서 모듈 경로를 나타내는 ${path.module}을 이용하여 파일의 상대경로를 완성한다.
사실상 변경사항은 없다.
(2) 인라인 블록
리소스 내에 설정하는 인수
resource "type" "name" {
<NAME> {
[CONFIG...]
}
}
NAME은 인라인 블록의 이름(예: ingress )이고 CONFIG는 해당 인라인 블록(예: from_port 및 to_port)과 관련된 하나 이상의 인수로 구성
인라인 블록과 별도의 리소스를 혼합하여 사용하려고 하면 Terraform의 설계 방식으로 인해 구성이 충돌하고 서로 덮어쓰는 오류가 발생 → 별도의 리소스 사용을 권장
[ 인라인 방식 ]
resource "aws_security_group" "alb" {
name = "${var.cluster_name}-alb"
ingress {
from_port = local.http_port
to_port = local.http_port
protocol = local.tcp_protocol
cidr_blocks = local.all_ips
}
egress {
from_port = local.any_port
to_port = local.any_port
protocol = local.any_protocol
cidr_blocks = local.all_ips
}
}
[ 별도 모듈 방식 ]
resource "aws_security_group" "alb" {
name = "${var.cluster_name}-alb"
}
resource "aws_security_group_rule" "allow_http_inbound" {
type = "ingress"
security_group_id = aws_security_group.alb.id
from_port = local.http_port
to_port = local.http_port
protocol = local.tcp_protocol
cidr_blocks = local.all_ips
}
resource "aws_security_group_rule" "allow_all_outbound" {
type = "egress"
security_group_id = aws_security_group.alb.id
from_port = local.any_port
to_port = local.any_port
protocol = local.any_protocol
cidr_blocks = local.all_ips
}
모듈버저닝
모듈에 태그를 붙여서 버전별로 관리 가능
동일한 모듈을 사용하여 여러 환경에 배포할때 적용된 환경에 따라 모듈 버전을 지정( 스테이징에서 한 버전(예: v0.0.2)을 사용하고 프로덕션에서 다른 버전 (예: v0.0.1)을 사용 )
git tag를 통해 업로드하는 모듈의 버전을 명시
'CLOUDWAVE' 카테고리의 다른 글
IaC : Terraform - 테라폼 상태관리 및 상태파일(tfstate) (1) | 2025.02.07 |
---|---|
IaC : Terraform 실습 - 웹클러스터 배포, 로드밸런서 배포, 자원반환 (0) | 2025.02.07 |
IaC : Terraform 실습 - 단일 서버배포, 단일 웹서버배포, 구성가능한 웹서버배포 (0) | 2025.02.07 |
IaC : Terraform - 테라폼 소개, 테라폼 환경 구축 (0) | 2025.02.07 |
IaC : Ansible 변수관리 및 작업제어 (0) | 2025.02.01 |