Study_note
[Terraform] 모듈 (입력 변수, 지역 변수, 출력 변수, 파일 경로, 인라인 블록) 본문
아래 그림은 스테이징 환경 밖에 없지만 후에 prod, dev 환경을 구축한다면 스테이징에서 코드를 전부 하드 코딩하지 않고
prod, dev 환경을 추가하는 방법이 모듈이다
즉
여러 환경, 리전에 같은 인프라를 배포할 때, 목적에 따라 똑같은 인프라를 여러 개 배포할 필요가 있을 때
사용하는것이 모듈이다
모듈을 어떻게 생성하고, 효율적으로 관리 할지는 적어본다
우선 모듈 폴더를 생성하고 모듈 파일을 만드는데 모듈 파일은 일반 tf파일과는 다르게 provider 내용이 없고
모듈을 사용할 tf파일에서 provider를 아래와 같이 지정해준다.
provider "aws" { # 모듈을 사용하는 tf파일은 생성자 입력
region = "us-east-2"
}
module "webserver_cluster" { # 모듈 이름 지정
source = "../../../modules/services/webserver-cluster" # 모듈 경로 지정
또한 모듈은 var.tf 파일을 만들어 입력 매개 변수를 만들 수 있다.
입력 변수를 사용하면 모듈을 사용하는 tf파일들을 알맞게 커스텀할 수 있다.
variable "cluster_name" { # 클러스터 네임을 입력 변수로 지정
description = "The name to use for all the cluster resources"
type = string
}
variable "db_remote_state_bucket" { # remote_state를 입력 변수로 사용하기 위해 변수 지정
description = "The name of the S3 bucket for the database's remote state"
type = string
}
variable "db_remote_state_key" { # remote_state를 사용하기 위해 입력변수로 사용
description = "The path for the database's remote state in S3"
type = string
}
이렇게 만든 환경변수들을 모듈파일에 넣고 모듈을 사용하는 파일에서 변수를 입력해준다.
# 모듈 파일에 다음과 같이 환경 변수를 생성한 변수들을 입력
resource "aws_security_group" "alb" {
name = "${var.cluster_name}-alb"
}
data "terraform_remote_state" "db" {
backend = "s3"
config = {
bucket = var.db_remote_state_bucket
key = var.db_remote_state_key
region = "us-east-2"
}
}
------------------------------
변수를 지정한 목록들을 모듈을 사용할 파일에서 다음과 같이 입력해주어 사용
module "webserver_cluster" {
source = "../../../modules/services/webserver-cluster"
cluster_name = "webservers-stage"
db_remote_state_bucket = "(bucket_name)"
db_remote_state_key = "remote_state로 가져올 원격 backend tfstate파일 경로"
이렇듯 remote_state 버킷, 키 경로 뿐만 아니라 오토스케일링 최소,최대 값, 인스턴스 타입 등도 입력 변수로 지정해 모듈을 사용하는 파일 마다 값을 다르게 사용가능하다.
모듈에서는 입력 변수 말고 지역 변수도 자주 사용되는데
하드코딩된 부분들을 입력 변수로 값을 추출할 수 있지만 실수로 변수를 다르게 지정할 수 있기 때문에
local을 사용하여 모듈내에서 특정 값들을 지역 변수로 지정 가능하다.
지역 변수를 사용하면 자주 바뀌는 값들을 변수 하나만 바꾸면 되기 때문에 효율이 높아진다.
(하드 코딩을 최대한 피하고 변수를 사용하여 자주 바뀌는 값들을 지정해서 효율을 높히자)
# 모듈에 아래와 같이 보안그룹 인그레스를 설정한다 할떄
# 포트같이 자주 바뀔수 있는 값은 변수를 취하면 효율적이기 때문에 local 지역변수로 바꿔보면 아래와 같다
resource "aws_security_group_rule" "allow_http_inbound" {
type = "ingress"
security_group_id = aws_security_group.alb.id
from_port = 80
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
----------------------------
# 아래와 같이 포트, 프로토콜, cidr를 지역 변수 취했다
locals {
http_port = 80
any_port = 0
any_protocol = "-1"
tcp_protocol = "tcp"
all_ips = ["0.0.0.0/0"]
}
----------------------------
# 변수를 취한 후 아래와 같이 사용 (지역 변수는 모듈 내부에 있어야한다.)
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
}
모듈을 사용하고 리소스를 추가할때 모듈 내에 정의되어 있는값을 엑세스 해야할때가 있다
그럴때는 출력 변수를 사용하여 모듈 내에 정의 되어있던 변수값 출력
아래 형태로 모듈 내 정의되어있는 값 엑세스
module.<module name>.<output name>
resource "aws_autoscaling_schedule" "scale_out_during_business_hours" {
scheduled_action_name = "scale-out-during-business-hours"
min_size = 2
max_size = 10
desired_capacity = 10
recurrence = "0 9 * * *"
# 필수 매게 변수인 autoscaling_group_name의 값을 넣어줘야하는데 이 변수의 값은 모듈 내에 정의 되어
# 있어 아래 처럼 따로 엑세스 해야한다
autoscaling_group_name = module.webserver_cluster.asg_name
}
### 아래 형태로 모듈 내 정의되어있는 값 엑세스
module.<module name>.<output name>
# 모듈이 있는 디렉토리에 output 파일 추가
output "asg_name" {
value = aws_autoscaling_group.example.name
description = "The name of the Auto Scaling Group"
}
파일경로
내장 함수인 file을 사용하면 파일을 읽을수 있는데 파일 함수를 사용할 때 파일 경로가 상대 경로여야 한다
하지만 상대 경로를 쓴다는것은 테라폼 구성 파일(terraform.tfstate)에서 file 함수를 사용한다는 말인데
이말은 즉 별도 폴더에 정의된 모듈에서는 file 함수를 사용하지 못한다는것이다
이러한 문제점을 해결하려 나온게 파일 경로다
path.module : 표현식이 정의된 모듈의 파일 시스템 경로를 반환한다.
# path.module을 통해 파일 경로를 반환시켜 모듈을 사용해도 파일을 사용 가능하게 한다.
user_data = templatefile("${path.module}/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
})
여기서 위 코드를 이해하면 공부한것들을 복습할 수 있는데
"${path.module}/user-data.sh" - user-data.sh라는 파일을 모듈이 있는 경로에서 가져온다
templatefile - 템플릿 파일 사용 가능한 내장 함수
var.server_port - server_port를 모듈 경로에 있는 var.tf 파일에서 가져온다
data.terraform_remote_state.db.outputs.address/port
-> 원격 백엔드 기능인 S3 버킷의 특정 경로에 저장된 상태 정보 파일을 terraform_remote_state를 통해 가져온다
즉 outputs를 통해 상태파일에 출력값을 저장하고 업데이트 된 상태파일을 s3에 저장하고 remote_state를 통해 address와 port 출력 값을 가져오는 것이다.
마지막으로 인라인 블록이다
블록 내부에 있는 블록을 인라인 블록이라 하는데, 모듈을 만들 때는 항상 별도의 리소스를 사용하는 것이 좋다
모듈을 호출한 루트 모듈이 보안 그룹을 불러올 때, 보안 그룹 리소스 내의 igress/egress 규칙을 추가할 수 없고
모듈 호출 시 사용자가 보안 그룹의 규칙 추가를 위해 aws_security_group 리소스를 aws_security_group 리소스와 aws_security_group_rule 리소스로 나눈어 추가 해준다.
aws_security_group_rule를 통해외부에서 사용자 정의 규칙을 추가할 수 있게 모듈을 유현한게 만들 수 있다
여기서 만약 ingress는 인라인으로 두고, egress는 분리시키거나 이러한 방식은 불가하다 라우팅 규칙이 충돌하여 서로 덮어쓰는 오류 발생하기 때문에 나누거나, 합치거나 둘 중 한 가지 방법만 사용해야 한다.
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.http_port
to_port = local.http_port
protocol = local.tcp_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
}
위에 변수파일들을 생성해주면 아래와 같은 형태의 파일 경로들이 생성된다.
'Terraform' 카테고리의 다른 글
EKS Upgrade 1.22 -> 1.23 version (0) | 2023.03.13 |
---|---|
[etc] systemd 및 service 등록 (0) | 2023.03.09 |
[Terraform] 반복문, if문 (for, for_each, count, if) (0) | 2022.10.11 |
[Terraform] 상태 파일, 원격 Backend, remote_state (2) (1) | 2022.09.29 |
[Terraform] Terraform up & running 학습 및 기본 문법 (1) (0) | 2022.09.27 |