From 293c59060cb5ef4700dbd5944711f92cf5996a74 Mon Sep 17 00:00:00 2001 From: joungmin Date: Mon, 9 Mar 2026 23:02:59 +0900 Subject: [PATCH] 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 --- docs/environment-guide.md | 182 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 docs/environment-guide.md diff --git a/docs/environment-guide.md b/docs/environment-guide.md new file mode 100644 index 0000000..b29e2ec --- /dev/null +++ b/docs/environment-guide.md @@ -0,0 +1,182 @@ +# 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` 경로를 컨테이너 내부로 변경해야 합니다: +```ini +[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. **운영 시크릿 변경 시**: + ```bash + # secrets.yaml 수정 후 + kubectl apply -f k8s/secrets.yaml + kubectl rollout restart deployment/backend -n tasteby + ``` +4. **파일 기반 시크릿(Wallet, OCI config)은 kubectl로 직접 생성**: + ```bash + 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`이 환경변수를 자동으로 읽습니다: + +```yaml +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의 모든 키-값이 환경변수로 들어갑니다: + +```yaml +# backend-deployment.yaml +envFrom: + - configMapRef: + name: tasteby-config # REDIS_HOST, REDIS_PORT, ... + - secretRef: + name: tasteby-secrets # ORACLE_USER, ORACLE_PASSWORD, ... +``` + +개발 환경에서는 동일한 변수명이 `backend/.env`에서 `source`로 로드됩니다. +**변수명이 동일하므로 코드 변경 없이 환경만 바꿀 수 있습니다.**