MOA 서비스 인프라 구축을 위한 Terraform 구성 - 100-hours-a-week/4-bull4zo-wiki GitHub Wiki
개요
본 문서는 MOA 서비스의 안정적이고 확장 가능한 인프라 구축과 자동화를 위해 작성된 Terraform
코드의 구조와 주요 리소스를 설명합니다.
Terraform
Terraform
은 Hashicorp
에서 개발한 IaC, Infrastructure as Code 도구로 클라우드 인프라 리소스를 선언형 구성 파일로 정의하고 자동으로 배포, 변경, 관리할 수 있도록 합니다.
Terraform
사용에 따른 이점
- 자동화 : 명령어(
terraform apply
)를 통해 복잡한 인프라 리소스를 자동 생성, 변경, 삭제 가능 - 계획 기능 :
terraform plan
을 통해 생성 및 변경 내용을 사전 검토 가능 - 일관성 & 재현성 : 모든 인프라를 코드로 정의하여 누구나 같은 환경을 반복 생성 가능
- 멀티 클라우드 지원 :
GCP
뿐 아니라AWS
,Azure
등 다양한 클라우드 환경 지원 - 버전 관리 및 협업 :
Git
과 같은 형상관리 도구를 함께 활용하여 코드 기반 인프라 변경 이력을 명확히 추적 가능
Terraform
인프라 구성 목표
- IaC(Infrastructure as Code) 기반 자동화된 인프라 배포
GCP
리전asia-northeast3(서울)
기반 서비스 안정성 확보- 도메인 기반 로드 밸런싱과 정적/동적 자원의 분리 운영
- 보안과 확장성을 고려한 네트워크 설계
- 환경 분리(
dev
,prod
) 지원을 위한 변수 기반 설계
Terraform
코드 구조
main.tf
네트워크
## 네트워크 설정
# 서비스용 VPC 생성
resource "google_compute_network" "vpc" {
name = "moa-main-vpc-${var.environment}"
auto_create_subnetworks = false
}
# 백엔드 서브넷 생성
resource "google_compute_subnetwork" "subnet" {
name = "moa-backend-sub-${var.environment}-a"
ip_cidr_range = "[VPC_CIDR]"
region = var.region
network = google_compute_network.vpc.id
}
- 리소스 명의 경우, 사전 팀 내에서 협의한 리소스명 규칙을 따라서 구성
- 환경에 따른 리소스명 변화는 변수화를 통해 처리
$(var.environment)
정적 배포용 Cloud Storage 설정
# 정적 배포용 Cloud Storage 버킷 생성
resource "google_storage_bucket" "static_website" {
name = "${var.project_id}-${var.environment}-frontend"
location = var.region
force_destroy = true
# 모든 트래픽을 index.html로 리다이렉트
website {
main_page_suffix = "index.html"
not_found_page = "index.html"
}
uniform_bucket_level_access = true
cors {
origin = ["*"]
method = ["GET", "HEAD", "OPTIONS"]
response_header = ["Content-Type"]
max_age_seconds = 3600
}
}
# 버킷 공개 접근 설정
resource "google_storage_bucket_iam_member" "public_access" {
bucket = google_storage_bucket.static_website.name
role = "roles/storage.objectViewer"
member = "allUsers"
}
- 버킷명은 globally unique 해야하는 조건이 붙으므로, 고유한 프로젝트명 + 환경 변수 조합으로 생성
- 정적 배포를 위한
allUser
에 대한 접근 허용
방화벽 설정
## 방화벽
# SSH, MySQL, Redis 방화벽 규칙
resource "google_compute_firewall" "allow_ssh_mysql" {
name = "moa-ssh-sg-${var.environment}"
network = google_compute_network.vpc.name
allow {
protocol = "tcp"
ports = ["22", "3306", "6379"]
}
source_ranges = ["[VPC_CIDR]"]
target_tags = ["ssh", "mysql", "redis"]
}
# 웹 서비스 및 사용 API 방화벽 규칙
resource "google_compute_firewall" "allow_web_services" {
name = "moa-lb-sg-${var.environment}"
network = google_compute_network.vpc.name
allow {
protocol = "tcp"
ports = ["80", "443", "8000", "8080", "9090", "3000", "3100", "5601", "8200", "9200", "9300"]
}
source_ranges = ["[VPC_CIDR]"]
target_tags = ["web", "api"]
}
# HTTP/HTTPS Health Check 방화벽 규칙
resource "google_compute_firewall" "allow_http_https_health" {
name = "moa-http-health-${var.environment}"
network = google_compute_network.vpc.name
allow {
protocol = "tcp"
ports = ["80", "443", "8080"] # Common health check port
}
# 구글 클라우드 로드 밸런서 헬스 체크를 위한 IP 범위
source_ranges = [
"[VPC_CIDR]",
"130.211.0.0/22", # Google Cloud Load Balancer health checks
"35.191.0.0/16" # Google Cloud health checks
]
}
- 외부 접근은 차단, 내부 통신만 허용 (외부 접속은 LB를 통해 접속)
- 방화벽 정책은
tag
를 통해 인스턴스 별로 적용
Google Compute Engine 인스턴스 생성
# 백엔드 서버 인스턴스
resource "google_compute_instance" "vm_instance" {
name = "moa-be-ec2-${var.environment}"
machine_type = "e2-medium"
zone = "asia-northeast3-c"
tags = ["ssh", "web", "api", "mysql", "http-server", "https-server"]
boot_disk {
initialize_params {
image = "ubuntu-os-cloud/ubuntu-2204-lts"
size = 60
}
}
network_interface {
subnetwork = google_compute_subnetwork.subnet.id
network_ip = "[내부 IP]"
}
}
# AI 서버 인스턴스
resource "google_compute_instance" "ai_instance" {
name = "moa-ai-ec2-${var.environment}"
machine_type = "n1-standard-4"
zone = "asia-northeast3-c"
tags = ["ssh", "web", "api", "mysql", "http-server", "https-server"]
boot_disk {
initialize_params {
image = "ubuntu-os-cloud/ubuntu-2204-lts"
size = 130
}
}
network_interface {
subnetwork = google_compute_subnetwork.subnet.id
network_ip = "[내부 IP]"
}
guest_accelerator {
type = "nvidia-tesla-t4"
count = 1
}
# GPU 사용을 위해 필요 - 유지보수 시에 인스턴스 종료(정지)
scheduling {
on_host_maintenance = "TERMINATE"
}
}
# DB 서버 인스턴스
resource "google_compute_instance" "db_instance" {
name = "moa-db-ec2-${var.environment}"
machine_type = "e2-small"
zone = "asia-northeast3-c"
tags = ["mysql", "db"]
boot_disk {
initialize_params {
image = "ubuntu-os-cloud/ubuntu-2204-lts"
size = 30
}
}
network_interface {
subnetwork = google_compute_subnetwork.subnet.id
network_ip = "[내부 IP]"
}
}
# Redis 서버 인스턴스
resource "google_compute_instance" "redis_instance" {
name = "moa-redis-ec2-${var.environment}"
machine_type = "e2-small"
zone = "asia-northeast3-c"
tags = ["redis", "cache"]
boot_disk {
initialize_params {
image = "ubuntu-os-cloud/ubuntu-2204-lts"
size = 30
}
}
network_interface {
subnetwork = google_compute_subnetwork.subnet.id
network_ip = "[내부 IP]"
}
}
# 백엔드 인스턴스 그룹 생성
resource "google_compute_instance_group" "backend_group" {
name = "moa-be-ec2-group-${var.environment}"
description = "Backend instance group"
zone = "asia-northeast3-c"
instances = [
google_compute_instance.vm_instance.id
]
named_port {
name = "http"
port = 80
}
named_port {
name = "api"
port = 8080
}
}
BE
,AI
,Redis
,DB
총 4대의 인스턴스 생성- 외부 IP 없이 내부 IP만 부여
- 각 인스턴스에 tag 작성하여 보안 규칙 적용 등 리소스 호출 시 사용
- 외부에서 접속을 위한 bastion 서버 추후 생성
로드 밸런서 설정
## 프론트엔드 로드 밸런서 설정
# FE 로드 밸런서 고정 IP 주소
resource "google_compute_global_address" "frontend_lb_ip" {
name = "moa-fe-lb-ip-${var.environment}"
}
# 정적 배포용 백엔드 버킷 설정
resource "google_compute_backend_bucket" "frontend_bucket" {
name = "moa-fe-frontend-backend-${var.environment}"
bucket_name = google_storage_bucket.static_website.name
enable_cdn = true
}
# 로드밸런서 URL 맵 설정
resource "google_compute_url_map" "frontend_url_map" {
name = "moa-fe-url-map-${var.environment}"
default_service = google_compute_backend_bucket.frontend_bucket.id
}
# 프론트엔드 HTTP proxy
resource "google_compute_target_http_proxy" "frontend_http_proxy" {
name = "moa-fe-http-proxy-${var.environment}"
url_map = google_compute_url_map.frontend_url_map.id
}
# 프론트엔드 HTTP 포워딩 규칙
resource "google_compute_global_forwarding_rule" "frontend_http_forwarding_rule" {
name = "moa-fe-http-rule-${var.environment}"
target = google_compute_target_http_proxy.frontend_http_proxy.id
port_range = "80"
ip_address = google_compute_global_address.frontend_lb_ip.address
}
# 프론트엔드 SSL 인증서
resource "google_compute_managed_ssl_certificate" "frontend_certificate" {
name = "moa-fe-ssl-cert-${var.environment}"
managed {
domains = [var.frontend_domain]
}
}
# 프론트엔드 HTTPS proxy
resource "google_compute_target_https_proxy" "frontend_https_proxy" {
name = "moa-fe-https-proxy-${var.environment}"
url_map = google_compute_url_map.frontend_url_map.id
ssl_certificates = [google_compute_managed_ssl_certificate.frontend_certificate.id]
}
# 프론트엔드 HTTPS 포워딩 규칙
resource "google_compute_global_forwarding_rule" "frontend_https_forwarding_rule" {
name = "moa-fe-https-rule-${var.environment}"
target = google_compute_target_https_proxy.frontend_https_proxy.id
port_range = "443"
ip_address = google_compute_global_address.frontend_lb_ip.address
}
## 백엔드 로드 밸런서 설정
# 백엔드 고정 IP 주소
resource "google_compute_global_address" "backend_lb_ip" {
name = "moa-be-lb-ip-${var.environment}"
}
# 백엔드 서비스 헬스체크
resource "google_compute_health_check" "backend_health_check" {
name = "moa-be-ec2-healthcheck-${var.environment}"
timeout_sec = 5
check_interval_sec = 10
http_health_check {
port = 8080
request_path = "/health"
}
}
# 백엔드 서비스 설정
resource "google_compute_backend_service" "backend_service" {
name = "moa-be-ec2-service-${var.environment}"
protocol = "HTTP"
port_name = "api"
timeout_sec = 30
health_checks = [google_compute_health_check.backend_health_check.id]
load_balancing_scheme = "EXTERNAL"
backend {
group = google_compute_instance_group.backend_group.id
}
}
# 백엔드 URL 맵 설정
resource "google_compute_url_map" "backend_url_map" {
name = "moa-be-url-map-${var.environment}"
default_service = google_compute_backend_service.backend_service.id
host_rule {
hosts = [var.backend_domain]
path_matcher = "backend-paths"
}
path_matcher {
name = "backend-paths"
default_service = google_compute_backend_service.backend_service.id
path_rule {
paths = ["/api/*", "/api/v1/*", "/*"]
service = google_compute_backend_service.backend_service.id
}
}
}
# 백엔드 HTTP 프록시
resource "google_compute_target_http_proxy" "backend_http_proxy" {
name = "moa-be-http-proxy-${var.environment}"
url_map = google_compute_url_map.backend_url_map.id
}
# 백엔드 HTTP 포워딩 규칙
resource "google_compute_global_forwarding_rule" "backend_http_forwarding_rule" {
name = "moa-be-http-rule-${var.environment}"
target = google_compute_target_http_proxy.backend_http_proxy.id
port_range = "80"
ip_address = google_compute_global_address.backend_lb_ip.address
}
# 백엔드 HTTPS SSL 인증서
resource "google_compute_managed_ssl_certificate" "backend_certificate" {
name = "moa-be-ssl-cert-${var.environment}"
managed {
domains = [var.backend_domain]
}
}
# 백엔드 HTTPS 프록시
resource "google_compute_target_https_proxy" "backend_https_proxy" {
name = "moa-be-https-proxy-${var.environment}"
url_map = google_compute_url_map.backend_url_map.id
ssl_certificates = [google_compute_managed_ssl_certificate.backend_certificate.id]
}
# 백엔드 HTTPS 포워딩 규칙
resource "google_compute_global_forwarding_rule" "backend_https_forwarding_rule" {
name = "moa-be-https-rule-${var.environment}"
target = google_compute_target_https_proxy.backend_https_proxy.id
port_range = "443"
ip_address = google_compute_global_address.backend_lb_ip.address
}
- LB 구성을 위해 HTTPS용 SSL 인증서 생성
- 인증서 발급용
domain
은tfvars
파일을 통해 변수 처리
variables.tf
variable "project_id" {
description = "The GCP project ID"
type = string
}
variable "region" {
description = "The GCP region for resources"
type = string
}
variable "zone" {
description = "The GCP zone for zonal resources"
type = string
}
variable "environment" {
description = "Environment name (dev, staging, prod)"
type = string
}
variable "frontend_domain" {
description = "Domain name for the frontend SSL certificate"
type = string
}
variable "backend_domain" {
description = "Domain name for the backend SSL certificate"
type = string
}
variable "credentials_file" {
description = "Path to the GCP credentials JSON file"
type = string
}
- 변수는
.tfvars
파일을 통해 환경변수 주입, 이를 통해 다른 운영 환경에서 직접적 코드 수정 없이 동작 가능
outputs.tf
output "vpc_id" {
description = "ID of the VPC"
value = google_compute_network.vpc.id
}
output "subnet_id" {
description = "ID of the subnet"
value = google_compute_subnetwork.subnet.id
}
output "be_instance_name" {
description = "Name of the VM instance"
value = google_compute_instance.vm_instance.name
}
output "instance_group_name" {
description = "Name of the backend instance group"
value = google_compute_instance_group.backend_group.name
}
output "ai_instance_name" {
description = "Name of the AI VM instance"
value = google_compute_instance.ai_instance.name
}
output "db_instance_name" {
description = "Name of the database instance"
value = google_compute_instance.db_instance.name
}
output "redis_instance_name" {
description = "Name of the Redis instance"
value = google_compute_instance.redis_instance.name
}
output "frontend_bucket_name" {
description = "Name of the frontend static website bucket"
value = google_storage_bucket.static_website.name
}
output "frontend_bucket_url" {
description = "URL of the frontend static website"
value = "https://storage.googleapis.com/${google_storage_bucket.static_website.name}"
}
output "frontend_load_balancer_ip" {
description = "IP address of the frontend load balancer"
value = google_compute_global_address.frontend_lb_ip.address
}
output "backend_load_balancer_ip" {
description = "IP address of the backend load balancer"
value = google_compute_global_address.backend_lb_ip.address
}
output "backend_service_name" {
description = "Name of the backend service"
value = google_compute_backend_service.backend_service.name
}
- 주요 리소스 명과 접속 경로를
outputs
로 생성
terraform.tfvars
project_id = "[Project ID]"
region = "[Region]"
zone = "[Zone]"
environment = "[environment]"
frontend_domain = "[frontend domain]"
backend_domain = "[backend domain]"
credentials_file = "[Credential Key Path]"
- 환경에 맞는 변수 주입 후 적용
Terraform 실행 과정
# Terraform 프로젝트 폴더로 이동 **(GCP Credential 을 위한 Key 파일 경로 확인 필수)**
cd [Terraform Project]
# 초기 실행
terraform init
# 리소스 생성 계획 점검
terraform plan -var-file=terraform.tfvars
# 리소스 적용
terraform apply -var-file=terraform.tfvars
# 리소스 삭제
terraform destroy
시연 화면 (Environment = test로 적용)
terraform plan
및terraform apply
실제
GCP
콘솔 상 생성 화면Instance 생성
Load Balancer 생성
CDN 생성
terraform destroy
실행