
요약: 월 $100의 고정 비용이 발생하는 GCP Cloud Run 환경을 단일 노드 온프레미스 k3s 클러스터로 이관하여 비용을 90% 이상 절감하고, Argo CD를 통해 클라우드 네이티브 수준의 배포 경험(DX)을 유지한 경험을 공유합니다.
초기 스타트업이나 사이드 프로젝트에서 Google Cloud Run은 매력적인 선택지입니다. 인프라 관리 없이 컨테이너만 던지면 알아서 스케일링되고, 트래픽이 없으면 비용이 0이 되는 'Scale to Zero'는 환상적입니다.
하지만 서비스가 성장하고 Always-on 워크로드가 늘어나면 이야기가 달라집니다.
min-instances를 설정해야 하며,결국 "편리함"의 대가로 지불하는 프리미엄이 실제 하드웨어 비용 대비 과도하게 느껴지는 시점이 옵니다. 저는 이 지점에서 "로컬 온프레미스(Local On-premise)"로 돌아가려고 결심했습니다. 단, Kubernetes의 강력한 오케스트레이션 능력은 유지한 채로요.
"집에서 쿠버네티스를 돌린다"고 하면 대부분 오버엔지니어링이라고 생각합니다. 하지만 k3s라면 이야기가 다릅니다.
| 구분 | 기존 (GCP Cloud Run) | 변경 (On-Premise k3s) |
|---|---|---|
| Compute | Cloud Run (Serverless) | Mac Mini (Single Node) |
| Orchestrator | Google Borg (Managed) | k3s |
| Delivery | Cloud Build + gcloud deploy | Argo CD (GitOps) |
| Ingress | Global Load Balancer | Cloudflare Tunnel (Gateway) |
| Monitoring | Cloud Monitoring | Prometheus + Grafana (via Helm) |
단순히 kubectl apply로 배포하는 것은 지속 가능하지 않습니다. 클라우드 환경에서 누리던 자동화와 안정성을 온프레미스에 이식하기 위해 다음과 같은 전략을 사용했습니다.
인프라의 상태를 코드로 관리(IaC)하기 위해 Argo CD를 도입했습니다. 특히 App of Apps 패턴을 적용하여 클러스터 전체를 부트스트랩합니다.
# k8s/bootstrap/root-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: platform-bootstrap
spec:
source:
repoURL: 'https://github.com/gwak2837/....git'
path: k8s/platform
targetRevision: HEAD
# ...
디렉토리 구조는 다음과 같이 계층화했습니다.
k8s/platform/: 클러스터 전역 유틸리티 (Cert-manager, Ingress Controller, Monitoring)k8s/apps/: 실제 비즈니스 애플리케이션 (Next.js, Hono API, Redis)이제 git push 한 번이면, Argo CD가 변경 사항을 감지하고 로컬 클러스터의 상태를 동기화(Sync)합니다.
로컬 서버를 외부에 노출할 때 가장 큰 보안 위협은 방화벽 구멍(Port Forwarding)입니다. 이를 해결하기 위해 Cloudflare Tunnel (cloudflared)을 k8s 내부에 배포했습니다.
cloudflared 파드가 아웃바운드 전용 터널을 생성하여 Cloudflare 엣지와 연결됩니다.# cloudflared 설정 예시
ingress:
- hostname: api.litomi.com
service: http://litomi-api-service:8080
- hostname: monitor.litomi.com
service: http://kube-prometheus-stack-grafana:80
GCP에서는 클릭 몇 번으로 보던 메트릭을 직접 구축해야 합니다. kube-prometheus-stack Helm 차트를 커스터마이징하여 배포했습니다.
이 모든 설정 역시 k8s/platform/monitoring/values.yaml 파일로 버전 관리됩니다.
물론 모든 것이 장점만 있는 것은 아닙니다. Serverless의 무한한 확장성을 포기하고 고정된 하드웨어로 돌아오면서 겪은 기술적 과제들이 있었습니다.
Cloud Run에서는 돈만 내면 CPU와 메모리가 마법처럼 늘어났지만, 단일 노드 환경은 물리적 상한선(예: 16GB RAM)이 명확합니다. 배치 작업이 돌 때 웹 서버의 응답 속도가 느려지는 '이웃 소음(Noisy Neighbor)' 문제가 발생할 수 있습니다.
이를 해결하기 위해 Kubernetes의 QoS(Quality of Service) 클래스를 적극적으로 활용해야 했습니다.
requests와 limits를 동일하게 설정하여 리소스를 독점적으로 보장.단일 노드이기에 하드웨어 장애 시 서비스가 중단됩니다. 하지만 현재 서비스 규모에서는 "99.99%의 가용성"보다 "비용 효율성"이 더 중요하다고 판단했습니다. (필요 시 물리 노드 추가로 쉽게 확장 가능)
이 마이그레이션을 통해 얻은 성과는 명확합니다.
Cloud Run은 훌륭하지만, 엔지니어에게 "나만의 클라우드"를 구축해 보는 것만큼 값진 경험은 없습니다. k3s와 Argo CD는 그 여정을 위한 좋은 도구입니다.