Files
tasteby/docs/environment-guide.md
joungmin 293c59060c Add environment management guide for dev/prod separation
- Document all env vars with dev vs prod mapping
- Explain K8s Service DNS for Redis connectivity
- Detail Secret/ConfigMap strategy for sensitive config
- Cover OCI auth and Oracle Wallet volume mount differences

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 23:02:59 +09:00

9.7 KiB

Tasteby 환경 관리 가이드

환경 구성 개요

┌─────────────────────────────────────────────────────────────┐
│                        개발 (Local)                          │
│                                                              │
│  backend/.env          ← 백엔드 환경변수 (DB, OCI, Google)   │
│  frontend/.env.local   ← 프론트엔드 환경변수 (NEXT_PUBLIC_*) │
│  ~/.oci/config         ← OCI API 인증 (로컬 경로)            │
│  Oracle Wallet 디렉토리 ← DB mTLS 인증 (로컬 경로)           │
│                                                              │
│  PM2 → start.sh → source backend/.env → gradlew bootRun     │
│  PM2 → npm run dev (Next.js, .env.local 자동 로드)           │
│  Redis → 192.168.0.147:6379 (로컬 네트워크)                  │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                       운영 (OKE)                             │
│                                                              │
│  k8s/configmap.yaml    ← 비밀이 아닌 설정 (Redis host 등)    │
│  k8s/secrets.yaml      ← 민감 정보 (DB, JWT, API keys)      │
│  Secret: oracle-wallet  ← DB mTLS 인증 (Volume 마운트)       │
│  Secret: oci-config     ← OCI API 인증 (Volume 마운트)       │
│                                                              │
│  Pod → envFrom: ConfigMap + Secret → application.yml 참조    │
│  Redis → redis:6379 (K8s Service DNS, 클러스터 내부)          │
└─────────────────────────────────────────────────────────────┘

환경변수 전체 목록

백엔드 (application.yml에서 참조)

변수명 설명 민감 개발 운영
ORACLE_USER DB 사용자명 backend/.env Secret
ORACLE_PASSWORD DB 비밀번호 backend/.env Secret
ORACLE_DSN TNS 연결 문자열 backend/.env Secret
ORACLE_WALLET Wallet 디렉토리 경로 backend/.env ConfigMap → /etc/oracle/wallet
JWT_SECRET JWT 서명 키 기본값 사용 Secret
OCI_COMPARTMENT_ID OCI 컴파트먼트 ID backend/.env Secret
OCI_CHAT_ENDPOINT GenAI Chat 엔드포인트 backend/.env ConfigMap
OCI_GENAI_ENDPOINT GenAI Embed 엔드포인트 backend/.env ConfigMap
OCI_CHAT_MODEL_ID Chat 모델 ID backend/.env Secret
OCI_EMBED_MODEL_ID Embed 모델 ID backend/.env ConfigMap
GOOGLE_MAPS_API_KEY Google Maps API 키 backend/.env Secret
YOUTUBE_DATA_API_KEY YouTube Data API 키 backend/.env Secret
GOOGLE_CLIENT_ID Google OAuth 클라이언트 ID 기본값 사용 ConfigMap
REDIS_HOST Redis 호스트 기본값 192.168.0.147 ConfigMap → redis
REDIS_PORT Redis 포트 기본값 6379 ConfigMap
REDIS_DB Redis DB 번호 기본값 0 ConfigMap

프론트엔드 (빌드 시 주입)

변수명 설명 개발 운영
NEXT_PUBLIC_API_URL API 기본 URL .env.local → 빈값 (상대경로) Docker build arg → 빈값
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY Maps API 키 .env.local Docker build arg
NEXT_PUBLIC_GOOGLE_CLIENT_ID OAuth 클라이언트 ID .env.local Docker build arg

참고: NEXT_PUBLIC_* 변수는 Next.js 빌드 시 코드에 인라인되므로, 런타임이 아닌 Docker 빌드 시점에 주입해야 합니다.

개발 vs 운영 차이점

Redis 연결

개발: REDIS_HOST=192.168.0.147 (로컬 네트워크 IP, 기본값)
운영: REDIS_HOST=redis          (K8s Service DNS, ConfigMap)

K8s에서 Service 이름 redis는 클러스터 내부 DNS로 자동 해석됩니다. Pod IP가 변경되어도 Service가 항상 올바른 Pod를 가리킵니다.

redis (Service, ClusterIP)
  └─ selector: app=redis
      └─ redis Pod (IP 자동 할당, 변경되어도 Service가 추적)

OCI 인증

개발: ~/.oci/config → 로컬 PEM 파일 경로
운영: /root/.oci/config → Secret Volume 마운트
     /root/.oci/oci_api_key.pem → Secret Volume 마운트

운영용 OCI config 파일은 key_file 경로를 컨테이너 내부로 변경해야 합니다:

[DEFAULT]
user=ocid1.user.oc1..xxx
fingerprint=xx:xx:xx
key_file=/root/.oci/oci_api_key.pem    ← 컨테이너 내부 경로
tenancy=ocid1.tenancy.oc1..xxx
region=ap-seoul-1

Oracle DB 연결

개발: ORACLE_WALLET=/Users/joungmin/.../Wallet_xxx (로컬 경로)
      ORACLE_DSN=tasteby_high?TNS_ADMIN=/Users/joungmin/.../Wallet_xxx
운영: ORACLE_WALLET=/etc/oracle/wallet (Secret Volume 마운트 경로)
      ORACLE_DSN=tasteby_high?TNS_ADMIN=/etc/oracle/wallet

환경별 설정 파일 매핑

┌──────────────────┬──────────────────────┬──────────────────────────┐
│     설정 항목     │    개발 (Local)       │       운영 (OKE)          │
├──────────────────┼──────────────────────┼──────────────────────────┤
│ 백엔드 환경변수   │ backend/.env          │ k8s/configmap.yaml       │
│                  │ (start.sh에서 source)  │ k8s/secrets.yaml         │
├──────────────────┼──────────────────────┼──────────────────────────┤
│ 프론트엔드 환경변수│ frontend/.env.local   │ Dockerfile build args    │
│                  │ (Next.js 자동 로드)    │ (deploy.sh에서 주입)      │
├──────────────────┼──────────────────────┼──────────────────────────┤
│ OCI 인증         │ ~/.oci/config         │ Secret: oci-config       │
│                  │ (로컬 PEM 경로)        │ (Volume → /root/.oci/)   │
├──────────────────┼──────────────────────┼──────────────────────────┤
│ Oracle Wallet    │ 로컬 Wallet 디렉토리   │ Secret: oracle-wallet    │
│                  │                      │ (Volume → /etc/oracle/   │
│                  │                      │  wallet/)                │
├──────────────────┼──────────────────────┼──────────────────────────┤
│ Redis            │ 192.168.0.147:6379   │ redis:6379               │
│                  │ (로컬 네트워크)        │ (K8s Service DNS)        │
├──────────────────┼──────────────────────┼──────────────────────────┤
│ 웹서버/SSL       │ nginx + Let's Encrypt │ Ingress + cert-manager   │
│                  │ (로컬 certbot)         │ (자동 발급/갱신)          │
└──────────────────┴──────────────────────┴──────────────────────────┘

시크릿 관리 원칙

  1. secrets.yaml은 git에 올리지 않음.gitignore에 포함
  2. secrets.yaml.template만 git에 올림 — 키 이름 + 구조만 공유
  3. 운영 시크릿 변경 시:
    # secrets.yaml 수정 후
    kubectl apply -f k8s/secrets.yaml
    kubectl rollout restart deployment/backend -n tasteby
    
  4. 파일 기반 시크릿(Wallet, OCI config)은 kubectl로 직접 생성:
    kubectl create secret generic oracle-wallet --from-file=... -n tasteby
    kubectl create secret generic oci-config --from-file=... -n tasteby
    

application.yml의 환경변수 바인딩

Spring Boot의 application.yml이 환경변수를 자동으로 읽습니다:

spring:
  datasource:
    url: jdbc:oracle:thin:@${ORACLE_DSN}       # ← Secret에서 주입
  data:
    redis:
      host: ${REDIS_HOST:192.168.0.147}         # ← ConfigMap에서 주입, 개발은 기본값
app:
  oci:
    compartment-id: ${OCI_COMPARTMENT_ID}       # ← Secret에서 주입

K8s에서는 envFrom으로 ConfigMap과 Secret의 모든 키-값이 환경변수로 들어갑니다:

# backend-deployment.yaml
envFrom:
  - configMapRef:
      name: tasteby-config     # REDIS_HOST, REDIS_PORT, ...
  - secretRef:
      name: tasteby-secrets    # ORACLE_USER, ORACLE_PASSWORD, ...

개발 환경에서는 동일한 변수명이 backend/.env에서 source로 로드됩니다. 변수명이 동일하므로 코드 변경 없이 환경만 바꿀 수 있습니다.