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>
This commit is contained in:
182
docs/environment-guide.md
Normal file
182
docs/environment-guide.md
Normal file
@@ -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`로 로드됩니다.
|
||||
**변수명이 동일하므로 코드 변경 없이 환경만 바꿀 수 있습니다.**
|
||||
Reference in New Issue
Block a user