Merge pull request #14 from hwanny1128/feat/notification-noti_request

Feat/notification noti request
This commit is contained in:
Daewoong Jeon 2025-10-27 16:39:16 +09:00 committed by GitHub
commit 836b45a2b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
71 changed files with 9237 additions and 17037 deletions

500
.github/actions-pipeline-guide.md vendored Normal file
View File

@ -0,0 +1,500 @@
# GitHub Actions CI/CD 파이프라인 구축 가이드
## 📋 목차
1. [개요](#개요)
2. [사전 준비사항](#사전-준비사항)
3. [GitHub 저장소 환경 구성](#github-저장소-환경-구성)
4. [디렉토리 구조](#디렉토리-구조)
5. [Kustomize 구조 설명](#kustomize-구조-설명)
6. [GitHub Actions 워크플로우](#github-actions-워크플로우)
7. [배포 방법](#배포-방법)
8. [롤백 방법](#롤백-방법)
9. [SonarQube 설정](#sonarqube-설정)
10. [트러블슈팅](#트러블슈팅)
---
## 개요
HGZero 프로젝트의 백엔드 서비스를 위한 GitHub Actions 기반 CI/CD 파이프라인입니다.
### 주요 기능
- ✅ Gradle 기반 빌드 및 테스트
- ✅ SonarQube 코드 품질 분석 (선택적)
- ✅ Azure Container Registry에 Docker 이미지 빌드 및 푸시
- ✅ Kustomize를 사용한 환경별(dev/staging/prod) 배포
- ✅ AKS 클러스터 자동 배포
### 지원 서비스
- **user**: 사용자 관리 서비스
- **meeting**: 회의 관리 서비스
- **stt**: 음성 인식 서비스
- **ai**: AI 처리 서비스
- **notification**: 알림 서비스
---
## 사전 준비사항
### 1. 프로젝트 정보
- **시스템명**: hgzero
- **ACR 이름**: acrdigitalgarage02
- **리소스 그룹**: rg-digitalgarage-02
- **AKS 클러스터**: aks-digitalgarage-02
- **네임스페이스**: hgzero
- **JDK 버전**: 21
### 2. 필수 도구
- Git
- kubectl
- Azure CLI
- Kustomize (자동 설치됨)
---
## GitHub 저장소 환경 구성
### 1. Repository Secrets 설정
`Repository Settings > Secrets and variables > Actions > Repository secrets`에 다음 항목을 등록하세요:
#### Azure 인증 정보
```json
AZURE_CREDENTIALS:
{
"clientId": "{클라이언트ID}",
"clientSecret": "{클라이언트시크릿}",
"subscriptionId": "{구독ID}",
"tenantId": "{테넌트ID}"
}
```
**예시:**
```json
{
"clientId": "5e4b5b41-7208-48b7-b821-d6d5acf50ecf",
"clientSecret": "ldu8Q~GQEzFYU.dJX7_QsahR7n7C2xqkIM6hqbV8",
"subscriptionId": "2513dd36-7978-48e3-9a7c-b221d4874f66",
"tenantId": "4f0a3bfd-1156-4cce-8dc2-a049a13dba23"
}
```
#### ACR Credentials
ACR Credential을 확인하려면:
```bash
az acr credential show --name acrdigitalgarage02
```
등록할 Secrets:
```
ACR_USERNAME: acrdigitalgarage02
ACR_PASSWORD: {ACR 패스워드}
```
#### SonarQube 설정
**SONAR_HOST_URL 확인:**
```bash
kubectl get svc -n sonarqube
```
출력된 External IP를 사용하여 `http://{External IP}` 형식으로 설정
**SONAR_TOKEN 생성:**
1. SonarQube에 로그인 (기본: admin/admin)
2. 우측 상단 'Administrator' > My Account 클릭
3. Security 탭 선택 후 토큰 생성
등록할 Secrets:
```
SONAR_TOKEN: {SonarQube 토큰}
SONAR_HOST_URL: http://{External IP}
```
#### Docker Hub (Rate Limit 해결용)
**패스워드 생성:**
1. [Docker Hub](https://hub.docker.com) 로그인
2. 우측 상단 프로필 아이콘 > Account Settings
3. 좌측 메뉴 'Personal Access Tokens' 클릭하여 생성
등록할 Secrets:
```
DOCKERHUB_USERNAME: {Docker Hub 사용자명}
DOCKERHUB_PASSWORD: {Docker Hub 패스워드 또는 토큰}
```
### 2. Repository Variables 설정
`Repository Settings > Secrets and variables > Actions > Variables > Repository variables`에 등록:
```
ENVIRONMENT: dev
SKIP_SONARQUBE: true
```
---
## 디렉토리 구조
```
.github/
├── workflows/
│ └── backend-cicd.yaml # GitHub Actions 워크플로우
├── kustomize/
│ ├── base/ # 기본 Kubernetes 매니페스트
│ │ ├── common/ # 공통 리소스
│ │ │ ├── cm-common.yaml
│ │ │ ├── secret-common.yaml
│ │ │ ├── secret-imagepull.yaml
│ │ │ └── ingress.yaml
│ │ ├── user/ # User 서비스
│ │ │ ├── deployment.yaml
│ │ │ ├── service.yaml
│ │ │ └── secret-user.yaml
│ │ ├── meeting/ # Meeting 서비스
│ │ ├── stt/ # STT 서비스
│ │ ├── ai/ # AI 서비스
│ │ ├── notification/ # Notification 서비스
│ │ └── kustomization.yaml
│ └── overlays/ # 환경별 오버레이
│ ├── dev/ # 개발 환경
│ │ ├── kustomization.yaml
│ │ ├── cm-common-patch.yaml
│ │ ├── secret-common-patch.yaml
│ │ ├── ingress-patch.yaml
│ │ ├── deployment-{service}-patch.yaml
│ │ └── secret-{service}-patch.yaml
│ ├── staging/ # 스테이징 환경
│ └── prod/ # 프로덕션 환경
├── config/ # 환경별 설정
│ ├── deploy_env_vars_dev
│ ├── deploy_env_vars_staging
│ └── deploy_env_vars_prod
└── scripts/
└── deploy-actions.sh # 수동 배포 스크립트
```
---
## Kustomize 구조 설명
### Base 구조
Base는 모든 환경에서 공통으로 사용되는 기본 매니페스트입니다.
**주요 리소스:**
- **ConfigMap (cm-common)**: 환경 변수, 프로파일 설정
- **Secret (secret-common)**: JWT 시크릿, Redis 패스워드
- **Ingress**: API 라우팅 규칙
- **Deployment**: 각 서비스별 배포 설정
- **Service**: 각 서비스별 ClusterIP 서비스
- **Secret**: 각 서비스별 데이터베이스 연결 정보
### Overlay 구조
각 환경(dev/staging/prod)별로 Base를 오버라이드합니다.
#### DEV 환경
- **Replicas**: 1
- **Resources**: CPU 256m-1024m, Memory 256Mi-1024Mi
- **Profile**: dev
- **DDL**: update
- **Log Level**: DEBUG
- **Image Tag**: dev-{timestamp}
#### STAGING 환경
- **Replicas**: 2
- **Resources**: CPU 512m-2048m, Memory 512Mi-2048Mi
- **Profile**: staging
- **DDL**: validate
- **Log Level**: INFO
- **Image Tag**: staging-{timestamp}
- **SSL**: Enabled
#### PROD 환경
- **Replicas**: 3
- **Resources**: CPU 1024m-4096m, Memory 1024Mi-4096Mi
- **Profile**: prod
- **DDL**: validate
- **Log Level**: WARN
- **JWT Expiration**: 짧게 설정 (보안 강화)
- **Image Tag**: prod-{timestamp}
- **SSL**: Enabled
---
## GitHub Actions 워크플로우
### 트리거 조건
1. **Push 이벤트**:
- 브랜치: `main`, `develop`
- 경로: 서비스 코드 변경 시 (`user/**`, `meeting/**` 등)
2. **Pull Request**:
- 대상 브랜치: `main`
3. **수동 실행 (workflow_dispatch)**:
- Environment 선택: dev/staging/prod
- SonarQube 분석 스킵 선택: true/false
### 워크플로우 단계
#### 1. Build Job
1. 소스코드 체크아웃
2. JDK 21 설정
3. 환경 결정 (input 또는 기본값 dev)
4. Gradle 빌드 (테스트 제외)
5. SonarQube 분석 (선택적)
6. 빌드 아티팩트 업로드
7. 이미지 태그 생성 (타임스탬프 기반)
#### 2. Release Job
1. 빌드 아티팩트 다운로드
2. Docker Buildx 설정
3. Docker Hub 로그인 (Rate Limit 방지)
4. ACR 로그인
5. 각 서비스별 Docker 이미지 빌드 및 푸시
#### 3. Deploy Job
1. Azure CLI 설치 및 로그인
2. kubectl 설정
3. AKS Credentials 가져오기
4. 네임스페이스 생성
5. Kustomize 설치
6. 이미지 태그 업데이트
7. 매니페스트 적용
8. Deployment Ready 대기
---
## 배포 방법
### 1. 자동 배포 (Push/PR)
코드를 `main` 또는 `develop` 브랜치에 push하면 자동으로 dev 환경에 배포됩니다.
```bash
git add .
git commit -m "feat: 새로운 기능 추가"
git push origin develop
```
### 2. 수동 배포 (GitHub Actions UI)
1. GitHub Repository > Actions 탭 이동
2. "Backend Services CI/CD" 워크플로우 선택
3. "Run workflow" 버튼 클릭
4. 환경 선택 (dev/staging/prod)
5. SonarQube 분석 스킵 여부 선택
6. "Run workflow" 실행
### 3. 로컬에서 수동 배포
```bash
# 스크립트 실행 권한 확인
chmod +x .github/scripts/deploy-actions.sh
# DEV 환경에 배포 (기본)
./.github/scripts/deploy-actions.sh dev latest
# STAGING 환경에 특정 이미지 태그로 배포
./.github/scripts/deploy-actions.sh staging 20250127120000
# PROD 환경에 배포
./.github/scripts/deploy-actions.sh prod 20250127120000
```
---
## 롤백 방법
### 1. GitHub Actions를 통한 롤백
1. GitHub > Actions > 성공한 이전 워크플로우 선택
2. "Re-run all jobs" 클릭
3. 이전 버전으로 재배포됨
### 2. kubectl을 이용한 롤백
```bash
# 특정 Revision으로 롤백
kubectl rollout undo deployment/user -n hgzero --to-revision=2
# 이전 버전으로 롤백
kubectl rollout undo deployment/user -n hgzero
# 롤백 상태 확인
kubectl rollout status deployment/user -n hgzero
# Rollout 히스토리 확인
kubectl rollout history deployment/user -n hgzero
```
### 3. 수동 스크립트를 이용한 롤백
```bash
# 이전 안정 버전의 이미지 태그로 배포
./.github/scripts/deploy-actions.sh dev 20250126110000
```
---
## SonarQube 설정
### 프로젝트 생성
각 서비스별로 SonarQube 프로젝트를 생성하세요:
- hgzero-user-dev
- hgzero-meeting-dev
- hgzero-stt-dev
- hgzero-ai-dev
- hgzero-notification-dev
### Quality Gate 설정
기본 Quality Gate 설정:
- **Coverage**: >= 80%
- **Duplicated Lines**: <= 3%
- **Maintainability Rating**: <= A
- **Reliability Rating**: <= A
- **Security Rating**: <= A
### Gradle 설정 (이미 구성됨)
```gradle
// build.gradle
plugins {
id 'org.sonarqube' version '4.0.0.2929'
id 'jacoco'
}
sonarqube {
properties {
property "sonar.projectKey", "hgzero-${project.name}"
property "sonar.projectName", "hgzero-${project.name}"
}
}
jacocoTestReport {
reports {
xml.enabled true
}
}
```
---
## 트러블슈팅
### 1. 이미지 Pull 실패
**증상**: `ImagePullBackOff` 또는 `ErrImagePull`
**해결 방법**:
```bash
# ACR 로그인 테스트
az acr login --name acrdigitalgarage02
# Image Pull Secret 재생성
kubectl delete secret acr-secret -n hgzero
kubectl create secret docker-registry acr-secret \
--docker-server=acrdigitalgarage02.azurecr.io \
--docker-username=acrdigitalgarage02 \
--docker-password={ACR_PASSWORD} \
-n hgzero
```
### 2. Deployment 타임아웃
**증상**: `deployment "user" exceeded its progress deadline`
**해결 방법**:
```bash
# Pod 상태 확인
kubectl get pods -n hgzero
# Pod 로그 확인
kubectl logs -n hgzero {pod-name}
# Events 확인
kubectl describe pod -n hgzero {pod-name}
```
### 3. Health Check 실패
**증상**: Deployment가 Ready 상태로 전환되지 않음
**해결 방법**:
```bash
# Actuator health 엔드포인트 확인
kubectl exec -n hgzero {pod-name} -- curl http://localhost:8080/actuator/health
# 애플리케이션 로그 확인
kubectl logs -n hgzero {pod-name} -f
```
### 4. Kustomize 빌드 오류
**증상**: `kustomize build` 실패
**해결 방법**:
```bash
# 로컬에서 Kustomize 검증
kubectl kustomize .github/kustomize/overlays/dev
# YAML 문법 검증
yamllint .github/kustomize/overlays/dev/*.yaml
```
### 5. SonarQube 연결 실패
**증상**: SonarQube Analysis 단계에서 연결 오류
**해결 방법**:
1. SONAR_HOST_URL이 올바른지 확인
2. SONAR_TOKEN이 유효한지 확인
3. SonarQube 서비스 상태 확인:
```bash
kubectl get pods -n sonarqube
kubectl logs -n sonarqube {sonarqube-pod}
```
### 6. 환경 변수 로드 실패
**증상**: 환경 설정 파일을 찾을 수 없음
**해결 방법**:
```bash
# 파일 존재 확인
ls -la .github/config/
# 파일 내용 확인
cat .github/config/deploy_env_vars_dev
```
---
## 참고 자료
- [Kustomize 공식 문서](https://kustomize.io/)
- [GitHub Actions 문서](https://docs.github.com/en/actions)
- [Azure Container Registry 문서](https://docs.microsoft.com/en-us/azure/container-registry/)
- [AKS 문서](https://docs.microsoft.com/en-us/azure/aks/)
- [SonarQube 문서](https://docs.sonarqube.org/)
---
## 문의 및 지원
문제가 발생하거나 질문이 있으시면:
1. GitHub Issues에 등록
2. DevOps 팀에 문의 (송주영)
3. Slack #devops 채널
---
**작성일**: 2025-01-27
**작성자**: DevOps Team (주영)
**버전**: 1.0.0

3
.github/config/deploy_env_vars_dev vendored Normal file
View File

@ -0,0 +1,3 @@
# dev Environment Configuration
resource_group=rg-digitalgarage-02
cluster_name=aks-digitalgarage-02

3
.github/config/deploy_env_vars_prod vendored Normal file
View File

@ -0,0 +1,3 @@
# prod Environment Configuration
resource_group=rg-digitalgarage-02
cluster_name=aks-digitalgarage-02

View File

@ -0,0 +1,3 @@
# staging Environment Configuration
resource_group=rg-digitalgarage-02
cluster_name=aks-digitalgarage-02

View File

@ -0,0 +1,66 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai
labels:
app: ai
spec:
replicas: 1
selector:
matchLabels:
app: ai
template:
metadata:
labels:
app: ai
spec:
containers:
- name: ai
image: acrdigitalgarage02.azurecr.io/hgzero/ai:latest
ports:
- containerPort: 8080
protocol: TCP
envFrom:
- configMapRef:
name: cm-common
- secretRef:
name: secret-common
env:
- name: DB_URL
valueFrom:
secretKeyRef:
name: secret-ai
key: DB_URL
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: secret-ai
key: DB_USERNAME
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: secret-ai
key: DB_PASSWORD
resources:
requests:
cpu: 256m
memory: 256Mi
limits:
cpu: 1024m
memory: 1024Mi
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: secret-ai
labels:
app: ai
type: Opaque
stringData:
DB_URL: "jdbc:postgresql://postgres-service:5432/aidb"
DB_USERNAME: "aiuser"
DB_PASSWORD: "aipass123"

15
.github/kustomize/base/ai/service.yaml vendored Normal file
View File

@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: ai
labels:
app: ai
spec:
type: ClusterIP
ports:
- port: 8080
targetPort: 8080
protocol: TCP
name: http
selector:
app: ai

View File

@ -0,0 +1,25 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-common
data:
# Spring Profiles
SPRING_PROFILES_ACTIVE: "dev"
# Database Configuration
DDL_AUTO: "update"
SHOW_SQL: "true"
# JWT Configuration
JWT_ACCESS_TOKEN_EXPIRATION: "3600000" # 1 hour
JWT_REFRESH_TOKEN_EXPIRATION: "86400000" # 24 hours
# Logging Configuration
LOG_LEVEL: "INFO"
# Application Configuration
SERVER_PORT: "8080"
# Redis Configuration
REDIS_HOST: "redis-service"
REDIS_PORT: "6379"

View File

@ -0,0 +1,48 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hgzero
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
ingressClassName: nginx
rules:
- host: hgzero-api.20.214.196.128.nip.io
http:
paths:
- path: /api/users
pathType: Prefix
backend:
service:
name: user
port:
number: 8080
- path: /api/meetings
pathType: Prefix
backend:
service:
name: meeting
port:
number: 8080
- path: /api/stt
pathType: Prefix
backend:
service:
name: stt
port:
number: 8080
- path: /api/ai
pathType: Prefix
backend:
service:
name: ai
port:
number: 8080
- path: /api/notifications
pathType: Prefix
backend:
service:
name: notification
port:
number: 8080

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: secret-common
type: Opaque
stringData:
# JWT Secret Key (Base64 encoded in production)
JWT_SECRET_KEY: "hgzero-jwt-secret-key-change-in-production"
# Redis Password
REDIS_PASSWORD: "redis-password-change-in-production"

View File

@ -0,0 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
name: acr-secret
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: e30K

View File

@ -0,0 +1,49 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
metadata:
name: hgzero-base
resources:
# Common resources
- common/cm-common.yaml
- common/secret-common.yaml
- common/secret-imagepull.yaml
- common/ingress.yaml
# User service
- user/deployment.yaml
- user/service.yaml
- user/secret-user.yaml
# Meeting service
- meeting/deployment.yaml
- meeting/service.yaml
- meeting/secret-meeting.yaml
# STT service
- stt/deployment.yaml
- stt/service.yaml
- stt/secret-stt.yaml
# AI service
- ai/deployment.yaml
- ai/service.yaml
- ai/secret-ai.yaml
# Notification service
- notification/deployment.yaml
- notification/service.yaml
- notification/secret-notification.yaml
images:
- name: acrdigitalgarage02.azurecr.io/hgzero/user
newTag: latest
- name: acrdigitalgarage02.azurecr.io/hgzero/meeting
newTag: latest
- name: acrdigitalgarage02.azurecr.io/hgzero/stt
newTag: latest
- name: acrdigitalgarage02.azurecr.io/hgzero/ai
newTag: latest
- name: acrdigitalgarage02.azurecr.io/hgzero/notification
newTag: latest

View File

@ -0,0 +1,66 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: meeting
labels:
app: meeting
spec:
replicas: 1
selector:
matchLabels:
app: meeting
template:
metadata:
labels:
app: meeting
spec:
containers:
- name: meeting
image: acrdigitalgarage02.azurecr.io/hgzero/meeting:latest
ports:
- containerPort: 8080
protocol: TCP
envFrom:
- configMapRef:
name: cm-common
- secretRef:
name: secret-common
env:
- name: DB_URL
valueFrom:
secretKeyRef:
name: secret-meeting
key: DB_URL
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: secret-meeting
key: DB_USERNAME
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: secret-meeting
key: DB_PASSWORD
resources:
requests:
cpu: "256m"
memory: "256Mi"
limits:
cpu: "1024m"
memory: "1024Mi"
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3

View File

@ -0,0 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: secret-meeting
type: Opaque
stringData:
# Meeting Service Database Configuration (Development)
DB_URL: "jdbc:postgresql://postgres-meeting:5432/meeting"
DB_USERNAME: "meeting_user"
DB_PASSWORD: "meeting_password"

View File

@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: meeting
labels:
app: meeting
spec:
type: ClusterIP
selector:
app: meeting
ports:
- port: 8080
targetPort: 8080
protocol: TCP
name: http

View File

@ -0,0 +1,68 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: notification
labels:
app: notification
system: hgzero
spec:
replicas: 1
selector:
matchLabels:
app: notification
template:
metadata:
labels:
app: notification
system: hgzero
spec:
containers:
- name: notification
image: acrdigitalgarage02.azurecr.io/hgzero/notification:latest
ports:
- containerPort: 8080
protocol: TCP
envFrom:
- configMapRef:
name: cm-common
- secretRef:
name: secret-common
env:
- name: DB_URL
valueFrom:
secretKeyRef:
name: secret-notification
key: DB_URL
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: secret-notification
key: DB_USERNAME
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: secret-notification
key: DB_PASSWORD
resources:
requests:
cpu: "256m"
memory: "256Mi"
limits:
cpu: "1024m"
memory: "1024Mi"
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3

View File

@ -0,0 +1,12 @@
apiVersion: v1
kind: Secret
metadata:
name: secret-notification
labels:
app: notification
system: hgzero
type: Opaque
stringData:
DB_URL: "jdbc:postgresql://postgres-service:5432/notification_db"
DB_USERNAME: "notification_user"
DB_PASSWORD: "notification_pass"

View File

@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: notification
labels:
app: notification
system: hgzero
spec:
type: ClusterIP
selector:
app: notification
ports:
- port: 8080
targetPort: 8080
protocol: TCP
name: http

View File

@ -0,0 +1,66 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: stt
labels:
app: stt
spec:
replicas: 1
selector:
matchLabels:
app: stt
template:
metadata:
labels:
app: stt
spec:
containers:
- name: stt
image: acrdigitalgarage02.azurecr.io/hgzero/stt:latest
ports:
- containerPort: 8080
protocol: TCP
envFrom:
- configMapRef:
name: cm-common
- secretRef:
name: secret-common
env:
- name: DB_URL
valueFrom:
secretKeyRef:
name: secret-stt
key: DB_URL
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: secret-stt
key: DB_USERNAME
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: secret-stt
key: DB_PASSWORD
resources:
requests:
cpu: 256m
memory: 256Mi
limits:
cpu: 1024m
memory: 1024Mi
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 20
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3

View File

@ -0,0 +1,9 @@
apiVersion: v1
kind: Secret
metadata:
name: secret-stt
type: Opaque
stringData:
DB_URL: "jdbc:postgresql://postgres-service:5432/sttdb"
DB_USERNAME: "sttuser"
DB_PASSWORD: "sttpass"

15
.github/kustomize/base/stt/service.yaml vendored Normal file
View File

@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: stt
labels:
app: stt
spec:
type: ClusterIP
selector:
app: stt
ports:
- port: 8080
targetPort: 8080
protocol: TCP
name: http

View File

@ -0,0 +1,66 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: user
labels:
app: user
spec:
replicas: 1
selector:
matchLabels:
app: user
template:
metadata:
labels:
app: user
spec:
containers:
- name: user
image: acrdigitalgarage02.azurecr.io/hgzero/user:latest
ports:
- containerPort: 8080
protocol: TCP
envFrom:
- configMapRef:
name: cm-common
- secretRef:
name: secret-common
env:
- name: DB_URL
valueFrom:
secretKeyRef:
name: secret-user
key: DB_URL
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: secret-user
key: DB_USERNAME
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: secret-user
key: DB_PASSWORD
resources:
requests:
cpu: "256m"
memory: "256Mi"
limits:
cpu: "1024m"
memory: "1024Mi"
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: secret-user
labels:
app: user
type: Opaque
stringData:
DB_URL: "jdbc:mysql://mysql-user:3306/userdb?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true"
DB_USERNAME: "user"
DB_PASSWORD: "user1234"

View File

@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: user
labels:
app: user
spec:
type: ClusterIP
selector:
app: user
ports:
- port: 8080
targetPort: 8080
protocol: TCP
name: http

View File

@ -0,0 +1,18 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-common
data:
# Spring Profiles
SPRING_PROFILES_ACTIVE: "dev"
# Database Configuration
DDL_AUTO: "update"
SHOW_SQL: "true"
# JWT Configuration
JWT_ACCESS_TOKEN_EXPIRATION: "3600000" # 1 hour
JWT_REFRESH_TOKEN_EXPIRATION: "86400000" # 24 hours
# Logging Configuration
LOG_LEVEL: "DEBUG"

View File

@ -0,0 +1,17 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai
spec:
replicas: 1
template:
spec:
containers:
- name: ai
resources:
requests:
cpu: "256m"
memory: "256Mi"
limits:
cpu: "1024m"
memory: "1024Mi"

View File

@ -0,0 +1,17 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: meeting
spec:
replicas: 1
template:
spec:
containers:
- name: meeting
resources:
requests:
cpu: "256m"
memory: "256Mi"
limits:
cpu: "1024m"
memory: "1024Mi"

View File

@ -0,0 +1,17 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: notification
spec:
replicas: 1
template:
spec:
containers:
- name: notification
resources:
requests:
cpu: "256m"
memory: "256Mi"
limits:
cpu: "1024m"
memory: "1024Mi"

View File

@ -0,0 +1,17 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: stt
spec:
replicas: 1
template:
spec:
containers:
- name: stt
resources:
requests:
cpu: "256m"
memory: "256Mi"
limits:
cpu: "1024m"
memory: "1024Mi"

View File

@ -0,0 +1,17 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: user
spec:
replicas: 1
template:
spec:
containers:
- name: user
resources:
requests:
cpu: "256m"
memory: "256Mi"
limits:
cpu: "1024m"
memory: "1024Mi"

View File

@ -0,0 +1,48 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hgzero
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
ingressClassName: nginx
rules:
- host: hgzero-api.20.214.196.128.nip.io
http:
paths:
- path: /api/users
pathType: Prefix
backend:
service:
name: user
port:
number: 8080
- path: /api/meetings
pathType: Prefix
backend:
service:
name: meeting
port:
number: 8080
- path: /api/stt
pathType: Prefix
backend:
service:
name: stt
port:
number: 8080
- path: /api/ai
pathType: Prefix
backend:
service:
name: ai
port:
number: 8080
- path: /api/notifications
pathType: Prefix
backend:
service:
name: notification
port:
number: 8080

View File

@ -0,0 +1,84 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: hgzero
resources:
- ../../base
patches:
# Common patches
- path: cm-common-patch.yaml
target:
kind: ConfigMap
name: cm-common
- path: secret-common-patch.yaml
target:
kind: Secret
name: secret-common
- path: ingress-patch.yaml
target:
kind: Ingress
name: hgzero
# User service patches
- path: deployment-user-patch.yaml
target:
kind: Deployment
name: user
- path: secret-user-patch.yaml
target:
kind: Secret
name: secret-user
# Meeting service patches
- path: deployment-meeting-patch.yaml
target:
kind: Deployment
name: meeting
- path: secret-meeting-patch.yaml
target:
kind: Secret
name: secret-meeting
# STT service patches
- path: deployment-stt-patch.yaml
target:
kind: Deployment
name: stt
- path: secret-stt-patch.yaml
target:
kind: Secret
name: secret-stt
# AI service patches
- path: deployment-ai-patch.yaml
target:
kind: Deployment
name: ai
- path: secret-ai-patch.yaml
target:
kind: Secret
name: secret-ai
# Notification service patches
- path: deployment-notification-patch.yaml
target:
kind: Deployment
name: notification
- path: secret-notification-patch.yaml
target:
kind: Secret
name: secret-notification
images:
- name: acrdigitalgarage02.azurecr.io/hgzero/user
newTag: dev-latest
- name: acrdigitalgarage02.azurecr.io/hgzero/meeting
newTag: dev-latest
- name: acrdigitalgarage02.azurecr.io/hgzero/stt
newTag: dev-latest
- name: acrdigitalgarage02.azurecr.io/hgzero/ai
newTag: dev-latest
- name: acrdigitalgarage02.azurecr.io/hgzero/notification
newTag: dev-latest

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: secret-ai
labels:
app: ai
type: Opaque
stringData:
DB_URL: "jdbc:postgresql://postgres-service-dev:5432/aidb_dev"
DB_USERNAME: "aiuser_dev"
DB_PASSWORD: "aipass_dev123"

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: secret-common
type: Opaque
stringData:
# JWT Secret Key (개발용)
JWT_SECRET_KEY: "hgzero-jwt-secret-key-change-in-production"
# Redis Password (개발용)
REDIS_PASSWORD: "redis-password-change-in-production"

View File

@ -0,0 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: secret-meeting
type: Opaque
stringData:
# Meeting Service Database Configuration (Development)
DB_URL: "jdbc:postgresql://postgres-meeting-dev:5432/meeting_dev"
DB_USERNAME: "meeting_dev_user"
DB_PASSWORD: "meeting_dev_password"

View File

@ -0,0 +1,12 @@
apiVersion: v1
kind: Secret
metadata:
name: secret-notification
labels:
app: notification
system: hgzero
type: Opaque
stringData:
DB_URL: "jdbc:postgresql://postgres-service-dev:5432/notification_db_dev"
DB_USERNAME: "notification_dev_user"
DB_PASSWORD: "notification_dev_pass"

View File

@ -0,0 +1,9 @@
apiVersion: v1
kind: Secret
metadata:
name: secret-stt
type: Opaque
stringData:
DB_URL: "jdbc:postgresql://postgres-service-dev:5432/sttdb_dev"
DB_USERNAME: "sttuser_dev"
DB_PASSWORD: "sttpass_dev"

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: secret-user
labels:
app: user
type: Opaque
stringData:
DB_URL: "jdbc:mysql://mysql-user-dev:3306/userdb_dev?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true"
DB_USERNAME: "user_dev"
DB_PASSWORD: "user_dev1234"

View File

@ -0,0 +1,14 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: common-config
namespace: hgzero
data:
SPRING_PROFILES_ACTIVE: "prod"
DDL_AUTO: "validate"
LOG_LEVEL: "WARN"
JWT_ACCESS_TOKEN_EXPIRATION: "1800000"
JWT_REFRESH_TOKEN_EXPIRATION: "43200000"
REDIS_HOST: "redis-svc.hgzero.svc.cluster.local"
REDIS_PORT: "6379"
KAFKA_BOOTSTRAP_SERVERS: "kafka-svc.hgzero.svc.cluster.local:9092"

View File

@ -0,0 +1,18 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-deploy
namespace: hgzero
spec:
replicas: 3
template:
spec:
containers:
- name: ai-container
resources:
requests:
cpu: "1024m"
memory: "1024Mi"
limits:
cpu: "4096m"
memory: "4096Mi"

View File

@ -0,0 +1,18 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: meeting-deploy
namespace: hgzero
spec:
replicas: 3
template:
spec:
containers:
- name: meeting-container
resources:
requests:
cpu: "1024m"
memory: "1024Mi"
limits:
cpu: "4096m"
memory: "4096Mi"

View File

@ -0,0 +1,18 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: notification-deploy
namespace: hgzero
spec:
replicas: 3
template:
spec:
containers:
- name: notification-container
resources:
requests:
cpu: "1024m"
memory: "1024Mi"
limits:
cpu: "4096m"
memory: "4096Mi"

View File

@ -0,0 +1,18 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: stt-deploy
namespace: hgzero
spec:
replicas: 3
template:
spec:
containers:
- name: stt-container
resources:
requests:
cpu: "1024m"
memory: "1024Mi"
limits:
cpu: "4096m"
memory: "4096Mi"

View File

@ -0,0 +1,18 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-deploy
namespace: hgzero
spec:
replicas: 3
template:
spec:
containers:
- name: user-container
resources:
requests:
cpu: "1024m"
memory: "1024Mi"
limits:
cpu: "4096m"
memory: "4096Mi"

View File

@ -0,0 +1,49 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hgzero-ingress
namespace: hgzero
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
rules:
- host: hgzero-api.example.com
http:
paths:
- path: /user(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: user-svc
port:
number: 8080
- path: /meeting(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: meeting-svc
port:
number: 8081
- path: /stt(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: stt-svc
port:
number: 8082
- path: /ai(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: ai-svc
port:
number: 8083
- path: /notification(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: notification-svc
port:
number: 8084

View File

@ -0,0 +1,84 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: hgzero
bases:
- ../../base
patches:
# Common patches
- path: cm-common-patch.yaml
target:
kind: ConfigMap
name: common-config
- path: secret-common-patch.yaml
target:
kind: Secret
name: common-secret
- path: ingress-patch.yaml
target:
kind: Ingress
name: hgzero-ingress
# User service patches
- path: deployment-user-patch.yaml
target:
kind: Deployment
name: user-deploy
- path: secret-user-patch.yaml
target:
kind: Secret
name: user-secret
# Meeting service patches
- path: deployment-meeting-patch.yaml
target:
kind: Deployment
name: meeting-deploy
- path: secret-meeting-patch.yaml
target:
kind: Secret
name: meeting-secret
# STT service patches
- path: deployment-stt-patch.yaml
target:
kind: Deployment
name: stt-deploy
- path: secret-stt-patch.yaml
target:
kind: Secret
name: stt-secret
# AI service patches
- path: deployment-ai-patch.yaml
target:
kind: Deployment
name: ai-deploy
- path: secret-ai-patch.yaml
target:
kind: Secret
name: ai-secret
# Notification service patches
- path: deployment-notification-patch.yaml
target:
kind: Deployment
name: notification-deploy
- path: secret-notification-patch.yaml
target:
kind: Secret
name: notification-secret
images:
- name: user-service
newTag: prod-latest
- name: meeting-service
newTag: prod-latest
- name: stt-service
newTag: prod-latest
- name: ai-service
newTag: prod-latest
- name: notification-service
newTag: prod-latest

View File

@ -0,0 +1,9 @@
apiVersion: v1
kind: Secret
metadata:
name: ai-secret
namespace: hgzero
type: Opaque
stringData:
OPENAI_API_KEY: "your-openai-api-key"
LANGCHAIN_API_KEY: "your-langchain-api-key"

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: common-secret
namespace: hgzero
type: Opaque
stringData:
JWT_SECRET_KEY: "your-prod-secret-key-change-this-in-production"
REDIS_PASSWORD: "your-prod-redis-password"
KAFKA_USERNAME: "admin"
KAFKA_PASSWORD: "admin-secret"

View File

@ -0,0 +1,13 @@
apiVersion: v1
kind: Secret
metadata:
name: meeting-secret
namespace: hgzero
type: Opaque
stringData:
DB_URL: "jdbc:postgresql://postgres-prod:5432/meeting_prod"
DB_USERNAME: "meeting_admin"
DB_PASSWORD: "meeting_prod_password"
OPENAI_API_KEY: "your-openai-api-key"
S3_ACCESS_KEY: "your-s3-access-key"
S3_SECRET_KEY: "your-s3-secret-key"

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: notification-secret
namespace: hgzero
type: Opaque
stringData:
DB_URL: "jdbc:postgresql://postgres-prod:5432/notification_prod"
DB_USERNAME: "notification_admin"
DB_PASSWORD: "notification_prod_password"
OPENAI_API_KEY: "your-openai-api-key"

View File

@ -0,0 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: stt-secret
namespace: hgzero
type: Opaque
stringData:
OPENAI_API_KEY: "your-openai-api-key"
S3_ACCESS_KEY: "your-s3-access-key"
S3_SECRET_KEY: "your-s3-secret-key"

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: user-secret
namespace: hgzero
type: Opaque
stringData:
DB_URL: "jdbc:postgresql://postgres-prod:5432/user_prod"
DB_USERNAME: "user_admin"
DB_PASSWORD: "user_prod_password"
OPENAI_API_KEY: "your-openai-api-key"

View File

@ -0,0 +1,99 @@
# STAGING Environment Kustomize Overlay
## 개요
STAGING 환경을 위한 Kustomize overlay 설정입니다.
## 환경 설정
### 네임스페이스
- `hgzero`
### 공통 설정
- **프로파일**: staging
- **DDL 모드**: validate
- **로그 레벨**: INFO
- **Ingress 호스트**: hgzero-staging-api.example.com
- **SSL 리다이렉트**: 활성화
### 리소스 설정
- **Replicas**: 2
- **Resource Requests**:
- CPU: 512m
- Memory: 512Mi
- **Resource Limits**:
- CPU: 2048m
- Memory: 2048Mi
## 생성된 파일 목록 (총 14개)
### Common Patches (3개)
1. `cm-common-patch.yaml` - 공통 ConfigMap 패치
2. `secret-common-patch.yaml` - 공통 Secret 패치 (JWT, Redis)
3. `ingress-patch.yaml` - Ingress 패치 (호스트, SSL)
### Service-specific Patches (10개)
각 서비스(user, meeting, stt, ai, notification)별 2개 파일:
- `deployment-{서비스명}-patch.yaml` - Deployment 리소스 패치
- `secret-{서비스명}-patch.yaml` - DB 연결 정보 패치
4. `deployment-user-patch.yaml`
5. `secret-user-patch.yaml`
6. `deployment-meeting-patch.yaml`
7. `secret-meeting-patch.yaml`
8. `deployment-stt-patch.yaml`
9. `secret-stt-patch.yaml`
10. `deployment-ai-patch.yaml`
11. `secret-ai-patch.yaml`
12. `deployment-notification-patch.yaml`
13. `secret-notification-patch.yaml`
### Kustomization (1개)
14. `kustomization.yaml` - Kustomize 설정 파일
## 데이터베이스 설정
각 서비스별 STAGING 환경 DB 정보:
- **호스트**: {서비스명}-db-staging
- **포트**: 5432
- **데이터베이스명**: {서비스명}_db_staging
- **사용자명**: {서비스명}_service
- **비밀번호**: stringData로 정의 (실제 환경에서 변경 필요)
## 이미지 태그
모든 서비스: `staging-latest`
## 사용 방법
### 1. Kustomize 빌드 확인
```bash
kubectl kustomize .github/kustomize/overlays/staging
```
### 2. STAGING 환경 배포
```bash
kubectl apply -k .github/kustomize/overlays/staging
```
### 3. 배포 상태 확인
```bash
kubectl get all -n hgzero
```
### 4. Secret 업데이트 (실제 배포 시)
```bash
# Secret 파일들의 stringData를 실제 STAGING 환경 값으로 변경
vi .github/kustomize/overlays/staging/secret-common-patch.yaml
vi .github/kustomize/overlays/staging/secret-user-patch.yaml
# ... (각 서비스별 secret 파일 수정)
```
## 주의사항
1. Secret 파일들의 비밀번호는 반드시 실제 환경에 맞게 변경해야 합니다
2. Ingress 호스트명을 실제 STAGING 도메인으로 변경해야 합니다
3. DB 호스트명이 실제 STAGING 환경과 일치하는지 확인해야 합니다
4. 리소스 제한은 실제 부하 테스트 결과에 따라 조정이 필요할 수 있습니다
## 다음 단계
- PROD 환경 overlay 생성
- CI/CD 파이프라인과 통합
- Monitoring 및 Logging 설정 추가

View File

@ -0,0 +1,8 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: hgzero-common-config
data:
SPRING_PROFILES_ACTIVE: "staging"
DDL_AUTO: "validate"
LOG_LEVEL: "INFO"

View File

@ -0,0 +1,17 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-service
spec:
replicas: 2
template:
spec:
containers:
- name: ai-service
resources:
requests:
memory: "512Mi"
cpu: "512m"
limits:
memory: "2048Mi"
cpu: "2048m"

View File

@ -0,0 +1,17 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: meeting-service
spec:
replicas: 2
template:
spec:
containers:
- name: meeting-service
resources:
requests:
memory: "512Mi"
cpu: "512m"
limits:
memory: "2048Mi"
cpu: "2048m"

View File

@ -0,0 +1,17 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: notification-service
spec:
replicas: 2
template:
spec:
containers:
- name: notification-service
resources:
requests:
memory: "512Mi"
cpu: "512m"
limits:
memory: "2048Mi"
cpu: "2048m"

View File

@ -0,0 +1,17 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: stt-service
spec:
replicas: 2
template:
spec:
containers:
- name: stt-service
resources:
requests:
memory: "512Mi"
cpu: "512m"
limits:
memory: "2048Mi"
cpu: "2048m"

View File

@ -0,0 +1,17 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
replicas: 2
template:
spec:
containers:
- name: user-service
resources:
requests:
memory: "512Mi"
cpu: "512m"
limits:
memory: "2048Mi"
cpu: "2048m"

View File

@ -0,0 +1,46 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hgzero-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
rules:
- host: hgzero-staging-api.example.com
http:
paths:
- path: /api/users
pathType: Prefix
backend:
service:
name: user-service
port:
number: 8080
- path: /api/meetings
pathType: Prefix
backend:
service:
name: meeting-service
port:
number: 8080
- path: /api/stt
pathType: Prefix
backend:
service:
name: stt-service
port:
number: 8080
- path: /api/ai
pathType: Prefix
backend:
service:
name: ai-service
port:
number: 8080
- path: /api/notifications
pathType: Prefix
backend:
service:
name: notification-service
port:
number: 8080

View File

@ -0,0 +1,91 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: hgzero
resources:
- ../../base
patches:
# Common patches
- path: cm-common-patch.yaml
target:
kind: ConfigMap
name: hgzero-common-config
- path: secret-common-patch.yaml
target:
kind: Secret
name: hgzero-common-secret
- path: ingress-patch.yaml
target:
kind: Ingress
name: hgzero-ingress
# User service patches
- path: deployment-user-patch.yaml
target:
kind: Deployment
name: user-service
- path: secret-user-patch.yaml
target:
kind: Secret
name: user-service-secret
# Meeting service patches
- path: deployment-meeting-patch.yaml
target:
kind: Deployment
name: meeting-service
- path: secret-meeting-patch.yaml
target:
kind: Secret
name: meeting-service-secret
# STT service patches
- path: deployment-stt-patch.yaml
target:
kind: Deployment
name: stt-service
- path: secret-stt-patch.yaml
target:
kind: Secret
name: stt-service-secret
# AI service patches
- path: deployment-ai-patch.yaml
target:
kind: Deployment
name: ai-service
- path: secret-ai-patch.yaml
target:
kind: Secret
name: ai-service-secret
# Notification service patches
- path: deployment-notification-patch.yaml
target:
kind: Deployment
name: notification-service
- path: secret-notification-patch.yaml
target:
kind: Secret
name: notification-service-secret
images:
- name: user-service
newTag: staging-latest
- name: meeting-service
newTag: staging-latest
- name: stt-service
newTag: staging-latest
- name: ai-service
newTag: staging-latest
- name: notification-service
newTag: staging-latest

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: ai-service-secret
type: Opaque
stringData:
DB_HOST: "ai-db-staging"
DB_PORT: "5432"
DB_NAME: "ai_db_staging"
DB_USERNAME: "ai_service"
DB_PASSWORD: "your-staging-ai-db-password"

View File

@ -0,0 +1,9 @@
apiVersion: v1
kind: Secret
metadata:
name: hgzero-common-secret
type: Opaque
stringData:
JWT_SECRET: "your-staging-jwt-secret-key-here-change-in-production"
JWT_EXPIRATION: "3600000"
REDIS_PASSWORD: "your-staging-redis-password"

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: meeting-service-secret
type: Opaque
stringData:
DB_HOST: "meeting-db-staging"
DB_PORT: "5432"
DB_NAME: "meeting_db_staging"
DB_USERNAME: "meeting_service"
DB_PASSWORD: "your-staging-meeting-db-password"

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: notification-service-secret
type: Opaque
stringData:
DB_HOST: "notification-db-staging"
DB_PORT: "5432"
DB_NAME: "notification_db_staging"
DB_USERNAME: "notification_service"
DB_PASSWORD: "your-staging-notification-db-password"

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: stt-service-secret
type: Opaque
stringData:
DB_HOST: "stt-db-staging"
DB_PORT: "5432"
DB_NAME: "stt_db_staging"
DB_USERNAME: "stt_service"
DB_PASSWORD: "your-staging-stt-db-password"

View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: user-service-secret
type: Opaque
stringData:
DB_HOST: "user-db-staging"
DB_PORT: "5432"
DB_NAME: "user_db_staging"
DB_USERNAME: "user_service"
DB_PASSWORD: "your-staging-user-db-password"

69
.github/scripts/deploy-actions.sh vendored Executable file
View File

@ -0,0 +1,69 @@
#!/bin/bash
set -e
ENVIRONMENT=${1:-dev}
IMAGE_TAG=${2:-latest}
echo "🚀 Manual deployment starting..."
echo "Environment: $ENVIRONMENT"
echo "Image Tag: $IMAGE_TAG"
# Check if kustomize is installed
if ! command -v kustomize &> /dev/null; then
echo "Installing Kustomize..."
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
sudo mv kustomize /usr/local/bin/
fi
# Load environment variables from .github/config
if [[ -f ".github/config/deploy_env_vars_${ENVIRONMENT}" ]]; then
source ".github/config/deploy_env_vars_${ENVIRONMENT}"
echo "✅ Environment variables loaded for $ENVIRONMENT"
else
echo "❌ Environment configuration file not found: .github/config/deploy_env_vars_${ENVIRONMENT}"
exit 1
fi
# Create namespace
echo "📝 Creating namespace hgzero..."
kubectl create namespace hgzero --dry-run=client -o yaml | kubectl apply -f -
# 환경별 이미지 태그 업데이트 (.github/kustomize 사용)
cd .github/kustomize/overlays/${ENVIRONMENT}
echo "🔄 Updating image tags..."
# 서비스 배열 정의
services=(user meeting stt ai notification)
# 각 서비스별 이미지 태그 업데이트
for service in "${services[@]}"; do
kustomize edit set image acrdigitalgarage02.azurecr.io/hgzero/$service:${ENVIRONMENT}-${IMAGE_TAG}
done
echo "🚀 Deploying to Kubernetes..."
# 배포 실행
kubectl apply -k .
echo "⏳ Waiting for deployments to be ready..."
# 서비스별 배포 상태 확인
for service in "${services[@]}"; do
kubectl rollout status deployment/$service -n hgzero --timeout=300s || echo "⚠️ $service deployment timeout"
done
echo "🔍 Health check..."
# 각 서비스의 Health Check
for service in "${services[@]}"; do
POD=$(kubectl get pod -n hgzero -l app.kubernetes.io/name=$service -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "")
if [[ -n "$POD" ]]; then
kubectl -n hgzero exec $POD -- curl -f http://localhost:8080/actuator/health 2>/dev/null || echo "⚠️ $service health check failed"
else
echo "⚠️ $service pod not found"
fi
done
echo "📋 Service Information:"
kubectl get pods -n hgzero
kubectl get services -n hgzero
kubectl get ingress -n hgzero
echo "✅ GitHub Actions deployment completed successfully!"

276
.github/workflows/backend-cicd.yaml vendored Normal file
View File

@ -0,0 +1,276 @@
name: Backend Services CI/CD
on:
push:
branches: [ main, develop ]
paths:
- 'user/**'
- 'meeting/**'
- 'stt/**'
- 'ai/**'
- 'notification/**'
- 'common/**'
- '.github/**'
pull_request:
branches: [ main ]
workflow_dispatch:
inputs:
ENVIRONMENT:
description: 'Target environment'
required: true
default: 'dev'
type: choice
options:
- dev
- staging
- prod
SKIP_SONARQUBE:
description: 'Skip SonarQube Analysis'
required: false
default: 'true'
type: choice
options:
- 'true'
- 'false'
env:
REGISTRY: acrdigitalgarage02.azurecr.io
IMAGE_ORG: hgzero
RESOURCE_GROUP: rg-digitalgarage-02
AKS_CLUSTER: aks-digitalgarage-02
NAMESPACE: hgzero
jobs:
build:
name: Build and Test
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.set_outputs.outputs.image_tag }}
environment: ${{ steps.set_outputs.outputs.environment }}
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: '21'
distribution: 'temurin'
cache: 'gradle'
- name: Determine environment
id: determine_env
run: |
# Use input parameter or default to 'dev'
ENVIRONMENT="${{ github.event.inputs.ENVIRONMENT || 'dev' }}"
echo "environment=$ENVIRONMENT" >> $GITHUB_OUTPUT
- name: Load environment variables
id: env_vars
run: |
ENV=${{ steps.determine_env.outputs.environment }}
# Initialize variables with defaults
REGISTRY="acrdigitalgarage02.azurecr.io"
IMAGE_ORG="hgzero"
RESOURCE_GROUP="rg-digitalgarage-02"
AKS_CLUSTER="aks-digitalgarage-02"
NAMESPACE="hgzero"
# Read environment variables from .github/config file
if [[ -f ".github/config/deploy_env_vars_${ENV}" ]]; then
while IFS= read -r line || [[ -n "$line" ]]; do
# Skip comments and empty lines
[[ "$line" =~ ^#.*$ ]] && continue
[[ -z "$line" ]] && continue
# Extract key-value pairs
key=$(echo "$line" | cut -d '=' -f1)
value=$(echo "$line" | cut -d '=' -f2-)
# Override defaults if found in config
case "$key" in
"resource_group") RESOURCE_GROUP="$value" ;;
"cluster_name") AKS_CLUSTER="$value" ;;
esac
done < ".github/config/deploy_env_vars_${ENV}"
fi
# Export for other jobs
echo "REGISTRY=$REGISTRY" >> $GITHUB_ENV
echo "IMAGE_ORG=$IMAGE_ORG" >> $GITHUB_ENV
echo "RESOURCE_GROUP=$RESOURCE_GROUP" >> $GITHUB_ENV
echo "AKS_CLUSTER=$AKS_CLUSTER" >> $GITHUB_ENV
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: |
./gradlew build -x test
- name: SonarQube Analysis & Quality Gate
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
run: |
# Check if SonarQube should be skipped
SKIP_SONARQUBE="${{ github.event.inputs.SKIP_SONARQUBE || 'true' }}"
if [[ "$SKIP_SONARQUBE" == "true" ]]; then
echo "⏭️ Skipping SonarQube Analysis (SKIP_SONARQUBE=$SKIP_SONARQUBE)"
exit 0
fi
# Define services array
services=(user meeting stt ai notification)
# Run tests, coverage reports, and SonarQube analysis for each service
for service in "${services[@]}"; do
./gradlew :$service:test :$service:jacocoTestReport :$service:sonar \
-Dsonar.projectKey=hgzero-$service-${{ steps.determine_env.outputs.environment }} \
-Dsonar.projectName=hgzero-$service-${{ steps.determine_env.outputs.environment }} \
-Dsonar.host.url=$SONAR_HOST_URL \
-Dsonar.token=$SONAR_TOKEN \
-Dsonar.java.binaries=build/classes/java/main \
-Dsonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml \
-Dsonar.exclusions=**/config/**,**/entity/**,**/dto/**,**/*Application.class,**/exception/**
done
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: app-builds
path: |
user/build/libs/*.jar
meeting/build/libs/*.jar
stt/build/libs/*.jar
ai/build/libs/*.jar
notification/build/libs/*.jar
- name: Set outputs
id: set_outputs
run: |
# Generate timestamp for image tag
IMAGE_TAG=$(date +%Y%m%d%H%M%S)
echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT
echo "environment=${{ steps.determine_env.outputs.environment }}" >> $GITHUB_OUTPUT
release:
name: Build and Push Docker Images
needs: build
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: app-builds
- name: Set environment variables from build job
run: |
echo "REGISTRY=${{ env.REGISTRY }}" >> $GITHUB_ENV
echo "IMAGE_ORG=${{ env.IMAGE_ORG }}" >> $GITHUB_ENV
echo "ENVIRONMENT=${{ needs.build.outputs.environment }}" >> $GITHUB_ENV
echo "IMAGE_TAG=${{ needs.build.outputs.image_tag }}" >> $GITHUB_ENV
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub (prevent rate limit)
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Login to Azure Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.ACR_USERNAME }}
password: ${{ secrets.ACR_PASSWORD }}
- name: Build and push Docker images for all services
run: |
# Define services array
services=(user meeting stt ai notification)
# Build and push each service image
for service in "${services[@]}"; do
echo "Building and pushing $service..."
docker build \
--build-arg BUILD_LIB_DIR="$service/build/libs" \
--build-arg ARTIFACTORY_FILE="$service.jar" \
-f deployment/container/Dockerfile-backend \
-t ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/$service:${{ needs.build.outputs.environment }}-${{ needs.build.outputs.image_tag }} .
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/$service:${{ needs.build.outputs.environment }}-${{ needs.build.outputs.image_tag }}
done
deploy:
name: Deploy to Kubernetes
needs: [build, release]
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set image tag environment variable
run: |
echo "IMAGE_TAG=${{ needs.build.outputs.image_tag }}" >> $GITHUB_ENV
echo "ENVIRONMENT=${{ needs.build.outputs.environment }}" >> $GITHUB_ENV
- name: Install Azure CLI
run: |
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Setup kubectl
uses: azure/setup-kubectl@v3
- name: Get AKS Credentials
run: |
az aks get-credentials --resource-group ${{ env.RESOURCE_GROUP }} --name ${{ env.AKS_CLUSTER }} --overwrite-existing
- name: Create namespace
run: |
kubectl create namespace ${{ env.NAMESPACE }} --dry-run=client -o yaml | kubectl apply -f -
- name: Install Kustomize
run: |
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
sudo mv kustomize /usr/local/bin/
- name: Update Kustomize images and deploy
run: |
# 환경별 디렉토리로 이동
cd .github/kustomize/overlays/${{ env.ENVIRONMENT }}
# 각 서비스별 이미지 태그 업데이트
kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/user:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/meeting:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/stt:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/ai:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_ORG }}/notification:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
# 매니페스트 적용
kubectl apply -k .
- name: Wait for deployments to be ready
run: |
echo "Waiting for deployments to be ready..."
kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/user --timeout=300s || true
kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/meeting --timeout=300s || true
kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/stt --timeout=300s || true
kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/ai --timeout=300s || true
kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/notification --timeout=300s || true

File diff suppressed because it is too large Load Diff