356 lines
18 KiB
Markdown
356 lines
18 KiB
Markdown
# Tasteby CI/CD 파이프라인 & 전체 아키텍처
|
||
|
||
## 전체 시스템 아키텍처
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────────────┐
|
||
│ Internet │
|
||
│ www.tasteby.net │
|
||
└──────────────────────────────┬──────────────────────────────────────────┘
|
||
│
|
||
┌─────────▼──────────┐
|
||
│ Namecheap DNS │
|
||
│ A → LB External IP │
|
||
└─────────┬──────────┘
|
||
│
|
||
┌──────────────────────────────▼──────────────────────────────────────────┐
|
||
│ OCI Load Balancer (NLB) │
|
||
│ (Nginx Ingress Controller가 자동 생성) │
|
||
└──────────────────────────────┬──────────────────────────────────────────┘
|
||
│
|
||
┌──────────────────────────────▼──────────────────────────────────────────┐
|
||
│ OKE Cluster (tasteby-cluster) │
|
||
│ ap-seoul-1 │ ARM64 × 2 노드 (2CPU/8GB 각) │
|
||
│ │
|
||
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
||
│ │ Nginx Ingress Controller (ingress-nginx) │ │
|
||
│ │ │ │
|
||
│ │ TLS termination (Let's Encrypt via cert-manager) │ │
|
||
│ │ tasteby.net → www.tasteby.net 리다이렉트 │ │
|
||
│ │ │ │
|
||
│ │ /api/* ──→ backend Service :8000 │ │
|
||
│ │ /* ──→ frontend Service :3001 │ │
|
||
│ └─────────────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ ┌─── namespace: tasteby ─────────────────────────────────────────────┐ │
|
||
│ │ │ │
|
||
│ │ ┌──────────────────┐ ┌──────────────────┐ ┌────────────────┐ │ │
|
||
│ │ │ backend (×1) │ │ frontend (×1) │ │ redis (×1) │ │ │
|
||
│ │ │ Spring Boot 3 │ │ Next.js 15 │ │ Redis 7 │ │ │
|
||
│ │ │ Java 21 │ │ standalone mode │ │ alpine │ │ │
|
||
│ │ │ :8000 │ │ :3001 │ │ :6379 │ │ │
|
||
│ │ │ │ │ │ │ │ │ │
|
||
│ │ │ ┌─ Volumes ─────┐│ └──────────────────┘ └────────────────┘ │ │
|
||
│ │ │ │ oracle-wallet ││ │ │
|
||
│ │ │ │ oci-config ││ │ │
|
||
│ │ │ └───────────────┘│ │ │
|
||
│ │ └──────────────────┘ │ │
|
||
│ │ │ │
|
||
│ │ ┌─── ConfigMap / Secrets ──────────────────────────────────────┐ │ │
|
||
│ │ │ tasteby-config : REDIS_HOST, OCI endpoints, 등 │ │ │
|
||
│ │ │ tasteby-secrets : DB credentials, API keys, JWT │ │ │
|
||
│ │ │ oracle-wallet : cwallet.sso, tnsnames.ora, keystore.jks │ │ │
|
||
│ │ │ oci-config : OCI API config + PEM key │ │ │
|
||
│ │ │ ocir-secret : OCIR 이미지 Pull 인증 │ │ │
|
||
│ │ └──────────────────────────────────────────────────────────────┘ │ │
|
||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||
│ │
|
||
│ ┌─── namespace: cert-manager ──┐ ┌─── namespace: ingress-nginx ──┐ │
|
||
│ │ cert-manager (×3 pods) │ │ ingress-nginx-controller │ │
|
||
│ │ ClusterIssuer: letsencrypt │ │ (NLB 자동 생성) │ │
|
||
│ └──────────────────────────────┘ └────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────────────────┘
|
||
│
|
||
┌─────────▼──────────┐
|
||
│ Oracle ADB 23ai │
|
||
│ (mTLS via Wallet) │
|
||
└────────────────────┘
|
||
```
|
||
|
||
## 외부 서비스 연동
|
||
|
||
```
|
||
backend (Spring Boot)
|
||
├─→ Oracle ADB 23ai : JDBC + mTLS (Wallet)
|
||
├─→ OCI GenAI (Chat) : 식당 정보 추출, 음식 태그, 평가 생성
|
||
├─→ OCI GenAI (Embed) : 벡터 임베딩 (Cohere embed-v4)
|
||
├─→ Google Maps Places API : 식당 검색, 좌표 조회
|
||
├─→ YouTube Data API v3 : 채널/영상 정보 조회
|
||
└─→ Redis : 캐시 (API 응답, 검색 결과)
|
||
|
||
frontend (Next.js)
|
||
├─→ Google Maps JavaScript API : 지도 렌더링
|
||
└─→ Google OAuth 2.0 : 사용자 인증
|
||
```
|
||
|
||
---
|
||
|
||
## CI/CD 파이프라인
|
||
|
||
### 파이프라인 개요
|
||
|
||
```
|
||
┌──────────┐ ┌──────────────────┐ ┌──────────────────────┐ ┌─────────┐
|
||
│ 개발자 │────→│ OCI Code Repo │────→│ OCI DevOps Build │────→│ OKE │
|
||
│ git push │ │ (tasteby) │ │ Pipeline │ │ 배포 │
|
||
└──────────┘ └──────────────────┘ └──────────────────────┘ └─────────┘
|
||
```
|
||
|
||
### 상세 흐름
|
||
|
||
```
|
||
1. 코드 푸시
|
||
┌──────────────┐
|
||
│ git push oci │ ← OCI Code Repository remote
|
||
└──────┬───────┘
|
||
│
|
||
▼
|
||
2. 빌드 파이프라인 (OCI DevOps Build Pipeline)
|
||
┌───────────────────────────────────────────────────────────┐
|
||
│ │
|
||
│ Stage 1: Managed Build │
|
||
│ ┌──────────────────────────────────────────────────────┐ │
|
||
│ │ build_spec.yaml 실행 │ │
|
||
│ │ │ │
|
||
│ │ 1) IMAGE_TAG 생성 (BuildRunID + timestamp) │ │
|
||
│ │ 2) docker build --platform linux/arm64 │ │
|
||
│ │ - backend-java/Dockerfile → backend image │ │
|
||
│ │ - frontend/Dockerfile → frontend image │ │
|
||
│ │ 3) Output: BACKEND_IMAGE, FRONTEND_IMAGE │ │
|
||
│ └──────────────────────────────────────────────────────┘ │
|
||
│ │ │
|
||
│ ▼ │
|
||
│ Stage 2: Deliver Artifacts │
|
||
│ ┌──────────────────────────────────────────────────────┐ │
|
||
│ │ Docker images → OCIR 푸시 │ │
|
||
│ │ │ │
|
||
│ │ icn.ocir.io/idyhsdamac8c/tasteby/backend:TAG │ │
|
||
│ │ icn.ocir.io/idyhsdamac8c/tasteby/frontend:TAG │ │
|
||
│ └──────────────────────────────────────────────────────┘ │
|
||
└───────────────────────────────────────────────────────────┘
|
||
│
|
||
▼
|
||
3. 배포 (수동 또는 deploy.sh)
|
||
┌───────────────────────────────────────────────────────────┐
|
||
│ kubectl set image deployment/backend backend=IMAGE:TAG │
|
||
│ kubectl set image deployment/frontend frontend=IMAGE:TAG │
|
||
│ kubectl rollout status ... │
|
||
│ │
|
||
│ git tag -a "vX.Y.Z" -m "Deploy: ..." │
|
||
│ git push origin "vX.Y.Z" │
|
||
└───────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### Git Remote 구성
|
||
|
||
```
|
||
origin → Gitea (gittea.cloud-handson.com) ← 소스 코드 관리
|
||
oci → OCI Code Repository ← CI/CD 트리거용
|
||
```
|
||
|
||
두 리모트에 모두 push하여 소스와 빌드를 동기화합니다.
|
||
|
||
### build_spec.yaml 구조
|
||
|
||
```yaml
|
||
# OCI DevOps Build Pipeline 설정
|
||
version: 0.1
|
||
component: build
|
||
shell: bash
|
||
|
||
env:
|
||
variables:
|
||
REGISTRY: "icn.ocir.io/idyhsdamac8c/tasteby"
|
||
exportedVariables:
|
||
- IMAGE_TAG # 다음 stage에서 사용
|
||
- BACKEND_IMAGE
|
||
- FRONTEND_IMAGE
|
||
|
||
steps:
|
||
- Set image tag # BuildRunID + timestamp 조합
|
||
- Build backend image # backend-java/Dockerfile, ARM64
|
||
- Build frontend image # frontend/Dockerfile, ARM64
|
||
|
||
outputArtifacts:
|
||
- backend-image (DOCKER_IMAGE)
|
||
- frontend-image (DOCKER_IMAGE)
|
||
```
|
||
|
||
---
|
||
|
||
## 로컬 배포 (deploy.sh)
|
||
|
||
OCI DevOps 없이 로컬에서 직접 배포할 때 사용합니다.
|
||
|
||
```bash
|
||
# 전체 배포
|
||
./deploy.sh "초기 배포"
|
||
|
||
# 백엔드만
|
||
./deploy.sh --backend-only "API 버그 수정"
|
||
|
||
# 프론트엔드만
|
||
./deploy.sh --frontend-only "UI 개선"
|
||
|
||
# 드라이런
|
||
./deploy.sh --dry-run "테스트"
|
||
```
|
||
|
||
**deploy.sh 동작:**
|
||
1. 최신 git tag에서 다음 버전 계산 (v0.1.X → v0.1.X+1)
|
||
2. Docker build (ARM64) + OCIR push
|
||
3. `kubectl set image` → rollout 대기
|
||
4. git tag 생성 + push
|
||
|
||
---
|
||
|
||
## Docker 이미지 빌드
|
||
|
||
### Backend (Spring Boot)
|
||
|
||
```
|
||
eclipse-temurin:21-jdk (build)
|
||
└─ gradlew bootJar
|
||
└─ app.jar
|
||
|
||
eclipse-temurin:21-jre (runtime)
|
||
└─ java -XX:MaxRAMPercentage=75.0 -jar app.jar
|
||
└─ EXPOSE 8000
|
||
```
|
||
|
||
### Frontend (Next.js)
|
||
|
||
```
|
||
node:22-alpine (build)
|
||
└─ npm ci + npm run build
|
||
└─ NEXT_PUBLIC_* 빌드 시 주입 (build args)
|
||
|
||
node:22-alpine (runtime)
|
||
└─ .next/standalone + .next/static + public/
|
||
└─ node server.js
|
||
└─ EXPOSE 3001
|
||
```
|
||
|
||
---
|
||
|
||
## K8s 리소스 구성
|
||
|
||
### 파일 구조
|
||
|
||
```
|
||
k8s/
|
||
├── namespace.yaml # tasteby namespace
|
||
├── configmap.yaml # 비밀이 아닌 설정
|
||
├── secrets.yaml.template # 시크릿 템플릿 (실제 파일은 .gitignore)
|
||
├── redis-deployment.yaml # Redis 7 + Service
|
||
├── backend-deployment.yaml # Spring Boot + Service
|
||
├── frontend-deployment.yaml # Next.js + Service
|
||
├── ingress.yaml # Nginx Ingress + TLS
|
||
└── cert-manager/
|
||
└── cluster-issuer.yaml # Let's Encrypt ClusterIssuer
|
||
```
|
||
|
||
### 리소스 할당
|
||
|
||
| Pod | replicas | CPU req/lim | Memory req/lim |
|
||
|-----|----------|-------------|----------------|
|
||
| backend | 1 | 500m / 1 | 768Mi / 1536Mi |
|
||
| frontend | 1 | 200m / 500m | 256Mi / 512Mi |
|
||
| redis | 1 | 100m / 200m | 128Mi / 256Mi |
|
||
| ingress-controller | 1 | 100m / 200m | 128Mi / 256Mi |
|
||
| cert-manager (×3) | 1 each | 50m / 100m | 64Mi / 128Mi |
|
||
| **합계** | | **~1.2 CPU** | **~1.6GB** |
|
||
|
||
클러스터: ARM64 × 2 노드 (4 CPU / 16GB 총) → 여유 충분
|
||
|
||
### 네트워크 흐름
|
||
|
||
```
|
||
Client → NLB:443 → Ingress Controller → /api/* → backend:8000
|
||
→ /* → frontend:3001
|
||
|
||
backend → redis:6379 (K8s Service DNS, 클러스터 내부)
|
||
backend → Oracle ADB (mTLS, Wallet Volume Mount)
|
||
backend → OCI GenAI (OCI SDK, oci-config Volume Mount)
|
||
backend → Google APIs (API Key, 환경변수)
|
||
```
|
||
|
||
### Volume Mounts (backend)
|
||
|
||
```
|
||
/etc/oracle/wallet/ ← Secret: oracle-wallet
|
||
├── cwallet.sso
|
||
├── tnsnames.ora
|
||
├── sqlnet.ora
|
||
├── keystore.jks
|
||
├── truststore.jks
|
||
└── ojdbc.properties
|
||
|
||
/root/.oci/ ← Secret: oci-config
|
||
├── config
|
||
└── oci_api_key.pem
|
||
```
|
||
|
||
---
|
||
|
||
## 환경 분리
|
||
|
||
```
|
||
┌────────────────────────────┬──────────────────────────────────────┐
|
||
│ 개발 (Local) │ 운영 (OKE) │
|
||
├────────────────────────────┼──────────────────────────────────────┤
|
||
│ backend/.env │ ConfigMap + Secret │
|
||
│ frontend/.env.local │ Dockerfile build args │
|
||
│ ~/.oci/config │ Secret: oci-config → /root/.oci/ │
|
||
│ 로컬 Wallet 디렉토리 │ Secret: oracle-wallet → /etc/oracle/ │
|
||
│ Redis: 192.168.0.147:6379 │ Redis: redis:6379 (K8s DNS) │
|
||
│ PM2로 프로세스 관리 │ K8s Deployment로 관리 │
|
||
│ nginx + certbot (SSL) │ Ingress + cert-manager (SSL) │
|
||
└────────────────────────────┴──────────────────────────────────────┘
|
||
```
|
||
|
||
**변수명이 동일**하므로 코드 변경 없이 환경만 교체 가능합니다.
|
||
자세한 환경변수 목록은 [environment-guide.md](./environment-guide.md) 참고.
|
||
|
||
---
|
||
|
||
## OCI 리소스 정보
|
||
|
||
| 항목 | 값 |
|
||
|------|-----|
|
||
| 리전 | ap-seoul-1 (Seoul) |
|
||
| OCI 프로필 | JOUNGMINKOAWS |
|
||
| OKE 클러스터 | tasteby-cluster |
|
||
| OCIR Registry | icn.ocir.io/idyhsdamac8c/tasteby |
|
||
| DevOps 프로젝트 | tasteby |
|
||
| Code Repository | tasteby (OCI DevOps SCM) |
|
||
| 도메인 | www.tasteby.net (Namecheap) |
|
||
| SSL | Let's Encrypt (cert-manager HTTP-01) |
|
||
| 노드 | ARM64 × 2대 (2 CPU / 8GB 각) |
|
||
|
||
---
|
||
|
||
## 배포 버전 관리
|
||
|
||
- 태그 형식: `v0.1.X` (patch 자동 증가)
|
||
- deploy.sh가 자동으로 git tag 생성 + push
|
||
- 태그 메시지에 배포 대상(backend/frontend)과 이미지 태그 포함
|
||
|
||
```bash
|
||
# 태그 목록 확인
|
||
git tag -l 'v*' --sort=-v:refname
|
||
|
||
# 특정 태그 상세 확인
|
||
git tag -n20 v0.1.5
|
||
|
||
# 롤백
|
||
kubectl rollout undo deployment/backend -n tasteby
|
||
```
|
||
|
||
---
|
||
|
||
## 관련 문서
|
||
|
||
- [OKE 배포 가이드](./oke-deployment-guide.md) — 인프라 설치 및 배포 절차
|
||
- [환경 관리 가이드](./environment-guide.md) — 환경변수 및 시크릿 관리
|