Terraform은 인프라를 코드로 관리하는 IaC(Infrastructure as Code) 도구입니다. 이는 선언적 관리로 안정적이고 일관된 인프라 프로비저닝을 지원하죠. 그러나 팀이 커지고 환경이 다양해지면, Terraform을 사용할 때 코드 중복과 관리 복잡도 문제가 생깁니다. 이 글에서는 모듈화, 워크스페이스와 변수 파일(.tfvars
) 관리, Terragrunt*로 Terraform의 이러한 문제를 해결하는 방법을 알아보겠습니다.
(이 글은 Terraform의 주요 개념(예: Backend)을 이해하는 독자를 대상으로 작성했습니다)
*Terragrunt: Terraform으로 작성한 IaC를 확장하는 오케스트레이션 도구
Terraform 기본 이해
먼저 Terraform 워크플로와 기본 파일을 짚고 가겠습니다.
워크플로
Terraform의 워크플로는 Write(Define & Initialize), Plan, Apply 이렇게 세 단계로 구성됩니다. 각 단계에서 수행하는 활동은 다음과 같습니다.
- Write 단계: 여러 클라우드 제공업체와 서비스에 리소스를 정의하고 버전을 관리합니다.
- Plan 단계: 기존 인프라와 구성을 기반으로 실행 계획을 생성합니다. 이 단계에서는 변경 사항을 미리 확인할 수 있습니다.
- Apply 단계: 승인 후 리소스 의존성을 고려해 제안된 작업을 올바른 순서로 수행합니다. 이 단계에서 실제 인프라가 변경됩니다.
Terraform 워크플로. 출처=https://developer.hashicorp.com/terraform/intro
기본 파일
다음은 기존에 Terraform을 사용한 폴더 구조 예시입니다. 보통 한 폴더 안에 아래와 같은 파일 묶음이 있습니다.
├── .terraform.lock.hcl
├── main.tf
├── terraform.tfstate
├── terraform.tfvars
├── user_data.sh
├── variables.tf
└── version.tf
Terraform의 워크플로 단계별로 각 파일은 다음 역할을 합니다.
- Write 단계
main.tf
: 인프라 리소스를 정의하는 메인 구성 파일입니다. 이 파일에서 실제로 생성할 인프라를 선언합니다.variables.tf
: Terraform에서 사용할 변수를 선언합니다. 이로써 다양한 환경에서 설정값을 쉽게 변경할 수 있습니다.version.tf
: Terraform과 필요한 Provider의 버전을 지정해 버전 호환성 문제를 방지합니다.user_data.sh
: EC2 인스턴스를 시작할 때 실행될 스크립트를 포함합니다. 인스턴스를 초기화할 때 필요한 설정이나 소프트웨어 설치를 자동화할 수 있습니다.
- Plan 단계
terraform.tfvars
: 변숫값을 지정해 다른 환경에서도 재사용할 수 있는 설정을 정의합니다. 이는variables.tf
와 함께terraform plan
명령에 사용돼 인프라 변경 사항을 예측하는 데 쓰입니다..terraform.lock.hcl
: Provider와 모듈 버전을 잠가 Terraform을 실행할 때, 동일한 버전이 사용되도록 고정합니다. 이 파일은terraform init
명령을 실행할 때 생성되지만, 계획 단계에서 일관된 버전을 사용해 예측 가능한 계획을 수립하는 데 중요한 역할을 합니다.
- Apply 단계
terraform.tfstate
: 현재 인프라 상태를 저장해 변경 사항을 관리하는 핵심 파일입니다.terraform apply
명령을 실행할 때, 이 파일이 업데이트돼 실제 인프라 상태를 반영합니다.
코드 중복, 관리 복잡도 해결 방법
DevOps에서 다양한 환경을 다룰 때 생산성을 향상하려면, PoC(Proof of Concept) 환경을 신속하게 구축해야 하죠. 그러나 단순히 인프라만 자동화한다고 생산성이 높아지지는 않습니다. 각 환경에 맞춘 개별 코드 작성에 따른 코드 중복 문제와 유지 관리 문제부터 해결해야 하죠.
Terraform을 사용할 때도 마찬가지입니다. 앞서 언급했듯 팀이 커지고 환경이 다양해지면, Terraform을 사용 할 때 코드 중복과 관리 복잡도 문제가 발생하는데요. 이 문제는 다음 방법으로 해결할 수 있습니다.
- 모듈화: 반복적인 인프라 구성을 모듈로 만들고 여러 환경에서 재사용해 코드 중복을 줄입니다.
- 워크스페이스와 변수 파일(
.tfvars
) 관리: 각 환경에 별도의 워크스페이스를 사용해 서로 독립적으로 인프라를 관리합니다. 또 환경별 변숫값을 지정해 다양한 환경에서 코드 유연성을 높입니다.
코드 재사용성을 높이려면 위 방법은 둘 다 사용하는 게 좋습니다. 각 방법을 자세히 살펴보겠습니다.
폴더 구조 예시
먼저 Terraform을 사용하는 폴더 구조 예시를 짚고 가겠습니다. 이 구조는 A 환경과 B 환경으로 구분해 다양한 환경에서 코드를 재사용하도록 설정됐습니다. 각 환경에 맞는 초기화 스크립트와 변수 파일을 사용해 동일한 main.tf
코드가 환경별로 적절히 실행되도록 구성됐습니다.
├── [backend.tf](http://backend.tf/) # 백엔드 설정 파일
├── [main.tf](http://main.tf/) # 메인 인프라 리소스 정의 파일
├── [output.tf](http://output.tf/) # 출력 변수 정의 파일
├── terraform.tfstate.d # 각 워크스페이스별 상태 파일 저장 디렉토리
│ ├── A.tfstate # A 환경 상태 파일 저장
│ └── B.tfstate # B 환경 상태 파일 저장
├── tfvars # 환경별 변수 파일 저장 디렉토리
│ ├── A.tfvars # A 환경에 필요한 변수 파일
│ └── B.tfvars # B 환경에 필요한 변수 파일
├── user_data # 인스턴스 초기화 스크립트 저장 디렉토리
│ ├── [default.sh](http://default.sh/) # 기본 초기화 스크립트
│ ├── [A.sh](http://a.sh/) # A 환경 초기화 스크립트
│ └── [B.sh](http://b.sh/) # B 환경 초기화 스크립트
└── [variables.tf](http://variables.tf/) # 변수 선언 파일
방법 1. 모듈화(Don’t Repeat Yourself)
Terraform 모듈화는 반복적으로 작성해야 하는 인프라 구성 요소를 모듈 단위로 재사용하도록 지원합니다. 이로써 코드 중복을 줄이고, DRY(Don't Repeat Yourself) 원칙도 지킬 수 있습니다.
출처=픽사베이예를 들어, AWS EC2 인스턴스를 구성하는 모듈을 생성하면, 아래와 같이 여러 환경에서 재사용하고 코드 중복도 줄일 수 있죠.
# main.tf
module "ec2_instance" {
source = "terraform-aws-modules/ec2-instance/aws" # AWS EC2 인스턴스를 구성하는 모듈 지정
name = "EC2-Sample-Instance" # 인스턴스 이름 설정
instance_type = "t2.micro" # 인스턴스 타입 지정
key_name = "sample-key" # 키 페어 이름 설정
monitoring = true # 모니터링 활성화
vpc_security_group_ids = ["sg-12345678"] # 보안 그룹 ID 설정
subnet_id = "subnet-eddcdzz4" # 서 브넷 ID 설정
tags = { # 인스턴스 태그 정의
Terraform = "true"
Environment = "sample-env"
}
}
방법 2. 워크스페이스와 변수 파일(.tfvars
) 관리
Terraform 워크스페이스와 변수 파일(.tfvars
)을 사용하면, 환경별로 상태 파일을 분리할 수 있습니다. 이는 여러 환경에서 인프라를 독립적으로 관리하는 데 도움이 되죠.
앞서 살펴본 Terraform 모듈화로 코드 중복을 줄여도 현재 구조에서 여전히 하나의 tfstate 파일(동일한 상태 파일)을 공유하는 문제가 생길 수 있는데요. 동일한 상태 파일을 사용하면, 여러 환경에서 발생하는 변경 사항이 서로 영향을 미쳐 관리가 더 복잡해집니다. 그러나 워크스페이스와 변수 파일(.tfvars
)을 사용하면 이러한 문제를 해결할 수 있죠. 앞서 언급한 Terraform 사용 폴더 구조 예시를 토대로 상세 방법을 알아보겠습니다.
-
워크스페이스 생성, 선택
앞서 살펴본 Terraform 사용 폴더 구조는 A 환경과 B 환경으로 구분해 다양한 환경에서 코드를 재사용하도록 설정됐는데요. 만약 A 환경과 B 환경에서 각각 EC2 인스턴스를 생성하려면, 워크스페이스를 활용해 환경을 분리하면 됩니다. 각 워크스페이스는 독립된 상태 파일을 사용하는데요. 이에 서로 다른 환경에서 EC2 인스턴스를 독립적으로 생성하고 관리할 수 있습니다.
먼저, 아래 명령을 입력해 환경을 분리합니다.
terraform workspace new A
terraform workspace select A그다음, 워크스페이스가 선택된 상태에서
terraform plan
또는terraform apply
명령을 실행합니다. 그러면 아래와 같이terraform.tfstate.d
폴더에 해당 워크스페이스 이름으로 폴더 구조가 생성되고요. 상태 파일(terraform.tfstate
)이 그 안에 저장됩니다....(중략)...
└── terraform.tfstate.d
└── A
└── terraform.tfstate -
.tfvars
파일 생성, 적용.tfvars
파일을 사용하면 환경별로 변숫값을 지정할 수 있습니다. 저는 Docker가 설치된 EC2를 띄우기 위해 아래와 같이A.tfvars
파일을 설정했는데요. 다음 예제를 참고하세요.# A.tfvars
instance_name = "IG-POC-SBX-EC2-A"
instance_type = "t3.small"
instance_count = 1
tags = {
Expiry = "2024.12.31"
Owner = "Chad"
Environment = "SBX"
Purpose = "Sample Instance for A Environment"
}
user_data_path = "user_data/A.sh" -
환경별 EC2 인스턴스 프로비저닝
이제 각 환경에 맞는 Terraform 구성을 적용합니다. 이 과정은 워크스페이스 선택, 계획 수립, 적용 단계로 구성됩니다.
아래는 B 환경에 EC2 인스턴스를 프로비저닝하는 단계별 명령입니다.
-
B 워크스페이스 생성
terraform workspace new B
-
B 워크스페이스 선택
terraform workspace select B
-
B 환경 계획 수립
terraform plan -var-file=tfvars/B.tfvars
-
B 환경에 인프라 적용
terraform apply -var-file=tfvars/B.tfvars
-