지난 포스팅까지 Kustomize와 Argo CD를 활용하여 GKE(Google Kubernetes Engine) 환경에서의 완전한 GitOps 파이프라인을 구축했다. 이로써 확장성과 운영 안정성을 갖춘 클라우드 네이티브 아키텍처를 경험할 수 있었다.하지만 개인 프로젝트 규모에서 GKE를 유지하는 것은 비용 과 리소스 오버헤드 측면에서 비효율적이다. 학습이라는 1차 목표를 달성한 시점에서, 실제 지속 가능한 운영을 위해서는 서비스 규모에 맞는 아키텍처 최적화가 필요했다.
이번 포스팅에서는 GKE 클러스터를 제거하고, GCP의 상시 Free Tier 조건을 만족하는 단일 VM (e2-micro) 환경으로 인프라를 마이그레이션한 과정을 기록한다. 이 과정은 제한된 리소스 내에서 자동화, 보안, 가용성을 유지하기 위한 과정이었다.
1. 아키텍처 변화
마이그레이션의 핵심 목표는 "실제 운영 비용 $0" 이다. 이를 위해 쿠버네티스의 복잡한 오케스트레이션 계층을 제거하고, Docker Compose를 활용한 단일 호스트 구성으로 전환했다.
| 구분 | Before (GKE) | After (Single VM) |
|---|---|---|
| 인프라 | GKE Cluster (Control Plane + Worker Node) | Compute Engine (e2-micro 1대) |
| 오케스트레이션 | Kubernetes (Pods, Deployments) | Docker Compose (Services) |
| 네트워크(외부) | GKE Ingress (L7 LoadBalancer) | Nginx Container (Reverse Proxy) |
| SSL 인증서 | Google Managed Certificate | Let's Encrypt (Certbot DNS-01) |
| 배포 방식 | GitOps (Argo CD - Pull) | GitHub Actions + SSH (Push) |
| 비용 | 약 $30~40/월 | $0/월 (GCP Free Tier) |
1.1 아키텍처 비교
Before: GKE - 확장성과 고가용성
"대규모 트래픽 처리를 위한 아키텍처"

- 핵심 기술: Ingress (L7 LoadBalancer), Argo CD (GitOps), HPA (Auto-scaling)
- 장점 (Pros):
- 무중단 배포: 롤링 업데이트를 통해 사용자에게 다운타임 없는 경험 제공.
- 고가용성 (HA): 파드(Pod) 자동 복구 및 트래픽 부하 분산.
- 확장성: 트래픽 증가 시 노드와 파드를 자동으로 확장 가능.
- 단점 (Cons):
- 높은 비용: 클러스터 유지를 위한 고정 비용 발생 (월 $30 이상).
- 리소스 오버헤드: 쿠버네티스 시스템 파드들의 리소스 점유로 인해 소규모 앱에는 비효율적.
After: 단일 VM (Docker Compose) - 비용 효율성과 실용성
"실제 낮은 트래픽을 고려한하여 비용 효율적으로 운영하기 위한 아키텍처"

- 핵심 기술: Nginx (Reverse Proxy), Certbot (DNS-01 SSL), GitHub Actions (SSH Push), Swap Memory
- 장점 (Pros):
- 비용 제로화: GCP Free Tier(e2-micro, us-central1) 정책을 준수하여 프리티어 범위로 운영.
- 단순성:
docker-compose.yml파일 하나로 전체 인프라 정의 및 관리 가능. - 리소스 효율: 오케스트레이션 오버헤드를 제거하고, Swap 메모리를 활용하여 1GB RAM 한계 극복.
- 단점 :
- 단일 장애점 : VM 장애 시 전체 서비스 중단.
- 배포 다운타임: 컨테이너 재생성 시 수 초간의 짧은 서비스 중단 발생.
2. 인프라 재구성
Terraform을 사용하여 기존 GKE 리소스를 삭제하고, 프리티어 조건에 맞는 새로운 인프라를 프로비저닝했다.
2.1. 리전 변경 및 리소스 정의
GCP의 평생 무료 혜택은 특정 리전(us-central1 등)에서만 적용된다. 따라서 기존 서울 리전(asia-northeast3)을 포기하고 미국 리전으로 인프라를 이전했다.
2.2. Swap Memory 설정
e2-micro 인스턴스는 1GB RAM만을 제공한다. 이 환경에서 애플리케이션, DB, 배포 프로세스를 모두 실행하면 OOM (Out Of Memory) 이 발생할 위험이 크다. 이를 해결하기 위해 Terraform의 metadata_startup_script를 활용하여 VM 부팅 시 2GB의 Swap 메모리를 자동으로 생성하도록 구성했다.
# infra/vm.tf (Startup Script 일부) metadata_startup_script = <<-EOF #! /bin/bash # 1GB RAM 한계 극복을 위한 Swap 설정 if [ ! -f /swapfile ]; then fallocate -l 2G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile echo '/swapfile none swap sw 0 0' >> /etc/fstab fi # ... Docker 설치 스크립트 ... EOF
3. 컨테이너 오케스트레이션 전환: Docker Compose
쿠버네티스의 역할을 Docker Compose가 대신한다. 운영 환경을 위한 docker-compose.prod.yml을 작성하여 5개의 컨테이너(nginx, certbot, backend, frontend, db)를 하나의 네트워크로 묶었다.
이 과정에서 환경 변수 주입 문제가 발생했다. Docker Compose가 .env 파일의 변수를 컨테이너 내부로 전달할 때 치환 문제가 발생하여 DB 접속에 실패하는 현상이 있었다. 이를 해결하기 위해 .env.prod 파일 내에서 변수 재할당을 하지 않고 명시적인 값을 할당하는 방식으로 설정을 단순화했다.
4. HTTPS 및 도메인 연결: Nginx & Certbot
GKE Ingress가 담당하던 라우팅과 SSL 처리를 Nginx 컨테이너와 Certbot으로 직접 구현했다.
4.1. DNS-01 Challenge 도입
초기에는 webroot 방식을 시도했으나, Nginx 설정과 인증서 발급 간의 순환 의존성 및 네트워크 설정의 복잡함으로 인해 실패했다.
이를 해결하기 위해 DNS-01 Challenge 방식을 채택했다. 이 방식은 웹 서버 설정과 무관하게 AWS Route53 API를 통해 도메인 소유권을 증명하므로, 훨씬 안정적으로 인증서를 발급받을 수 있었다.
# docker-compose.prod.yml (Certbot 서비스) certbot: image: certbot/dns-route53 volumes: - certbot-conf:/etc/letsencrypt command: renew --dns-route53 env_file: .env.aws # AWS 자격 증명 주입
5. 배포 파이프라인 재구축
Argo CD를 제거하고, GitHub Actions가 직접 VM에 접속하여 배포하는 Push 방식으로 파이프라인을 변경했다.
- Build: Docker 이미지를 빌드하여 Artifact Registry에 푸시한다.
- Deploy:
appleboy/ssh-action을 사용하여 VM에 SSH로 접속한다. - Update:
scp로 최신 설정 파일(docker-compose.prod.yml)을 전송하고,docker compose pull && up -d를 실행하여 컨테이너를 갱신한다. - Cleanup:
docker image prune을 실행하여 한정된 디스크 공간(30GB)을 효율적으로 관리한다.

6. 데이터 영속성 및 관리 환경
6.1. 데이터 마이그레이션
기존 GKE 환경의 DB 데이터를 pg_dump로 백업한 후, 새로운 VM의 PostgreSQL 컨테이너에 psql 명령어로 복원하여 서비스의 연속성을 유지했다.
6.2. 로컬 관리 환경 (SSH 터널링)
보안을 위해 DB 포트(5432)를 외부 인터넷에 개방하지 않았다. 대신 개발 시에는 SSH 터널링을 통해 로컬 포트를 원격 DB 포트와 연결하여 안전하게 데이터를 조회하고 관리할 수 있도록 구성했다.
# 로컬 5433 포트를 원격 DB 5432 포트로 터널링 ssh -i key -L 5433:localhost:5433 user@vm-ip -N
(트러블슈팅: VM 내부의 DB 컨테이너가 127.0.0.1 인터페이스로 포트를 노출하도록 설정해야 터널링이 정상 작동함을 확인했다.)
7. 결론
이번 마이그레이션을 통해 "쿠버네티스 환경 학습용 오버 엔지니어링" 상태에서 "지속 가능한 프리티어 범위 내 운영" 상태로의 전환을 완료했다.
- 비용 제로화: GCP Free Tier 조건을 완벽하게 준수한다.
- 보안성 유지: HTTPS 적용, SSH Key 기반 접속, DB 포트 비공개 원칙을 준수한다.
- 자동화: 코드 푸시 한 번으로 빌드부터 배포까지 완료되는 파이프라인을 유지했다.
이제 시스템은 비용 부담 없이 평생 운영될 수 있는 기반을 갖추었다. 다음 포스팅에서는 이 안정된 기반 위에서 채팅방 분리, 관리자 기능 등 애플리케이션 레벨의 기능 고도화를 진행하는 과정을 다룰 예정이다.
