Terraform 인프라 관리
개요
DTA-WIDE 시스템은 코드형 인프라(Infrastructure as Code, IaC) 원칙에 따라 Terraform을 사용하여 모든 인프라를 관리합니다. 이 문서는 Terraform을 통한 인프라 관리 방법과 모범 사례를 설명합니다.
구성
디렉토리 구조
infrastructure/
├── terraform/ # Terraform 관련 코드
│ ├── modules/ # 재사용 가능한 모듈
│ │ ├── gcp-project/ # GCP 프로젝트 설정
│ │ ├── network/ # 네트워크 구성
│ │ ├── bigquery/ # BigQuery 모듈
│ │ ├── firestore/ # Firestore 모듈
│ │ ├── pubsub/ # Pub/Sub 토픽 및 구독
│ │ ├── memorystore/ # Memorystore 모듈
│ │ └── firebase/ # Firebase 모듈
│ ├── environments/ # 환경별 구성
│ │ ├── dev/ # 개발 환경
│ │ ├── staging/ # 스테이징 환경
│ │ └── prod/ # 프로덕션 환경
│ └── scripts/ # 유틸리티 스크립트
├── terragrunt/ # Terragrunt 구성
│ ├── terragrunt.hcl # 공통 Terragrunt 설정
│ ├── dev/ # 개발 환경
│ │ ├── bigquery/
│ │ ├── firestore/
│ │ ├── pubsub/
│ │ ├── memorystore/
│ │ └── firebase/
│ ├── staging/ # 스테이징 환경
│ │ └── ...
│ └── prod/ # 프로덕션 환경
│ └── ...
└── .github/ # GitHub Actions 워크플로우
└── workflows/
├── terraform-plan.yml
└── terraform-apply.yml
주요 모듈
GCP 프로젝트 모듈
- 프로젝트 생성 및 구성
- API 활성화
- 서비스 계정 관리
- 기본 IAM 정책 설정
네트워크 모듈
- VPC 네트워크 구성
- 서브넷 관리
- 방화벽 규칙
- VPC 피어링 및 서비스 연결
클라우드 서비스 모듈
- BigQuery: 데이터 분석 및 웨어하우스
- Firestore: NoSQL 데이터베이스
- Pub/Sub: 메시징 서비스
- Memorystore: 인메모리 데이터 저장소
- Firebase: 모바일 및 웹 애플리케이션 플랫폼
환경 관리
환경 분리
DTA-WIDE는 다음 세 가지 환경으로 분리되어 있습니다:
- 개발(dev): 개발자 테스트용
- 스테이지(stage): QA 및 사전 배포 테스트용
- 프로덕션(prod): 실제 서비스 운영
각 환경은 독립적인 Terraform 상태를 유지하며, 환경별로 다른 변수를 적용할 수 있습니다.
변수 관리
- terraform.tfvars: 환경별 변수 설정
- variables.tf: 변수 정의 및 기본값
- locals.tf: 파생 변수 및 계산된 값
상태 관리
- 원격 상태 저장소: GCS 버킷 사용
- 상태 잠금: Cloud Storage 객체 버전 관리
- 환경별 상태 분리
CI/CD 통합
파이프라인 구성
Terraform 작업은 Cloud Build 파이프라인에 통합되어 있습니다:
- 계획 단계: PR 생성 시
terraform plan실행 - 적용 단계: 메인 브랜치 병합 시
terraform apply자동 실행 - 검증 단계: 적용 후 인프라 검증 테스트 실행
관련 문서: TBD
보안 관행
- 민감한 변수는 Secret Manager에 저장
- 서비스 계정 권한 최소화
- 변경 내역 감사 및 추적
관련 문서: TBD
모범 사례
버전 관리
- Terraform 버전 고정(현재 1.5.x)
- 제공자 버전 명시적 지정
- 모듈 버전 고정
코드 품질
- 일관된 코드 형식(terraform fmt)
- 린팅 및 검증(terraform validate, tflint)
- 문서화된 변수 및 출력값
변경 관리
- 점진적 변경 적용
- 변경 사항 사전 검토(terraform plan)
- 롤백 계획 수립
재해 복구
백업 전략
- 정기적인 상태 백업
- 상태 파일 버전 관리
- 수동 복구 절차 문서화
복구 절차
- 상태 복원 방법
- 수동 개입 프로세스
- 복구 테스트 및 훈련
참고 자료
TBD
Terragrunt 활용
DTA-WIDE 시스템에서는 Terraform 관리를 위해 Terragrunt를 활용하고 있습니다. Terragrunt는 Terraform 래퍼로, DRY(Don't Repeat Yourself) 원칙을 지원하며 코드 재사용성을 높입니다.
Terragrunt 구성
디렉토리 구조
infrastructure/terragrunt/
├── dev/
│ ├── serverless/
│ │ └── dta-wide-api/
│ │ └── terragrunt.hcl
│ └── secret/
│ └── dta-wide-api/
│ ├── terragrunt.hcl
│ └── dta-wide-api.json
├── stage/
│ └── ...
└── prod/
└── ...
모듈 소스 관리
모든 Terraform 모듈은 중앙 저장소에서 관리됩니다:
git::git@github.com:weltcorp/gops-terraform-module.git//modules//[MODULE_NAME]
원격 상태 관리
Terragrunt 구성은 GCS 버킷을 사용하여 원격 상태를 저장합니다:
remote_state {
backend = "gcs"
config = {
project = "dta-cloud-de-dev"
location = "europe-west3"
bucket = "dta-cloud-de-dev-tf-state"
prefix = "serverless/dta-wide-api"
impersonate_service_account = "terraform@dta-cloud-de-dev.iam.gserviceaccount.com"
}
}
GitHub Actions 통합
Terraform/Terragrunt 작업은 GitHub Actions 워크플로우에 통합되어 자동화되어 있습니다.
워크플로우 구성
계획 워크플로우
- PR 생성/업데이트 시 실행
- Terraform 계획 생성 및 PR 코멘트로 표시
- 구문 검사 및 코드 포맷팅 검증
적용 워크플로우
- 메인 브랜치 병합 시 실행
- 자동 승인 및 변경사항 적용
- 결과 알림 전송
서비스 계정 권한
GitHub Actions는 Workload Identity Federation을 통해 GCP 서비스 계정을 사용합니다:
- 서비스 계정:
terraform@dta-cloud-de-dev.iam.gserviceaccount.com - 최소 권한 원칙 적용
사용 예시
Cloud Run 서비스 배포 예시
terraform {
source = "git::git@github.com:weltcorp/gops-terraform-module.git//modules//serverless"
}
remote_state {
backend = "gcs"
config = {
project = "dta-cloud-de-dev"
location = "europe-west3"
bucket = "dta-cloud-de-dev-tf-state"
prefix = "serverless/dta-wide-api"
impersonate_service_account = "terraform@dta-cloud-de-dev.iam.gserviceaccount.com"
}
}
locals {
project = "dta-cloud-de-dev"
location = "europe-west3"
connector = "dta-cloud-de-dev"
// set cloud sql instance
cloud_sql_instance = "db-dta-mono-dev"
// stable
app_version = "1.0.15-rc5"
secret_version = "12"
revision_name = "dta-wide-api-${replace(local.app_version, ".", "-")}-${local.secret_version}"
container_image = local.app_version
template_revision_name = local.revision_name
template_secret_version = local.secret_version
}
inputs = {
project = "dta-cloud-de-dev"
terraform_service_account = "terraform@dta-cloud-de-dev.iam.gserviceaccount.com"
cloud_run_service = [
{
name = "dta-wide-api"
template = {
revision = local.template_revision_name
scaling = {
min_instance_count = "2"
max_instance_count = "20"
}
vpc_access = {
connector = "projects/${local.project}/locations/${local.location}/connectors/${local.connector}"
egress = "PRIVATE_RANGES_ONLY"
}
timeout = "300s"
service_account = "dta-wide-api@dta-cloud-de-dev.iam.gserviceaccount.com"
containers = [
{
name = "dta-wide-api"
image = "asia.gcr.io/dta-cloud-de-dev/dta-wide-api:dta-wide-api-${local.container_image}"
env = [
{
name = "CONFIGURATION"
value_source = {
secret_key_ref = {
secret = "projects/dta-cloud-de-dev/secrets/dta-wide-api"
version = local.template_secret_version
}
}
}
]
resources = {
limits = {
cpu = "2"
memory = "1024Mi"
}
cpu_idle = true
startup_cpu_boost = "true"
}
ports = {
name = "http1"
container_port = "8080"
}
volume_mounts = [
{
name = "gcloud"
mount_path = "/app/credentials"
}
]
}
]
volumes = [
{
name = "cloudsql"
cloud_sql_instance = {
instances = [
"dta-cloud-de-dev:europe-west3:${local.cloud_sql_instance}",
"dta-cloud-de-prod:europe-west3:db-dta-mono-prod",
]
}
},
{
name = "gcloud"
secret = [
{
secret = "dta-wide-api-credentials"
default_mode = 292
items = [
{
version = "1"
path = "dta-wide-api-credentials.json"
}
]
}
]
}
]
max_instance_request_concurrency = "100"
execution_environment = "EXECUTION_ENVIRONMENT_GEN2"
}
location = "europe-west3"
description = "dta-wide-api"
ingress = "INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER"
launch_stage = "GA"
deletion_protection = false
traffic = [
{
type = "TRAFFIC_TARGET_ALLOCATION_TYPE_REVISION"
revision = local.revision_name
percent = "100"
tag = "stable"
}
]
}
]
}
Secret Manager 관리 예시
terraform {
source = "git::git@github.com:weltcorp/gops-terraform-module.git//modules//secret"
}
remote_state {
backend = "gcs"
config = {
project = "dta-cloud-de-dev"
location = "europe-west3"
bucket = "dta-cloud-de-dev-tf-state"
prefix = "secret/dta-wide-api"
impersonate_service_account = "terraform@dta-cloud-de-dev.iam.gserviceaccount.com"
}
}
locals {
extra_atlantis_dependencies = [
"*.json"
]
}
inputs = {
project = "dta-cloud-de-dev"
terraform_service_account = "terraform@dta-cloud-de-dev.iam.gserviceaccount.com"
secret = [
{
name = "dta-wide-api"
}
]
secret_version = [
{
secret_name = "dta-wide-api"
secret_data_file = "dta-wide-api.json"
}
]
}
배포 흐름
- 개발자가 코드 변경 후 PR 생성
- GitHub Actions가
terragrunt plan실행 및 결과 표시 - 코드 리뷰 및 승인
- 메인 브랜치 병합
- GitHub Actions가 자동으로
terragrunt apply실행 - 환경별 단계적 배포 (dev → stage → prod)
관련 문서: TBD
변경 이력
| 버전 | 날짜 | 작성자 | 변경 내용 |
|---|---|---|---|
| 0.1.0 | 2025-03-26 | bok@weltcorp.com | 초기 문서 작성 |
| 0.2.0 | 2025-03-28 | bok@weltcorp.com | 인프라 스캐폴딩 구현 및 문서 업데이트 |
인프라 스캐폴딩 구현
DTA-WIDE 모노레포에 Terraform 및 Terragrunt 기반 인프라 코드의 스캐폴딩을 구현하였습니다. 이 구조는 문서화된 설계를 바탕으로 실제 코드 관리를 위한 기반을 제공합니다.
모듈 구조
각 클라우드 서비스 모듈은 다음과 같은 구조를 따릅니다:
modules/<서비스>/
├── main.tf # 리소스 정의
├── variables.tf # 입력 변수
├── outputs.tf # 출력값
└── README.md # 모듈 사용법 및 설명
모듈별 사용 사례
BigQuery 모듈
데이터 웨어하우스 및 분석용 BigQuery 데이터셋과 테이블을 관리합니다:
module "bigquery" {
source = "../../modules/bigquery"
project_id = var.project_id
dataset_id = "analytics_${var.environment}"
location = "europe-west3"
tables = {
events = {
schema = file("${path.module}/schemas/events.json"),
partitioning = {
type = "DAY",
field = "created_at"
},
clustering = ["user_id", "event_type"]
}
}
}
Firestore 모듈
NoSQL 데이터베이스 컬렉션 및 문서 구조를 관리합니다:
module "firestore" {
source = "../../modules/firestore"
project_id = var.project_id
location = "europe-west3"
database_id = "main"
collections = ["users", "products", "orders"]
}
환경별 배포
각 환경(dev, staging, prod)에 대한 Terragrunt 구성은 다음과 같은 구조를 따릅니다:
# terragrunt/dev/bigquery/terragrunt.hcl
include {
path = find_in_parent_folders()
}
terraform {
source = "git::git@github.com:weltcorp/gops-terraform-module.git//modules//bigquery"
# 로컬 개발 시 다음 소스 사용
# source = "../../../terraform/modules/bigquery"
}
inputs = {
project_id = "dta-cloud-de-dev"
dataset_id = "analytics_dev"
location = "europe-west3"
# ... 기타 환경별 설정
}
향후 업데이트 계획
- 모듈 구현 완료: 각 클라우드 서비스 모듈의 실제 구현
- 자동화 스크립트 개발: 배포 및 검증 스크립트 구현
- CI/CD 파이프라인 통합: GitHub Actions 워크플로우 구현
- 문서 자동화: terraform-docs 도구를 사용한 문서 자동 생성
Terragrunt 명령어 가이드
DTA-WIDE 프로젝트에서는 인프라 변경을 위해 Terragrunt를 사용합니다. 아래는 기본적인 명령어 가이드입니다.
기본 Terragrunt 명령어
# 모듈 초기화
terragrunt init
# 변경 사항 계획 확인
terragrunt plan
# 변경 사항 적용
terragrunt apply
# 리소스 삭제
terragrunt destroy
계획 파일 사용하기 (권장 워크플로우)
프로덕션과 같은 중요한 환경에서의 변경은 계획 파일을 사용하는 워크플로우를 권장합니다:
# 1. 변경 계획을 파일로 저장
terragrunt plan -out=tfplan
# 2. 계획 내용 검토 (선택사항)
terragrunt show tfplan
# 3. 저장된 계획 적용 (승인 메시지 없음)
terragrunt apply tfplan
계획 파일 워크플로우의 장점:
- 일관성 보장: 계획 검토 시점과 적용 시점의 변경 사항이 동일하게 유지됩니다.
- CI/CD 통합: 자동화된 파이프라인에서 승인 메시지 없이 적용 가능합니다.
- 변경 이력 관리: 계획 파일을 저장해두면 변경 이력을 추적할 수 있습니다.
- 협업 워크플로우: 다른 팀원이 계획 결과를 검토하고 승인할 수 있습니다.
- 오류 방지: 계획 후 리소스 상태가 변경되었거나 동시 변경으로 인한 충돌을 방지합니다.
주의사항:
- 계획 파일은 민감한 정보를 포함할 수 있으므로 안전하게 관리해야 합니다.
- 계획 파일은 생성 후 짧은 시간 내에 적용하는 것이 좋습니다 (환경 변화 최소화).
환경별 Terragrunt 변경 적용 방법
각 환경(dev, stage, prod)에 변경 사항을 적용하려면 해당 환경의 디렉토리로 이동하여 명령어를 실행합니다:
# 개발 환경
cd infrastructure/terragrunt/dev/<모듈명>
terragrunt plan # 변경 사항 미리 보기
terragrunt apply # 변경 사항 적용
# 스테이징 환경
cd infrastructure/terragrunt/stage/<모듈명>
terragrunt plan
terragrunt apply
# 프로덕션 환경
cd infrastructure/terragrunt/prod/<모듈명>
terragrunt plan
terragrunt apply
유용한 Terragrunt 옵션
자동 승인 (자동 yes):
terragrunt apply -auto-approve
특정 리소스만 변경:
terragrunt apply -target=google_sql_database_instance.main
디버그 로그 출력:
TF_LOG=DEBUG terragrunt apply
여러 모듈 동시 적용:
cd infrastructure/terragrunt/dev
terragrunt run-all apply
계획 파일 저장 및 적용:
terragrunt plan -out=plan.tfplan
terragrunt apply plan.tfplan
Cloud SQL 변경 적용 예시
Cloud SQL에 VPC 네트워크 연결 정보 변경과 같은 구성을 적용하는 방법:
# 1. 개발 환경 Cloud SQL 변경
cd infrastructure/terragrunt/dev/cloudsql
terragrunt init
terragrunt plan # 변경 내용 확인
terragrunt apply # 변경 적용 (yes 입력 필요)
# 2. 스테이징 환경 Cloud SQL 변경
cd ../../stage/cloudsql
terragrunt init
terragrunt plan
terragrunt apply
# 3. 프로덕션 환경 Cloud SQL 변경 (주의: 다운타임 발생 가능)
cd ../../prod/cloudsql
terragrunt init
terragrunt plan
terragrunt apply
주의사항
- 프로덕션 변경 시 주의: 프로덕션 환경 변경은 서비스 영향을 최소화하기 위해 계획된 유지보수 시간에 수행해야 합니다.
- VPC 네트워크 변경: Cloud SQL 인스턴스의 VPC 네트워크 변경은 인스턴스 재시작이 필요하여 다운타임이 발생할 수 있습니다.
- 백업 확인: 중요한 변경 전에 최신 백업이 있는지 확인하세요.
- 단계적 적용: 항상 dev → stage → prod 순서로 변경을 적용하여 문제 발생 시 미리 대응할 수 있도록 합니다.
- 변경 내용 검토:
terragrunt plan단계에서 변경 내용을 철저히 검토하세요.
위 명령어들은 로컬 개발 환경에서 실행하는 것을 가정합니다. CI/CD 파이프라인을 통한 자동화된 배포도 가능하며, 이는 보안 및 일관성을 위해 권장됩니다.