- 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>
8.0 KiB
8.0 KiB
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 설정
# 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 설치 (없으면)
brew install helm
2단계: 인프라 설치 (1회성)
2.1 Nginx Ingress Controller
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 확인:
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
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 생성
kubectl apply -f k8s/cert-manager/cluster-issuer.yaml
3단계: 네임스페이스 및 시크릿 생성 (1회성)
3.1 네임스페이스
kubectl apply -f k8s/namespace.yaml
3.2 OCIR 이미지 Pull Secret
# 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 앱 시크릿
# secrets.yaml.template을 복사하여 실제 값 입력
cp k8s/secrets.yaml.template k8s/secrets.yaml
# 편집 후
kubectl apply -f k8s/secrets.yaml
3.4 Oracle Wallet Secret
# 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
# 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 경로를 컨테이너 내부 마운트 경로로 수정:
[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 적용
kubectl apply -f k8s/configmap.yaml
4단계: 앱 배포
4.1 기본 리소스 배포
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 로그인 (이미지 푸시용)
docker login icn.ocir.io \
-u "idyhsdamac8c/<oci-username>" \
-p "<auth-token>"
4.3 이미지 빌드 & 배포
# 전체 배포
./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 인증서를 발급합니다.
운영 명령어
상태 확인
# 파드 상태
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
롤백
# 이전 버전으로 롤백
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
시크릿 업데이트
# secrets.yaml 수정 후
kubectl apply -f k8s/secrets.yaml
# 파드 재시작 (시크릿 변경 반영)
kubectl rollout restart deployment/backend -n tasteby
스케일링
# 백엔드 2개로 확장
kubectl scale deployment/backend --replicas=2 -n tasteby
배포 태그 규칙
- 형식:
v0.1.X(patch 버전 자동 증가) deploy.sh가 빌드 → 푸시 → K8s 업데이트 → git tag 생성 → 태그 푸시까지 자동 처리- 태그 메시지에 배포 대상(backend/frontend)과 이미지 태그 포함
# 태그 목록 확인
git tag -l 'v*' --sort=-v:refname
# 특정 태그의 배포 내역 확인
git tag -n20 v0.1.5
트러블슈팅
이미지 Pull 실패
kubectl describe pod <pod-name> -n tasteby
# Events에서 ImagePullBackOff 확인 → ocir-secret 점검
DB 연결 실패
kubectl exec -it deployment/backend -n tasteby -- env | grep ORACLE
# Oracle Wallet 마운트 확인
kubectl exec -it deployment/backend -n tasteby -- ls /etc/oracle/wallet/
인증서 발급 안 됨
kubectl get challenges -n tasteby
kubectl describe challenge -n tasteby
# DNS A 레코드가 LB IP로 설정되었는지, 80 포트가 열려있는지 확인
OCI GenAI 연결 실패
kubectl exec -it deployment/backend -n tasteby -- cat /root/.oci/config
# key_file 경로가 /root/.oci/oci_api_key.pem 인지 확인