
지난 포스팅에서는 Docker와 Docker Compose를 활용해 로컬 개발 환경에서 애플리케이션을 컨테이너화하고 실행하는 과정을 다루었다. 로컬에서의 기능 구현과 테스트는 완료되었으나, 실제 서비스를 위해서는 클라우드 환경에 인프라를 구축해야 한다.
이번 글에서는 Google Cloud Platform (GCP) 을 타겟으로 하여, Terraform을 이용해 인프라를 코드로 관리하고 구축한 과정을 기록한다. 콘솔에서 직접 클릭하여 리소스를 생성하는 대신 Terraform을 선택한 이유는 인프라의 변경 사항을 버전 관리하고, 언제든 동일한 환경을 재현하기 위함이다.
1. Terraform 환경 설정 및 보안 구성
GCP에서 리소스를 생성하기 위해 프로젝트를 생성하고, Terraform이 사용할 Service Account(서비스 계정) 를 발급받았다. 이 과정에서 인증 키 관리에 대한 중요한 이슈가 있었다.
GitHub Push Protection과 보안
초기 설정 중 실수로 .gitignore에 인증 키 파일(gcp-credentials.json)을 등록하지 않은 상태로 git push를 시도했으나, GitHub의 Push Protection 기능이 이를 감지하여 차단했다. 이를 통해 민감한 정보가 퍼블릭 저장소에 노출되는 사고를 방지할 수 있었다.
이후 보안을 위해 다음과 같이 구성을 변경했다.
- 인증 키 파일과
terraform.tfvars파일은.gitignore에 추가하여 추적에서 제외했다. - 프로젝트 ID, 리전(Region) 등의 설정값은
variables.tf로 분리하여 하드코딩을 제거했다.
2. 네트워크 리소스 정의 (VPC & Firewall)
가장 먼저 애플리케이션이 배포될 격리된 네트워크 환경을 구성했다.
- VPC & Subnet:
google_compute_network리소스를 통해 커스텀 VPC를 생성하고, 서울 리전(asia-northeast3)에 서브넷을 할당했다. - Firewall: 외부 접속을 위한 HTTP/HTTPS 및 SSH 포트를 개방하고, VPC 내부 리소스 간의 통신을 허용하는 규칙을 정의했다.
SSH 접속 보안에 대한 고찰
현재는 개발 및 학습 편의성을 위해 SSH(22번 포트) 접속 대상을 0.0.0.0/0(전체 허용)으로 설정하고, VM에 Public IP를 할당하여 직접 접속하는 방식을 택했다. 하지만 실제 프로덕션 환경이나 보안이 중요한 아키텍처에서는 이러한 구성이 지양되어야 한다.
추후 아키텍처를 고도화한다면 다음과 같은 대안을 적용할 예정이다.
- Bastion Host: Public Subnet에 Bastion Host를 두고, 이를 통해서만 Private Subnet의 DB 서버 등에 접근하도록 구성.
- IAP (Identity-Aware Proxy): GCP의 IAP를 사용하여 Public IP 없이도 인증된 사용자만 SSH 접속이 가능하도록 구성.
3. 컴퓨팅 리소스 구축 (GKE & VM)
네트워크 구성 후, 실제 애플리케이션과 데이터베이스가 구동될 컴퓨팅 리소스를 정의했다.
GKE (Google Kubernetes Engine) 클러스터 쿠버네티스 학습을 목적으로 GKE의 Standard 모드를 선택했다. 노드 풀(Node Pool) 설정 시 다음과 같은 이슈와 의사결정 과정이 있었다.
- 인스턴스 유형 선택 (
e2-medium): 초기에는 비용 절감을 위해 소형 인스턴스를 고려했으나, 쿠버네티스 시스템 파드(System Pods)가 점유하는 리소스를 고려하여 구글 권장 사양인e2-medium(2 vCPU, 4GB Memory)을 선택했다. - 할당량(Quota) 문제 해결:
terraform apply실행 시403 Insufficient regional quota오류가 발생했다. GKE 노드의 기본 부팅 디스크 크기가 100GB로 설정되어 있어, 프로젝트의 SSD 할당량(250GB)을 초과한 것이 원인이었다. 이를 해결하기 위해 Terraform 코드 내node_config블록에서 디스크 크기를30GB로 명시적으로 줄여 설정했다.
DB용 VM 및 저장소
- Compute Engine: PostgreSQL 데이터베이스를 구동하기 위해
e2-micro인스턴스를 생성했다. 이는 GCP의 프리티어 혜택을 활용하기 위함이다. - Artifact Registry: CI/CD 파이프라인을 통해 빌드된 Docker 이미지를 저장할 레지스트리를 생성했다.
# infra/gke.tf 설정 예시 (디스크 용량 최적화) resource "google_container_cluster" "primary" { # ... 생략 ... # 초기 생성 시 임시 노드 풀의 디스크 용량도 제한해야 함 node_config { disk_size_gb = 30 machine_type = "e2-medium" } }
이로써 서비스 운영에 필요한 인프라 구축을 완료했다.
4. 프로비저닝 자동화: DB 서버 설정
인프라 리소스 생성은 완료되었으나, 데이터베이스용 VM(db-server)은 OS만 설치된 껍데기 상태였다. 실제 서비스를 위해서는 Docker를 설치하고 PostgreSQL 컨테이너를 구동해야 한다.
초기에는 SSH로 직접 접속하여 수동으로 설치하는 방식을 고려했으나, IaC의 철학을 끝까지 유지하기 위해 이 과정 또한 Terraform 코드 내에 포함시켜 자동화하기로 결정했다.
수동 검증 후 자동화 적용
바로 스크립트를 작성하기보다, 먼저 생성된 VM에 SSH로 접속하여 Docker 설치 및 컨테이너 실행 명령어들이 정상적으로 동작하는지 검증 과정을 거쳤다. 이 과정에서 e2-micro 인스턴스의 리소스 한계로 인해 VSCode Remote SSH 연결 시 시스템이 멈추는 현상을 겪었고, 리소스가 적은 환경에서는 가벼운 터미널 접속이 유리하다는 점을 확인했다.
Terraform metadata_startup_script 활용
검증된 명령어들을 Terraform의 google_compute_instance 리소스 내 metadata_startup_script 블록에 작성했다. AWS의 user_data가 Base64 인코딩을 요구하는 것과 달리, GCP는 일반 텍스트 형태의 스크립트를 그대로 사용할 수 있어 관리가 용이했다.
# infra/vm.tf resource "google_compute_instance" "db_server" { # ... 기존 설정 ... # VM 부팅 시 실행될 스크립트 metadata_startup_script = <<-EOF #! /bin/bash exec > /var/log/startup-script.log 2>&1 # 1. Docker 설치 sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg # ... (Docker GPG 키 추가 및 레포지토리 설정) ... sudo apt-get install -y docker-ce docker-ce-cli containerd.io # 2. PostgreSQL 컨테이너 실행 (중복 실행 방지 로직 포함) if [ ! "$(sudo docker ps -q -f name=postgres-db)" ]; then sudo docker run -d \ --name postgres-db \ -p 5432:5432 \ -e POSTGRES_USER=postgres \ -e POSTGRES_PASSWORD=mysecretpassword \ -e POSTGRES_DB=chatdb \ -v postgres-data:/var/lib/postgresql/data \ postgres:15-alpine fi EOF }
스크립트 적용 후 terraform taint 명령어로 기존 VM을 재생성하도록 마킹하고, terraform apply를 실행했다. 결과적으로 별도의 SSH 접속 없이도 VM 생성과 동시에 DB 서버가 구동되는 완전 자동화 환경을 구축했다.


5. 비용 분석 및 운영 전략

클라우드 인프라 구축 후, 약 3일간의 리소스 사용량을 모니터링한 결과 예상보다 높은 비용(약 13,000원 소모)이 발생함을 확인했다. 원인은 GKE 클러스터 설정에 있었다.
- 비용 발생 원인: Terraform 설정 시
location을 리전(asia-northeast3)으로 지정하여 Regional Cluster가 생성되었다. 이는 고가용성을 위해 컨트롤 플레인을 3개로 복제하므로, 무료로 제공되는 Zonal Cluster와 달리 시간당 관리비가 부과된다. - 운영 전략: 현재는 GCP 무료 크레딧($300)을 보유하고 있어 학습 목적으로 엔터프라이즈급 고가용성 환경이라고 가정하고 경험하는 데 투자하기로 했다. 하지만 크레딧 소진 후나 실제 블로그의 채팅 기능으로 소규모 트래픽을 가정한 실제 운영 전환 시에는 비용 최적화를 위해 다음과 같이 아키텍처를 변경할 계획이다.
- GKE 제거: 고정 비용이 높은 쿠버네티스 클러스터를 제거.
- 단일 VM 전환:
e2-micro인스턴스 1대에 Docker Compose를 사용하여 프론트엔드, 백엔드, DB를 모두 구동하는 구조로 변경 (월 예상 비용 5천 원 미만).
마치며
이번 단계를 통해 로컬에 있던 애플리케이션을 위한 클라우드 인프라를 Terraform으로 완벽하게 구현했다. 네트워크 격리부터 컴퓨팅 리소스 할당, 그리고 소프트웨어 설치 자동화까지 모든 과정을 코드로 기록하고 관리할 수 있게 되었다.
이제 인프라 준비는 끝났다. 다음 포스팅에서는 이 위에 애플리케이션을 자동으로 배포하는 CI/CD 파이프라인 구축 과정을 다룰 예정이다. GitHub Actions와 Argo CD를 활용하여, 코드를 푸시하는 것만으로 GKE 클러스터에 서비스가 배포되는 GitOps 워크플로우를 완성해 볼 예정이다.
