Redis Server Separation Plan (Option A — Pulumi · Ansible)
Purpose: In Frappe/ERPNext multitenant setup, move Redis off App servers and run a single Redis instance with logical roles via DB numbers (1/2/3) to keep operations simple. Pulumi provisions the Redis server, firewall, and network; Ansible installs/configures Redis and updates App Redis URLs. No code generation — plan, phases, ownership, and deliverables only.
§2 Target architecture: One Redis VM (Hetzner), port 6379 allowed only from App (or private network). MariaDB separate. App nodes connect to remote Redis URLs.
§3 Redis roles: DB 1 cache, 2 queue, 3 socketio. URLs: redis://:PASSWORD@redis_host:6379/1 etc. MariaDB = physical/logical isolation; Redis = shared, tenant_id in metadata.
§4 Frappe: common_site_config.json (redis_cache, redis_queue, redis_socketio). Password via Ansible Vault. Optional: env vars or central config (NFS/Consul).
§5 Pulumi: Redis VM, firewall (22 + 6379 from App IPs only), optional private network/volume/DNS. Export redis_server_ip for Ansible. Spec: e.g. 4GB RAM, Ubuntu 24.04.
§6 Ansible: New group prego_redis_servers, role redis_server (Docker, redis.conf, requirepass, appendonly). App play: inject Redis URLs into common_site_config or env. Order: Pulumi → Ansible on redis_servers → Ansible on nodes (config).
§7 Phases: (1) Redis VM + role + verify. (2) Network/security (6379 only from App). (3) App config change, remove local Redis. (4) Rolling cutover (workers down, switch config, bench restart, workers up). Runbook and rollback.
Full tables (§1.2, §3, §4.1, §5.1–§5.3, §6.1–§6.4, §7.1–§7.4) and exact wording are in the Korean section below.
한국어 {#korean}
Redis 서버 분리 개발 기획서 (A안 — Pulumi·Ansible)
목적: Frappe/ERPNext 멀티테넌트 환경에서 Redis를 App 서버에서 분리하고, 단일 Redis 인스턴스에서 내부 DB 번호(1/2/3)로 역할을 나누어 운영 복잡도를 최소화한다. Pulumi로 Redis 전용 서버·방화벽·네트워크를 프로비저닝하고, Ansible로 Redis 설치·설정 및 App 측 Redis URL 반영을 수행한다. 코드 생성 없음 — 기획·단계·책임·산출물만 정리.
설계 원칙: Google SRE 운영 원칙 및 클라우드 디자인 패턴을 참고하여, 독립 서버 환경에서 확장성(Scalability)·안정성(Reliability)을 보장하는 멀티테넌트 SaaS ERP 인프라에 맞춘다.
1. 목적 및 설계 목표 (Design Objectives)
1.1 목적
Redis를 App 서버에서 분리하여 전용 서버에서 운영
단일 Redis 인스턴스 사용, 내부 DB 번호(0/1/2/3)로 역할 논리 분리
MariaDB는 이미 별도 서버(현행 유지)
운영 복잡도 최소화(A안 권장/단순)
1.2 설계 목표 (Design Objectives)
목표
내용
테넌트 격리 (Tenant Isolation)
각 테넌트의 DB는 물리/논리적으로 분리하여 보안 및 장애 전파 방지. MariaDB는 별도 서버·스키마 분리; Redis는 공유하되 **테넌트 식별은 메시지 메타데이터(tenant_id)**로 수행.
중앙 집중형 이벤트 브로커 (Centralized Event Broker)
시스템 전체의 비동기 작업·메시징·캐시·실시간 이벤트를 공유 Redis 한 곳에서 처리. 여러 App 노드의 Worker가 동일 큐를 분담 처리(Competing Consumers 패턴).
운영 자동화 (Operational Automation)
Pulumi·Ansible 및 중앙 집중식 설정(common_site_config 등)을 통해 서버 증설·Redis 전환 시 수동 개입 최소화(KISS 원칙).
2. 목표 아키텍처
flowchart LR
App1[App Node 1]
App2[App Node 2]
Redis[(Redis Server)]
DB[(MariaDB Server)]
App1 --> Redis
App2 --> Redis
App1 --> DB
App2 --> DB
Redis 1대: 전용 VM(Hetzner). 6379 포트는 App 서버(또는 Private Network)만 허용. 중앙 집중형 이벤트 브로커 역할.
MariaDB: 기존 별도 서버 유지(테넌트 격리).
App 노드: Bench, Worker, Scheduler, SocketIO — 모두 원격 Redis URL로 연결. 독립 서버 환경에서 외부 DB/Redis 접근은 호스트 네트워크 또는 외부 네트워크 브릿지로 극대화할 수 있음.
3. Redis 역할 분리 전략 (단일 인스턴스, DB 번호 분리)
역할
Redis DB 번호
설명
redis_cache
1
캐시
redis_queue
2
RQ 작업 큐
redis_socketio
3
실시간 이벤트
(선택) default
0
예비/미사용
Redis URL 설계 (DB 번호 명시):
redis://:PASSWORD@redis_host:6379/1 # cache
redis://:PASSWORD@redis_host:6379/2 # queue
redis://:PASSWORD@redis_host:6379/3 # socketio
redis_host: Pulumi로 프로비저닝한 Redis 서버 IP 또는 Private Network 내부 호스트명(DNS).
3.1 데이터베이스 vs Redis 할당 전략 (아키텍처 정합성)
구분
전략
상세 내용
MariaDB
물리/논리 격리
테넌트별 독립 스키마 또는 인스턴스 할당. 데이터 주권·장애 전파 방지. 현행 DB 서버 분리와 동일.
Redis
중앙 집중형 공유
시스템 전체 이벤트·캐시·큐·실시간 메시지를 하나의 Redis에서 처리. **테넌트 식별은 메시지 메타데이터(tenant_id)**로 수행.
— 본 기획서의 “단일 Redis + DB 1/2/3 역할 분리”는 위 Redis 중앙 공유 전략에 부합한다.
4. Frappe 설정 반영
4.1 common_site_config.json
App 서버(또는 bench 볼륨)의 sites/common_site_config.json에 다음 키를 설정한다.
키
예시 값
redis_cache
redis://:password@redis.internal:6379/1
redis_queue
redis://:password@redis.internal:6379/2
redis_socketio
redis://:password@redis.internal:6379/3
비밀번호는 Ansible Vault 또는 배포 시크릿으로 관리. 평문 저장 금지.
4.2 환경변수 vs common_site_config
권장: common_site_config.json에 직접 설정 — Frappe 표준 방식.
Docker Compose 사용 시: 환경변수(REDIS_CACHE, REDIS_QUEUE, REDIS_SOCKETIO)로 주입할 수 있으나, Frappe가 config 파일을 우선할 수 있으므로 실제 스택( bench 컨테이너 vs frappe_docker )에 맞춰 주입 위치를 확정할 것. 기획 단계에서는 “redis” 문자열 검색으로 설정 주입 위치를 사전 조사하는 것을 권장.
4.3 중앙 집중식 설정 관리 (Runtime Reconfiguration 패턴)
현행: Ansible이 각 App 노드에 배포 시 common_site_config.json에 Redis URL을 주입. 서버별 로컬 파일로 유지.
확장 옵션: 여러 App 서버가 동일 Redis·DB 설정을 공유해야 할 때, 공유 파일 시스템(NFS) 또는 **설정 서버(Consul/Etcd)**에서 common_site_config.json을 동기화하여 로드하는 Runtime Reconfiguration 패턴 적용 검토. 서버 기동 시 중앙에서 최신 설정을 주입받아 수동 개입을 줄일 수 있음.
5. Pulumi 역할 (Redis 전용 서버·네트워크·보안)
5.1 범위
항목
내용
Redis 전용 서버
Hetzner VM 1대 (예: prego-redis-01). 동일 리전·동일 SSH 키·Placement Group(선택).
방화벽
SSH(22) + 6379는 App 서버 IP(들)만 허용. Public에서 6379 차단. (DB 서버 방화벽 패턴과 동일: saas-db-separation-and-scaling-plan.md Phase 1.)
Private Network
현재 Pulumi에 Private Network 사용 여부에 따라, Redis 서버를 동일 VPC에 넣고 App에서 redis.internal 등 내부 호스트명으로 접근하도록 할지 결정. 미사용 시 App 서버 공인 IP로 6379 허용.
볼륨
선택. Redis 데이터 영속화를 서버 디스크가 아닌 Volume으로 둘 경우 Pulumi에서 Volume 생성·부착.
관리용 DNS
선택. 예: redis-01.pregoi.com → Redis 서버 공인 IP (관리·헬스체크용).
5.2 출력(Export)
출력명
설명
Ansible에서의 사용
redis_server_ip
Redis 서버의 IPv4 주소
인벤토리 ansible_host (prego_redis_servers), App play의 redis_host 변수
기존 app_server_ip, db_server_ip와 동일한 패턴으로 export.
5.3 사양 가이드
항목
권장
Server type
최소 4GB RAM (Cache 12GB, Queue 0.51GB, SocketIO ~200MB, 여유 1GB). 예: CPX21 또는 동급.
전환 후: connected_clients, redis connection error 0건, Job 실행·캐시 동작 확인.
롤백 준비: 로컬 Redis 설정 원복용 설정/코드 준비, 동일 순서로 롤백 가능하도록 문서화.
11. 산출물 요약 (구현 시 생성할 것)
구분
산출물
Pulumi
Redis 전용 서버 리소스, Redis 전용 방화벽(22 + 6379 from App), export redis_server_ip. (선택: Volume, 관리용 DNS.)
Ansible
Role redis_server: defaults, tasks, handlers, templates(redis.conf.j2). Playbook: prego_redis_servers 대상 redis_server 적용.
Ansible
인벤토리 그룹 prego_redis_servers, App play에서 redis_cache/redis_queue/redis_socketio URL 반영(common_site_config 또는 env).
문서
Runbook: Redis 전환 절차, 설정 주입 위치, 검증·롤백 절차. Production 전환 체크리스트 상세판.
12. 장점·리스크·향후 확장
12.1 장점
항목
효과
단일 Redis
관리 단순
DB 번호 분리
역할 논리 분리 (cache/queue/socketio)
DB 분리 + Redis 분리
장애 격리
방화벽·Private Network
보안 강화
중앙 공유 Redis
Competing Consumers로 다수 Worker가 큐 분담 처리 가능
12.2 리스크
단일 Redis는 SPOF. 초기 SaaS에는 허용 가능.
고부하 시 DB 번호 분리보다 프로세스(인스턴스) 분리가 더 중요할 수 있음.
Redis 메모리 부족 시 전체 서비스 영향 → maxmemory·모니터링 필수.
공유 Redis 사용 시: 특정 테넌트의 과도한 요청·큐 적체가 전체에 영향 → 테넌트별 Throttling·Rate Limiting 필수(§8.4).
12.3 향후 확장 로드맵
Phase
내용
Phase 1 (현재)
Docker Compose·단일/소수 서버, Pulumi·Ansible으로 Redis·DB·App 분리. 로컬 및 단일 서버 테스트 안정화.
Phase 2
서비스 디스커버리·L7 라우팅: Nginx 또는 HAProxy 역방향 프록시 도입. tenant-a.your-erp.com 등 호스트 헤더 분석 후 해당 테넌트가 할당된 App 컨테이너로 트래픽 포워딩. Health Check로 장애 노드 라우팅 제외. 필요 시 Kubernetes(K8s) 도입으로 오케스트레이션·오토스케일링.
Phase 3
Redis Sentinel(HA), Queue 전용 Redis 분리 또는 Redis Cluster. 전 세계 사용자 지연 최소화를 위한 멀티 데이터센터 배포·데이터 동기화 체계.
12.4 서비스 디스커버리·라우팅 (Phase 2 참고)
구현 방법: Nginx 또는 HAProxy를 사용한 역방향 프록시(Reverse Proxy).
동작 원리: 사용자가 tenant-a.your-erp.com으로 접속 시, L7이 호스트 헤더를 분석하여 해당 테넌트가 할당된 Docker App 컨테이너(또는 노드)로 트래픽 포워딩. 독립 서버 환경에서는 호스트 네트워크(Host Network) 또는 외부 네트워크 브릿지로 외부 DB/Redis 접근성 확보.
13. 최종 구조 한 줄 요약
Redis 1대 (전용 VM) · DB 1=cache, 2=queue, 3=socketio
Pulumi: Redis 서버·방화벽 · Ansible: redis_server Role + App 쪽 Redis URL 반영