Files
tasteby/docs/oke-deployment-guide.md
joungmin ff4e8d742d Add cuisine subcategory filter, fix remap logic, and add OKE deployment manifests
- Add 파인다이닝/코스 cuisine type to 한식/일식/중식/양식 categories
- Change cuisine filter from flat list to grouped optgroup with subcategories
- Fix remap-foods/remap-cuisine: add jdbcType=CLOB, fix CLOB LISTAGG,
  improve retry logic (3 attempts, batch size 5), add error logging
- Add OKE deployment: Dockerfiles, K8s manifests, deploy.sh, deployment guide
- Add Next.js standalone output for Docker builds

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

344 lines
8.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tasteby OKE 배포 가이드
## 아키텍처
```
Internet
OCI Load Balancer (Nginx Ingress가 자동 생성)
├─ / → frontend Service (Next.js :3001)
├─ /api/ → backend Service (Spring Boot :8000)
├─ cert-manager (Let's Encrypt 인증서 자동 발급/갱신)
└─ Redis (in-cluster 캐시 :6379)
```
## 인프라 정보
| 항목 | 값 |
|------|-----|
| 클러스터 | tasteby-cluster |
| 리전 | ap-seoul-1 (Seoul) |
| 노드 | ARM64 × 2대 (2 CPU / 8GB 각) |
| K8s 버전 | v1.34.2 |
| OCI 프로필 | JOUNGMINKOAWS |
| OCIR | icn.ocir.io/idyhsdamac8c/tasteby |
| 도메인 | www.tasteby.net (Namecheap DNS) |
| SSL | Let's Encrypt (cert-manager + HTTP-01) |
## 파일 구조
```
tasteby/
├── backend-java/Dockerfile
├── frontend/Dockerfile
├── k8s/
│ ├── namespace.yaml
│ ├── configmap.yaml
│ ├── secrets.yaml.template ← 실제 secrets.yaml은 .gitignore
│ ├── redis-deployment.yaml
│ ├── backend-deployment.yaml
│ ├── frontend-deployment.yaml
│ ├── ingress.yaml
│ └── cert-manager/
│ └── cluster-issuer.yaml
└── deploy.sh
```
## 리소스 배분
| 파드 | replicas | CPU req/lim | 메모리 req/lim |
|------|----------|-------------|----------------|
| backend (Java) | 1 | 500m / 1 | 768Mi / 1536Mi |
| frontend (Next.js) | 1 | 200m / 500m | 256Mi / 512Mi |
| redis | 1 | 100m / 200m | 128Mi / 256Mi |
| ingress-controller | 1 | 100m / 200m | 128Mi / 256Mi |
| cert-manager (×3) | 1씩 | 50m / 100m | 64Mi / 128Mi |
| **합계** | | **~1.2 CPU** | **~1.6GB** |
전체 클러스터: 4 CPU / 16GB → 여유 충분
---
## 1단계: 사전 준비
### 1.1 kubectl 설정
```bash
# OKE kubeconfig 가져오기
oci ce cluster create-kubeconfig \
--cluster-id ocid1.cluster.oc1.ap-seoul-1.aaaaaaaaoqgd2sh6754m5zrwfqaxwrtlqon3dxtdwbbc2dvzbcbou3pf75rq \
--profile JOUNGMINKOAWS \
--region ap-seoul-1 \
--token-version 2.0.0 \
--kube-endpoint PUBLIC_ENDPOINT
# ~/.kube/config의 user args에 --profile JOUNGMINKOAWS 추가 필요
# 확인
kubectl get nodes
```
### 1.2 Helm 설치 (없으면)
```bash
brew install helm
```
---
## 2단계: 인프라 설치 (1회성)
### 2.1 Nginx Ingress Controller
```bash
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace \
--set controller.service.type=LoadBalancer \
--set controller.service.annotations."oci\.oraclecloud\.com/load-balancer-type"=nlb
```
설치 후 External IP 확인:
```bash
kubectl get svc -n ingress-nginx ingress-nginx-controller -w
# EXTERNAL-IP가 나오면 Namecheap에서 A 레코드 업데이트
# www.tasteby.net → <EXTERNAL-IP>
# tasteby.net → <EXTERNAL-IP>
```
### 2.2 cert-manager
```bash
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager --create-namespace \
--set crds.enabled=true
```
### 2.3 ClusterIssuer 생성
```bash
kubectl apply -f k8s/cert-manager/cluster-issuer.yaml
```
---
## 3단계: 네임스페이스 및 시크릿 생성 (1회성)
### 3.1 네임스페이스
```bash
kubectl apply -f k8s/namespace.yaml
```
### 3.2 OCIR 이미지 Pull Secret
```bash
# OCI Auth Token 필요 (콘솔 > User Settings > Auth Tokens에서 생성)
kubectl create secret docker-registry ocir-secret \
--docker-server=icn.ocir.io \
--docker-username="idyhsdamac8c/<oci-username>" \
--docker-password="<auth-token>" \
--docker-email="<email>" \
-n tasteby
```
### 3.3 앱 시크릿
```bash
# secrets.yaml.template을 복사하여 실제 값 입력
cp k8s/secrets.yaml.template k8s/secrets.yaml
# 편집 후
kubectl apply -f k8s/secrets.yaml
```
### 3.4 Oracle Wallet Secret
```bash
# Wallet 디렉토리의 파일들을 Secret으로 생성
kubectl create secret generic oracle-wallet \
--from-file=cwallet.sso=<wallet-dir>/cwallet.sso \
--from-file=tnsnames.ora=<wallet-dir>/tnsnames.ora \
--from-file=sqlnet.ora=<wallet-dir>/sqlnet.ora \
--from-file=keystore.jks=<wallet-dir>/keystore.jks \
--from-file=truststore.jks=<wallet-dir>/truststore.jks \
--from-file=ojdbc.properties=<wallet-dir>/ojdbc.properties \
-n tasteby
```
### 3.5 OCI Config Secret
```bash
# OCI API key config 파일과 PEM 키를 Secret으로 생성
# config 파일은 K8s용으로 수정 필요 (key_file 경로를 /root/.oci/oci_api_key.pem으로)
kubectl create secret generic oci-config \
--from-file=config=<oci-config-for-k8s> \
--from-file=oci_api_key.pem=<pem-key-file> \
-n tasteby
```
**참고**: 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
```
### 3.6 ConfigMap 적용
```bash
kubectl apply -f k8s/configmap.yaml
```
---
## 4단계: 앱 배포
### 4.1 기본 리소스 배포
```bash
kubectl apply -f k8s/redis-deployment.yaml
kubectl apply -f k8s/backend-deployment.yaml
kubectl apply -f k8s/frontend-deployment.yaml
kubectl apply -f k8s/ingress.yaml
```
### 4.2 OCIR 로그인 (이미지 푸시용)
```bash
docker login icn.ocir.io \
-u "idyhsdamac8c/<oci-username>" \
-p "<auth-token>"
```
### 4.3 이미지 빌드 & 배포
```bash
# 전체 배포
./deploy.sh "초기 배포"
# 백엔드만 배포
./deploy.sh --backend-only "API 버그 수정"
# 프론트엔드만 배포
./deploy.sh --frontend-only "UI 개선"
# 드라이런 (실제 실행 안 함)
./deploy.sh --dry-run "테스트"
```
---
## 5단계: DNS 설정
Namecheap에서 A 레코드 변경:
| Type | Host | Value | TTL |
|------|------|-------|-----|
| A | @ | `<LB External IP>` | Automatic |
| A | www | `<LB External IP>` | Automatic |
DNS 전파 후 cert-manager가 자동으로 Let's Encrypt 인증서를 발급합니다.
---
## 운영 명령어
### 상태 확인
```bash
# 파드 상태
kubectl get pods -n tasteby
# 로그 확인
kubectl logs -f deployment/backend -n tasteby
kubectl logs -f deployment/frontend -n tasteby
# 인증서 상태
kubectl get certificate -n tasteby
kubectl describe certificate tasteby-tls -n tasteby
```
### 롤백
```bash
# 이전 버전으로 롤백
kubectl rollout undo deployment/backend -n tasteby
kubectl rollout undo deployment/frontend -n tasteby
# 특정 리비전으로 롤백
kubectl rollout history deployment/backend -n tasteby
kubectl rollout undo deployment/backend --to-revision=2 -n tasteby
```
### 시크릿 업데이트
```bash
# secrets.yaml 수정 후
kubectl apply -f k8s/secrets.yaml
# 파드 재시작 (시크릿 변경 반영)
kubectl rollout restart deployment/backend -n tasteby
```
### 스케일링
```bash
# 백엔드 2개로 확장
kubectl scale deployment/backend --replicas=2 -n tasteby
```
---
## 배포 태그 규칙
- 형식: `v0.1.X` (patch 버전 자동 증가)
- `deploy.sh`가 빌드 → 푸시 → K8s 업데이트 → git tag 생성 → 태그 푸시까지 자동 처리
- 태그 메시지에 배포 대상(backend/frontend)과 이미지 태그 포함
```bash
# 태그 목록 확인
git tag -l 'v*' --sort=-v:refname
# 특정 태그의 배포 내역 확인
git tag -n20 v0.1.5
```
---
## 트러블슈팅
### 이미지 Pull 실패
```bash
kubectl describe pod <pod-name> -n tasteby
# Events에서 ImagePullBackOff 확인 → ocir-secret 점검
```
### DB 연결 실패
```bash
kubectl exec -it deployment/backend -n tasteby -- env | grep ORACLE
# Oracle Wallet 마운트 확인
kubectl exec -it deployment/backend -n tasteby -- ls /etc/oracle/wallet/
```
### 인증서 발급 안 됨
```bash
kubectl get challenges -n tasteby
kubectl describe challenge -n tasteby
# DNS A 레코드가 LB IP로 설정되었는지, 80 포트가 열려있는지 확인
```
### OCI GenAI 연결 실패
```bash
kubectl exec -it deployment/backend -n tasteby -- cat /root/.oci/config
# key_file 경로가 /root/.oci/oci_api_key.pem 인지 확인
```