홈으로 돌아가기

VPS의 Docker: 프로덕션 24개 컨테이너

이 기사는 6 GB RAM VPS에 24개 Docker 컨테이너의 프로덕션 배포를 분석합니다. 격리 아키텍처 원칙, healthcheck을 통한 종속성 관리, Elasticsearch 및 Chrome Headless의 메모리 사용 최적화, SSH 터널을 통한 원격 DB 보안 작업, Prometheus 없이 경량 모니터링을 다룹니다.

한 서버에 24개 컨테이너: 기술 분석
Advertisement 728x90

단일 VPS 에 24 컨테이너: 중급/시니어 데브옵스를 위한 고밀도 기술 아키텍처

서버 하나, RAM 6GB, 컨테이너 24 개 — 모두 1 년 이상 안정적으로 작동합니다. 이는 실험이 아니라, 7 개의 활성 프로젝트를 지원하는 프로덕션 인프라입니다: 에듀테크 봇, 안티스팸 서비스, AI 백엔드, 메타 검색 엔진, 로컬 LLM 추론, 그리고 두 가지 유틸리티 서비스. 어느 것도 수익을 창출하지는 않지만, 모든 서비스가 운영 활동에 필수적입니다. 목표는 비용 절감 그 자체가 아니라 의도적인 타협이었습니다: 관리형 서비스 대신 수동 관리, 클라우드 탄력성 대신 예측 가능한 부하, 추상화 대신 깊은 통합.

Architectural Principles: Isolation, Observability, Resilience

핵심 접근 방식은 엄격한 네트워크 격리에 의존합니다. 각 프로젝트는 자체 Docker 네트워크 (bridge) 에 위치하여 종속성을 제거하고 공격 표면 (attack surface) 을 최소화합니다. shared 공유 네트워크는 모니터링이나 공통 Redis 와 같은 시스템 서비스에만 사용됩니다. 내부 포트 (9200, 8088, 9222) 는 127.0.0.1 를 통해서만 접근 가능하며, iptables 및 nginx 설정 수준에서 외부 접근은 차단됩니다.

복원력은 docker-compose.yml 의 헬스체크 의존성을 통해 보장됩니다. 예를 들어, EdTech 프로젝트의 PHP 서비스는 원격 데이터베이스로의 SSH 터널이 nc -z 127.0.0.1 3306 검사를 통과할 때까지 시작되지 않습니다. 이를 통해 애플리케이션이 사용 불가능한 데이터베이스에 연결하려고 시도하여 큐를 오류로 가득 채우지 않도록 보장합니다.

Google AdInline article slot

RAM 제약으로 인해 Prometheus/Grafana 없이 관측 가능성 (Observability) 이 구축되었습니다. 대신 매 15 분마다 bash 스크립트가 실행됩니다:

  • 공개 엔드포인트의 HTTP 상태 코드 확인 (/health, /webhook/advert)
  • docker ps --filter "health=unhealthy" 를 통한 비정상 컨테이터 식별
  • 디스크 공간 및 스왑 사용량 모니터링
  • Bot API 로 curl 을 사용하여 Telegram 채팅으로 알림 전송

이는 단일 관리자에게 최소한의 충분성을 제공하는 가시성을 제공합니다.

Critical Components: Elasticsearch, Chrome Headless, and SSH Tunnels

세 가지 구성 요소가 VPS 의 성능 한계를 정의합니다:

Google AdInline article slot
  • Elasticsearch 8.12.2 는 1.47 GB RAM 을 소비합니다. deploy.resources.limits 에 명시적인 memory: 2g 제한이 없으면 JVM 은 인접 프로세스를 스왑 아웃하기 시작하여 불안정성을 초래합니다. 약 5 만 개의 문서와 로깅용 인덱스에 대해 기능과 부하 사이의 최적 균형을 제공합니다. 대안인 Meilisearch 는 기존 인덱스를 마이그레이션하고 클라이언트 코드를 수정해야 하므로 현재 단계에서는 높은 노력 대비 낮은 ROI 를 가진 작업으로 평가됩니다.
  • Chrome Headless (zenika/alpine-chrome) 는 636 MB RAM 을 차지하지만, JS 렌더링 스크래핑을 위해 시간당 한 번만 사용됩니다. docker run --rm 을 통해 온디맨드로 실행하면 메모리를 절약할 수 있지만 호출당 5~10 초의 지연 시간이 추가됩니다. 엄격한 SLA 를 가진 서비스에는 용납될 수 없지만, 여기서는 허용 가능한 타협입니다.
  • SSH 터널autossh 를 사용한 별도의 알파인 컨테이너에 구현되어 있습니다. 외부 포트를 열지 않고 공유 호스트의 MySQL 에 대한 안전한 액세스를 제공합니다. 설정에는 ServerAliveInterval=30, AUTOSSH_GATETIME=0nc 를 통한 헬스체크가 포함됩니다. 이 솔루션은 SSH 를 지원하는 모든 호스트에서 작동하며 유료 관리형 데이터베이스를 완전히 대체합니다.

Nginx and PHP Optimization: Reducing Latency by Milliseconds

Nginx 는 웹훅 및 API 전용으로 구성되어 있으며 /health 를 제외한 정적 파일은 없습니다. 주요 최적화는 Telegram 웹훅 처리를 별도의 PHP 파일 (webhook-advert.php) 로 오프로드하여 Laravel 부트스트랩을 우회하는 것입니다. 이로써 응답 시간이 80~120 ms 에서 15~25 ms 로 단축되어 Telegram API 의 대량 웹훅 호출 시 (최대 타임아웃 — 60 초) 중요합니다.

설정에는 다음이 포함됩니다:

  • 강제 HTTP → HTTPS 리디렉션
  • /health, /webhook/, /api/telegram/ 외의 경로 처리 거부
  • 장기 실행 작업을 위한 fastcgi_read_timeout 을 120 초로 증가
  • 올바른 index.php 처리를 위한 realpath_root 사용

SSL and Security: Three Strategies on One Host

SSL 종결은 하이브리드로 조직됩니다:

Google AdInline article slot
  • getssl + Let's Encrypt — Cloudflare 없이 끝단 간 암호화가 필요한 도메인용
  • Cloudflare Proxy — 대부분의 도메인용: SSL 이 엣지에서 종결되며 VPS 로 가는 트래픽은 HTTP 로 진행되지만 IP 필터링 (Cloudflare ASN 만 허용) 으로 보호됨
  • 수동 업데이트 — 자동화를 진행 중인 AI 백엔드에 대한 임시 조치, 현재 Caddy 를 통해 자동화 중

Cloudflare 설정에는 필수 Always Use HTTPS, WAF, Rate Limiting(IP 당 분당 100 요청) 이 포함되어 VPS 측 WAF 부재를 보완합니다.

Key Takeaways

  • 별개의 Docker 네트워크를 통한 엄격한 네트워크 격리는 연쇄 장애를 방지하고 보안 감사 간소화에 도움이 됩니다.
  • docker-compose 의 헬스체크 의존성은 서비스 시작 전 종속성이 준비되었음을 보장합니다 (예: DB 에 대한 SSH 터널).
  • Elasticsearch 는 하드 메모리 제한 (2 GB) 이 필요합니다. 그렇지 않으면 JVM 이 인접 컨테이너를 스왑 아웃하여 OOM 킬러를 트리거합니다.
  • 비즈니스 로직에 시작 지연 시간이 중요한 경우 저주파 사용 시 Chrome Headless 를 항상 켜두는 것이 정당화됩니다.
  • 명확하게 정의된 SLO 가 있는 경우 RAM 제약 하에서 Bash 모니터링과 Telegram 알림은 Prometheus/Grafana 의 작동 가능한 대체재입니다.

— Editorial Team

Advertisement 728x90

다음 읽기