근묵자흑
테라폼 팁과 요령: 반복문, if문, 배포 및 주의사항 본문
1. 반복문 활용하기
1.1 count 매개 변수를 이용한 반복
count는 테라폼에서 가장 기본적인 반복 방법입니다. 동일한 리소스를 여러 개 생성할 때 사용합니다.
resource "aws_instance" "web" {
count = 3 # 3개의 동일한 인스턴스를 생성
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "web-server-${count.index}" # 각 인스턴스에 순차적인 이름 부여
}
}
상세 설명:
count = 3
: 리소스를 3번 반복 생성합니다.count.index
: 0부터 시작하는 인덱스 값을 제공합니다.- 생성되는 인스턴스 이름: "web-server-0", "web-server-1", "web-server-2"
- 참조 방법:
aws_instance.web[0]
,aws_instance.web[1]
,aws_instance.web[2]
활용 사례:
- 여러 가용 영역에 걸친 서버 배포
- 개발/테스트 환경의 다중 인스턴스 생성
- 로드 밸런서의 타겟 그룹 구성
1.2 for_each를 사용한 반복문 처리
for_each는 map이나 set을 이용해 더 유연한 반복문을 구현할 수 있습니다. count와 달리 각 리소스에 고유한 식별자를 부여할 수 있습니다.
variable "instances" {
type = map(object({
instance_type = string
environment = string
}))
default = {
"web-1" = {
instance_type = "t2.micro"
environment = "dev"
}
"web-2" = {
instance_type = "t2.small"
environment = "staging"
}
}
}
resource "aws_instance" "web" {
for_each = var.instances # map을 기반으로 인스턴스 생성
ami = "ami-0c55b159cbfafe1f0"
instance_type = each.value.instance_type # map의 value에서 인스턴스 타입 참조
tags = {
Name = each.key # map의 key를 이름으로 사용
Environment = each.value.environment # map의 value에서 환경 정보 참조
}
}
상세 설명:
for_each = var.instances
: map 형태의 변수를 반복 처리each.key
: map의 키 값 참조 ("web-1", "web-2")each.value
: map의 값 참조 (instance_type, environment 등의 객체)- 참조 방법:
aws_instance.web["web-1"]
,aws_instance.web["web-2"]
활용 사례:
- 서로 다른 구성의 서버 배포
- 다중 환경(개발/스테이징/운영) 리소스 관리
- 태그 기반의 리소스 관리
1.3 for 표현식을 이용한 반복문 처리
for 표현식은 리스트나 맵의 데이터를 변환하여 새로운 데이터 구조를 만들 때 사용합니다.
locals {
instance_types = ["t2.micro", "t2.small", "t2.medium"]
instance_tags = {
for type in local.instance_types : # 리스트를 map으로 변환
type => {
size = split(".", type)[1] # "micro", "small", "medium" 추출
tier = type == "t2.micro" ? "free" : "paid" # 조건에 따른 tier 설정
}
}
}
상세 설명:
- 입력: ["t2.micro", "t2.small", "t2.medium"]
- 출력 예시:
{ "t2.micro" = { size = "micro" tier = "free" } "t2.small" = { size = "small" tier = "paid" } "t2.medium" = { size = "medium" tier = "paid" } }
활용 사례:
- 리소스 태그 정책 관리
- 복잡한 데이터 구조 변환
- 동적 리소스 구성
1.4 문자열 지시자를 사용하는 반복문
문자열 지시자를 사용하여 동적으로 문자열을 생성하고 처리할 수 있습니다.
locals {
subnet_ids = ["subnet-1", "subnet-2", "subnet-3"]
formatted_subnets = [
for id in local.subnet_ids :
format("subnet-%s", id) # 문자열 포맷팅
]
# 여러 줄의 문자열 생성
user_data = <<EOT
%{ for id in local.subnet_ids ~}
subnet_id=${id}
%{ endfor ~}
EOT
}
상세 설명:
format
함수: 문자열 템플릿 생성~
: 줄바꿈 제어- 출력 예시:
subnet_id=subnet-1 subnet_id=subnet-2 subnet_id=subnet-3
활용 사례:
- 사용자 데이터 스크립트 생성
- 구성 파일 템플릿 생성
- 동적 정책 문서 생성
2. 조건문
2.1 count 매개 변수를 사용한 조건문
count를 사용하여 조건부로 리소스를 생성할 수 있습니다.
resource "aws_eip" "lb" {
count = var.environment == "production" ? 1 : 0 # 프로덕션 환경에서만 생성
vpc = true
}
상세 설명:
- 조건이 참이면 리소스 생성 (count = 1)
- 조건이 거짓이면 리소스 미생성 (count = 0)
- 참조 방법:
aws_eip.lb[0].id
(리소스가 생성된 경우에만 가능)
활용 사례:
- 환경별 선택적 리소스 생성
- 실험적 기능의 조건부 활성화
- 비용 최적화를 위한 리소스 제어
2.2 for_each와 for 표현식을 사용한 조건문
map이나 set의 요소를 필터링하여 조건부로 리소스를 생성할 수 있습니다.
locals {
prod_instances = {
for name, instance in var.instances :
name => instance
if instance.environment == "production" # 프로덕션 환경 인스턴스만 필터링
}
}
resource "aws_instance" "prod" {
for_each = local.prod_instances # 필터링된 인스턴스만 생성
ami = "ami-0c55b159cbfafe1f0"
instance_type = each.value.instance_type
}
상세 설명:
- map의 각 요소를 조건으로 필터링
- 조건을 만족하는 요소만으로 새로운 map 생성
- 필터링된 map을 기반으로 리소스 생성
활용 사례:
- 특정 조건의 리소스만 선택적 생성
- 태그 기반 리소스 필터링
- 환경별 리소스 구성 관리
2.3 if 문자열 지시자가 있는 조건문
문자열 템플릿 내에서 조건부로 내용을 포함할 수 있습니다.
locals {
environment = terraform.workspace
common_tags = {
Environment = local.environment
Project = "MyProject"
Managed_By = "Terraform"
%{ if local.environment == "production" }
Backup = "true"
Monitoring = "enhanced"
%{ endif }
}
}
상세 설명:
- 조건에 따라 추가 태그 포함
- 들여쓰기와 줄바꿈 제어 가능
- 중첩 조건문 사용 가능
활용 사례:
- 환경별 태그 정책 적용
- 조건부 구성 파일 생성
- 동적 IAM 정책 생성
3. 무중단 배포
1. 주요 구성 요소
Launch Configuration
resource "aws_launch_configuration" "example" {
lifecycle {
create_before_destroy = true
}
}
- 인스턴스 시작 구성을 정의
create_before_destroy = true
로 설정하여 무중단 배포 지원- 사용자 데이터를 통한 애플리케이션 구성 가능
Auto Scaling Group (ASG)
resource "aws_autoscaling_group" "example" {
name = "${var.cluster_name}-${aws_launch_configuration.example.name}"
min_elb_capacity = var.min_size
lifecycle {
create_before_destroy = true
}
}
- ASG 이름에 Launch Configuration 이름을 포함하여 변경 감지
min_elb_capacity
를 통해 최소 정상 인스턴스 수 보장create_before_destroy
로 무중단 업데이트 지원
2. 무중단 배포 메커니즘
- 블루 그린 배포
- 새로운 Launch Configuration 생성
- ASG 업데이트 (이름 변경으로 인한 신규 ASG 생성)
- 새로운 인스턴스 생성 및 상태 확인
- 이전 인스턴스 제거
4. 테라폼의 주의사항
4.1 count와 for_each 제한 사항
Terraform의 count와 for_each는 강력한 기능이지만 몇 가지 중요한 제한 사항이 있습니다.
1. 리소스 출력을 count 또는 for_each에서 참조할 수 없음
# 잘못된 예시
resource "aws_instance" "server" {
count = aws_instance.other.id != "" ? 1 : 0 # 오류: 리소스 출력을 count에서 참조
ami = "ami-0c55b159cbfafe1f0"
}
# 올바른 예시
variable "create_instance" {
type = bool
default = true
}
resource "aws_instance" "server" {
count = var.create_instance ? 1 : 0 # 변수를 사용하여 조건부 생성
ami = "ami-0c55b159cbfafe1f0"
}
2. module 내에서의 count와 for_each 제한
# 잘못된 예시
module "servers" {
source = "./app_server"
count = length(var.subnet_ids) # 모듈에서는 count 사용 불가
}
# 올바른 예시
resource "aws_instance" "servers" {
count = length(var.subnet_ids)
subnet_id = var.subnet_ids[count.index]
}
4.2 무중단 배포의 제한 사항
1. create_before_destroy 제한
- 모든 리소스가 create_before_destroy를 지원하지 않음
- 데이터베이스와 같은 상태 유지가 필요한 리소스는 특별한 처리 필요
- 의존성이 있는 리소스들 간의 순서 보장이 어려움
# 예시: create_before_destroy 사용
resource "aws_launch_configuration" "example" {
# ... 설정 ...
lifecycle {
create_before_destroy = true
}
}
2. 작업 시간 증가
- 리소스 생성 후 삭제까지 시간이 두 배로 소요
- 리소스가 많을 경우 전체 배포 시간 증가
4.3 유효한 plan의 실패
핵심은 terraform plan이 테라폼 상태 파일의 리소스만 확인한다는 것입니다. AWS 콘솔을 수동으로 클릭하는 등 테라폼 영역 밖에서 리소스를 생성하면 테라폼의 상태 파일에 포함되지 않으므로 plan 명령을 실행할 때 테라폼이 이를 고려하지 않습니다.
그리므로 유효하게 보이는 plan도 실패 할 수 있습니다.
1. 테라폼을 사용하기 시작했다면 테라폼만 사용해야 합니다.
2. 기존 인프라가 있을경우 import 명령을 사용해야 합니다.
4.4 리팩토링의 까다로움
코드형 인프라(Infrastructure as Code)에서는 코드의 외부 동작
을 정의하는 요소에 특별히 주의를 기울여야 합니다. 이는 실제 인프라에 직접적인 영향을 미치기 때문입니다.
1. 항상 plan 명령을 사용
# 리팩토링 전 상태 확인
terraform plan
// 예상치 못한 변경사항 예시
resource "aws_instance" "example" {
- ami = "ami-0c55b159cbfafe1f0" -> null
+ ami = "ami-new-version" # 완전한 교체 발생
instance_type = "t2.micro"
}
주의사항
- 모든 변경 사항을 적용하기 전에 반드시 plan 확인
- 예상치 못한 리소스 재생성이 없는지 검토
- 특히 프로덕션 환경에서는 더욱 신중하게 검토
2. 파기하기 전에 생성하기 (Create Before Destroy)
resource "aws_launch_configuration" "example" {
image_id = "ami-0c55b159cbfafe1f0"
lifecycle {
create_before_destroy = true # 새 리소스 생성 후 이전 리소스 제거
}
}
resource "aws_autoscaling_group" "example" {
name = "${var.cluster_name}-${aws_launch_configuration.example.name}"
lifecycle {
create_before_destroy = true
}
}
적용 시나리오
- 새로운 리소스 생성
- 상태 확인 및 검증
- 트래픽 전환
- 이전 리소스 제거
3. 식별자 변경을 위한 상태 변경
# 리소스 이름 변경 시
terraform state mv 'aws_instance.old_name' 'aws_instance.new_name'
# 모듈 간 리소스 이동 시
terraform state mv 'module.old.aws_instance.example' 'module.new.aws_instance.example'
주의사항
1. 상태 파일 백업
terraform state pull > terraform.tfstate.backup
2. 단계적 변경
// 1단계: 새 리소스 추가
resource "aws_instance" "new_name" {
// 설정
}
// 2단계: state 이동
// terraform state mv 'aws_instance.old_name' 'aws_instance.new_name'
// 3단계: 이전 리소스 제거
4. 일부 매개 변수는 변경할 수 없음
resource "aws_instance" "example" {
// 변경 불가능한 매개변수
availability_zone = "us-west-2a" # 변경 시 인스턴스 재생성 필요
// 변경 가능한 매개변수
instance_type = "t2.micro" # 인스턴스 중지 후 변경 가능
tags = {
Name = "example" # 즉시 변경 가능
}
}
변경 불가능한 주요 매개변수
1. EBS 볼륨
resource "aws_ebs_volume" "example" {
availability_zone = "us-west-2a" # 변경 불가
size = 40 # 증가만 가능
}
2. RDS 인스턴스
resource "aws_db_instance" "example" {
engine = "mysql" # 변경 불가
allocated_storage = 20 # 증가만 가능
}
해결 전략
1.임시 리소스 사용
// 1. 새 리소스 생성
resource "aws_instance" "example_new" {
availability_zone = "us-west-2b"
}
// 2. 데이터 마이그레이션
// 3. 이전 리소스 제거
resource "aws_instance" "example" {
count = 0 // 또는 리소스 블록 제거
}
2. 블루-그린 배포 활용
resource "aws_autoscaling_group" "example" {
name = "${var.cluster_name}-v${var.version}"
lifecycle {
create_before_destroy = true
}
}
'IaC > terraform' 카테고리의 다른 글
Terraform Mocks (4) | 2025.02.02 |
---|---|
프로덕션 수준의 테라폼 코드 (3) | 2025.01.19 |
Terraform Module (8) | 2025.01.05 |
Terraform State (3) | 2024.12.29 |
테라폼 로드밸런서 배포 (5) | 2024.12.22 |