add ci/cd

This commit is contained in:
djeon 2025-10-27 17:31:03 +09:00
parent decc4de180
commit 9adcab2048
11 changed files with 1407 additions and 0 deletions

View File

@ -0,0 +1,254 @@
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
update-manifest:
name: Update Manifest Repository
needs: [build, release]
runs-on: ubuntu-latest
steps:
- 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: Update Manifest Repository
run: |
# 매니페스트 레포지토리 클론
REPO_URL=$(echo "https://github.com/hjmoons/hgzero-manifest.git" | sed 's|https://||')
git clone https://${{ secrets.GIT_USERNAME }}:${{ secrets.GIT_PASSWORD }}@${REPO_URL} manifest-repo
cd manifest-repo
# Kustomize 설치
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
sudo mv kustomize /usr/local/bin/
# 매니페스트 업데이트
cd hgzero/kustomize/overlays/${{ env.ENVIRONMENT }}
# 각 서비스별 이미지 태그 업데이트
services="user meeting stt ai notification"
for service in $services; do
kustomize edit set image acrdigitalgarage02.azurecr.io/hgzero/$service:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
done
# Git 설정 및 푸시
cd ../../../..
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git add .
git commit -m "🚀 Update hgzero ${{ env.ENVIRONMENT }} images to ${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}"
git push origin main
echo "✅ 매니페스트 업데이트 완료. ArgoCD가 자동으로 배포합니다."

View File

@ -0,0 +1,420 @@
# HGZero 백엔드 서비스 Kubernetes 배포 가이드
## 개요
이 가이드는 HGZero 백엔드 서비스(User, Meeting, Notification)를 Azure Kubernetes Service(AKS)에 배포하는 방법을 설명합니다.
## 배포 환경
- **ACR(Azure Container Registry)**: acrdigitalgarage02
- **AKS(Azure Kubernetes Service)**: aks-digitalgarage-02
- **네임스페이스**: hgzero
- **리소스 그룹**: rg-digitalgarage-02
## 서비스 구성
### 1. User Service
- **포트**: 8080
- **이미지**: acrdigitalgarage02.azurecr.io/hgzero/user-service:latest
- **기능**: 사용자 인증 및 관리, LDAP 연동
### 2. Meeting Service
- **포트**: 8081 (HTTP), 8082 (WebSocket)
- **이미지**: acrdigitalgarage02.azurecr.io/hgzero/meeting-service:latest
- **기능**: 회의 관리, WebSocket 통신
### 3. Notification Service
- **포트**: 8082
- **이미지**: acrdigitalgarage02.azurecr.io/hgzero/notification-service:latest
- **기능**: 알림 전송, 이메일 발송
## 리소스 할당
각 서비스는 다음과 같은 리소스를 사용합니다:
- **Requests**:
- CPU: 256m
- Memory: 256Mi
- **Limits**:
- CPU: 1024m
- Memory: 1024Mi
- **Replicas**: 1 (각 서비스)
## 사전 요구사항
1. **Azure CLI 설치**
```bash
# macOS
brew install azure-cli
# Windows
# Download from https://aka.ms/installazurecliwindows
# Linux
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
```
2. **kubectl 설치**
```bash
# macOS
brew install kubectl
# Windows
# Download from https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/
# Linux
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
```
3. **Azure 로그인**
```bash
az login
```
4. **ACR 로그인**
```bash
az acr login --name acrdigitalgarage02
```
## 배포 파일 구조
```
deploy/k8s/backend/
├── namespace.yaml # 네임스페이스 정의
├── configmap.yaml # ConfigMap (Redis, Mail 설정)
├── secret-template.yaml # Secret 템플릿 (민감 정보)
├── user-service.yaml # User Service 배포 매니페스트
├── meeting-service.yaml # Meeting Service 배포 매니페스트
├── notification-service.yaml # Notification Service 배포 매니페스트
├── deploy.sh # 배포 스크립트
├── undeploy.sh # 배포 해제 스크립트
├── create-secrets.sh # Secret 생성 스크립트
└── README.md # 이 문서
```
## 배포 절차
### 1단계: AKS 클러스터 접근 설정
```bash
# AKS credentials 가져오기
az aks get-credentials \
--resource-group rg-digitalgarage-02 \
--name aks-digitalgarage-02 \
--overwrite-existing
# 클러스터 연결 확인
kubectl cluster-info
```
### 2단계: 네임스페이스 생성
```bash
kubectl apply -f namespace.yaml
```
### 3단계: ConfigMap 생성
```bash
kubectl apply -f configmap.yaml
```
### 4단계: Secret 생성
옵션 A: 대화형 스크립트 사용 (권장)
```bash
./create-secrets.sh
```
옵션 B: 직접 생성
```bash
# Database Secret
kubectl create secret generic db-secret \
--from-literal=host=<DB_HOST> \
--from-literal=username=<DB_USERNAME> \
--from-literal=password=<DB_PASSWORD> \
--namespace=hgzero
# Azure Secret
kubectl create secret generic azure-secret \
--from-literal=eventhub-connection-string=<EVENTHUB_CONN> \
--from-literal=blob-connection-string=<BLOB_CONN> \
--namespace=hgzero
# Mail Secret
kubectl create secret generic mail-secret \
--from-literal=username=<MAIL_USERNAME> \
--from-literal=password=<MAIL_PASSWORD> \
--namespace=hgzero
```
### 5단계: 서비스 배포
옵션 A: 자동 배포 스크립트 사용 (권장)
```bash
./deploy.sh
```
옵션 B: 수동 배포
```bash
# ACR 연동 설정
az aks update \
-n aks-digitalgarage-02 \
-g rg-digitalgarage-02 \
--attach-acr acrdigitalgarage02
# 서비스 배포
kubectl apply -f user-service.yaml
kubectl apply -f notification-service.yaml
kubectl apply -f meeting-service.yaml
```
### 6단계: 배포 상태 확인
```bash
# Deployment 상태 확인
kubectl get deployments -n hgzero
# Pod 상태 확인
kubectl get pods -n hgzero
# Service 확인
kubectl get services -n hgzero
# 상세 정보 확인
kubectl describe deployment user-service -n hgzero
```
## 배포 확인 및 테스트
### Pod 로그 확인
```bash
# User Service 로그
kubectl logs -f deployment/user-service -n hgzero
# Meeting Service 로그
kubectl logs -f deployment/meeting-service -n hgzero
# Notification Service 로그
kubectl logs -f deployment/notification-service -n hgzero
```
### Health Check
```bash
# User Service health check
kubectl port-forward svc/user-service 8080:8080 -n hgzero
curl http://localhost:8080/actuator/health
# Meeting Service health check
kubectl port-forward svc/meeting-service 8081:8081 -n hgzero
curl http://localhost:8081/actuator/health
# Notification Service health check
kubectl port-forward svc/notification-service 8082:8082 -n hgzero
curl http://localhost:8082/actuator/health
```
### Pod 내부 접속
```bash
# Pod 내부로 접속하여 디버깅
kubectl exec -it deployment/user-service -n hgzero -- /bin/sh
```
## 배포 해제
### 전체 서비스 삭제
```bash
./undeploy.sh
```
### 개별 서비스 삭제
```bash
kubectl delete -f user-service.yaml
kubectl delete -f meeting-service.yaml
kubectl delete -f notification-service.yaml
```
### Secret 및 ConfigMap 삭제
```bash
kubectl delete configmap redis-config mail-config -n hgzero
kubectl delete secret db-secret azure-secret mail-secret -n hgzero
```
### 네임스페이스 삭제
```bash
kubectl delete namespace hgzero
```
## 트러블슈팅
### Pod가 시작되지 않는 경우
```bash
# Pod 상태 확인
kubectl get pods -n hgzero
# Pod 상세 정보 확인
kubectl describe pod <pod-name> -n hgzero
# Pod 로그 확인
kubectl logs <pod-name> -n hgzero
# 이전 컨테이너 로그 확인 (재시작된 경우)
kubectl logs <pod-name> -n hgzero --previous
```
### 이미지 Pull 오류
```bash
# ACR 연동 상태 확인
az aks show -n aks-digitalgarage-02 -g rg-digitalgarage-02 --query "servicePrincipalProfile"
# ACR 재연동
az aks update -n aks-digitalgarage-02 -g rg-digitalgarage-02 --attach-acr acrdigitalgarage02
# ImagePullSecret 확인
kubectl get serviceaccount default -n hgzero -o yaml
```
### Secret 관련 오류
```bash
# Secret 존재 확인
kubectl get secrets -n hgzero
# Secret 내용 확인
kubectl get secret db-secret -n hgzero -o yaml
# Secret 재생성
kubectl delete secret db-secret -n hgzero
./create-secrets.sh
```
### 네트워크 연결 문제
```bash
# Service Endpoint 확인
kubectl get endpoints -n hgzero
# DNS 확인
kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup user-service.hgzero.svc.cluster.local
# 네트워크 정책 확인
kubectl get networkpolicies -n hgzero
```
### 리소스 부족 문제
```bash
# 노드 리소스 사용량 확인
kubectl top nodes
# Pod 리소스 사용량 확인
kubectl top pods -n hgzero
# 리소스 제한 조정 (필요 시)
kubectl edit deployment user-service -n hgzero
```
## 업데이트 및 롤링 배포
### 이미지 업데이트
```bash
# 새 이미지 태그로 업데이트
kubectl set image deployment/user-service \
user-service=acrdigitalgarage02.azurecr.io/hgzero/user-service:v2.0.0 \
-n hgzero
# 롤아웃 상태 확인
kubectl rollout status deployment/user-service -n hgzero
# 롤아웃 히스토리 확인
kubectl rollout history deployment/user-service -n hgzero
```
### 롤백
```bash
# 이전 버전으로 롤백
kubectl rollout undo deployment/user-service -n hgzero
# 특정 revision으로 롤백
kubectl rollout undo deployment/user-service --to-revision=2 -n hgzero
```
## 모니터링
### Kubernetes Dashboard
```bash
# Dashboard 접근
az aks browse -n aks-digitalgarage-02 -g rg-digitalgarage-02
```
### 리소스 모니터링
```bash
# 실시간 리소스 사용량 모니터링
watch kubectl top pods -n hgzero
# 이벤트 모니터링
kubectl get events -n hgzero --sort-by='.lastTimestamp'
```
## 보안 권장사항
1. **Secret 관리**
- Secret은 절대 Git에 커밋하지 마세요
- Azure Key Vault 통합을 고려하세요
- Secret rotation 정책을 수립하세요
2. **네트워크 보안**
- Network Policy를 활용하여 Pod 간 통신을 제한하세요
- Service Mesh 도입을 고려하세요
3. **이미지 보안**
- 정기적으로 이미지 스캔을 수행하세요
- 최소 권한 원칙을 적용하세요
## 성능 최적화
1. **Auto Scaling 설정**
```bash
kubectl autoscale deployment user-service \
--cpu-percent=70 \
--min=1 \
--max=5 \
-n hgzero
```
2. **리소스 조정**
- 실제 사용량에 따라 requests/limits를 조정하세요
- HPA(Horizontal Pod Autoscaler) 설정을 고려하세요
## 참고 자료
- [Azure Kubernetes Service 문서](https://docs.microsoft.com/azure/aks/)
- [Kubernetes 공식 문서](https://kubernetes.io/docs/)
- [kubectl 치트시트](https://kubernetes.io/docs/reference/kubectl/cheatsheet/)
## 지원 및 문의
문제 발생 시 다음 정보를 수집하여 보고해주세요:
```bash
# 진단 정보 수집
kubectl get all -n hgzero > hgzero-resources.txt
kubectl describe pods -n hgzero > hgzero-pods-detail.txt
kubectl logs deployment/user-service -n hgzero > user-service.log
kubectl logs deployment/meeting-service -n hgzero > meeting-service.log
kubectl logs deployment/notification-service -n hgzero > notification-service.log
```

View File

@ -0,0 +1,20 @@
---
# Redis Configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: redis-config
namespace: hgzero
data:
host: "redis-service.hgzero.svc.cluster.local"
port: "6379"
---
# Mail Configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: mail-config
namespace: hgzero
data:
host: "smtp.gmail.com"
port: "587"

View File

@ -0,0 +1,103 @@
#!/bin/bash
# HGZero Backend Services Secrets Creation Script
# This script helps create Kubernetes secrets for the backend services
set -e
# Color codes for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Configuration
NAMESPACE="hgzero"
echo -e "${GREEN}======================================${NC}"
echo -e "${GREEN}HGZero Secrets Creation${NC}"
echo -e "${GREEN}======================================${NC}"
# Check if kubectl is installed
if ! command -v kubectl &> /dev/null; then
echo -e "${RED}Error: kubectl is not installed${NC}"
exit 1
fi
# Verify connection to cluster
echo -e "${YELLOW}Verifying connection to Kubernetes cluster...${NC}"
if ! kubectl cluster-info &> /dev/null; then
echo -e "${RED}Error: Cannot connect to Kubernetes cluster${NC}"
exit 1
fi
# Check if namespace exists
if ! kubectl get namespace ${NAMESPACE} &> /dev/null; then
echo -e "${RED}Error: Namespace '${NAMESPACE}' does not exist${NC}"
echo -e "${YELLOW}Please run deploy.sh first to create the namespace${NC}"
exit 1
fi
# Function to prompt for secret value
prompt_secret() {
local prompt_text=$1
local secret_value
echo -n -e "${YELLOW}${prompt_text}: ${NC}"
read -s secret_value
echo ""
echo -n "$secret_value"
}
# Create Database Secret
echo -e "${GREEN}Creating Database Secret...${NC}"
DB_HOST=$(prompt_secret "Enter Database Host")
DB_USERNAME=$(prompt_secret "Enter Database Username")
DB_PASSWORD=$(prompt_secret "Enter Database Password")
kubectl create secret generic db-secret \
--from-literal=host="${DB_HOST}" \
--from-literal=username="${DB_USERNAME}" \
--from-literal=password="${DB_PASSWORD}" \
--namespace=${NAMESPACE} \
--dry-run=client -o yaml | kubectl apply -f -
echo -e "${GREEN}✓ Database secret created${NC}"
echo ""
# Create Azure Secret
echo -e "${GREEN}Creating Azure Secret...${NC}"
EVENTHUB_CONN=$(prompt_secret "Enter EventHub Connection String")
BLOB_CONN=$(prompt_secret "Enter Blob Storage Connection String")
kubectl create secret generic azure-secret \
--from-literal=eventhub-connection-string="${EVENTHUB_CONN}" \
--from-literal=blob-connection-string="${BLOB_CONN}" \
--namespace=${NAMESPACE} \
--dry-run=client -o yaml | kubectl apply -f -
echo -e "${GREEN}✓ Azure secret created${NC}"
echo ""
# Create Mail Secret
echo -e "${GREEN}Creating Mail Secret...${NC}"
MAIL_USERNAME=$(prompt_secret "Enter Mail Username")
MAIL_PASSWORD=$(prompt_secret "Enter Mail Password")
kubectl create secret generic mail-secret \
--from-literal=username="${MAIL_USERNAME}" \
--from-literal=password="${MAIL_PASSWORD}" \
--namespace=${NAMESPACE} \
--dry-run=client -o yaml | kubectl apply -f -
echo -e "${GREEN}✓ Mail secret created${NC}"
echo ""
# Verify secrets
echo -e "${GREEN}======================================${NC}"
echo -e "${GREEN}Secrets Created Successfully${NC}"
echo -e "${GREEN}======================================${NC}"
kubectl get secrets -n ${NAMESPACE}
echo ""
echo -e "${YELLOW}Note: Secrets are stored in Kubernetes and can be viewed with:${NC}"
echo -e " kubectl get secret <secret-name> -n ${NAMESPACE} -o yaml"

133
deploy/k8s/backend/deploy.sh Executable file
View File

@ -0,0 +1,133 @@
#!/bin/bash
# HGZero Backend Services Kubernetes Deployment Script
# Azure Container Registry: acrdigitalgarage02
# Azure Kubernetes Service: aks-digitalgarage-02
# Namespace: hgzero
set -e
# Color codes for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Configuration
ACR_NAME="acrdigitalgarage02"
AKS_NAME="aks-digitalgarage-02"
RESOURCE_GROUP="rg-digitalgarage-02"
NAMESPACE="hgzero"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo -e "${GREEN}======================================${NC}"
echo -e "${GREEN}HGZero Backend Services Deployment${NC}"
echo -e "${GREEN}======================================${NC}"
# Check if kubectl is installed
if ! command -v kubectl &> /dev/null; then
echo -e "${RED}Error: kubectl is not installed${NC}"
exit 1
fi
# Check if Azure CLI is installed
if ! command -v az &> /dev/null; then
echo -e "${RED}Error: Azure CLI is not installed${NC}"
exit 1
fi
# Login to Azure (if not already logged in)
echo -e "${YELLOW}Checking Azure login status...${NC}"
if ! az account show &> /dev/null; then
echo -e "${YELLOW}Please login to Azure...${NC}"
az login
fi
# Get AKS credentials
echo -e "${YELLOW}Getting AKS credentials...${NC}"
az aks get-credentials --resource-group ${RESOURCE_GROUP} --name ${AKS_NAME} --overwrite-existing
# Verify connection to cluster
echo -e "${YELLOW}Verifying connection to Kubernetes cluster...${NC}"
if ! kubectl cluster-info &> /dev/null; then
echo -e "${RED}Error: Cannot connect to Kubernetes cluster${NC}"
exit 1
fi
echo -e "${GREEN}✓ Successfully connected to ${AKS_NAME}${NC}"
# Create namespace if it doesn't exist
echo -e "${YELLOW}Creating namespace '${NAMESPACE}'...${NC}"
kubectl apply -f ${SCRIPT_DIR}/namespace.yaml
echo -e "${GREEN}✓ Namespace created/verified${NC}"
# Apply ConfigMaps
echo -e "${YELLOW}Applying ConfigMaps...${NC}"
kubectl apply -f ${SCRIPT_DIR}/configmap.yaml
echo -e "${GREEN}✓ ConfigMaps applied${NC}"
# Check if secrets exist
echo -e "${YELLOW}Checking for secrets...${NC}"
if ! kubectl get secret db-secret -n ${NAMESPACE} &> /dev/null || \
! kubectl get secret azure-secret -n ${NAMESPACE} &> /dev/null || \
! kubectl get secret mail-secret -n ${NAMESPACE} &> /dev/null; then
echo -e "${RED}Warning: One or more secrets are missing!${NC}"
echo -e "${YELLOW}Please create secrets using secret-template.yaml as reference${NC}"
echo -e "${YELLOW}Example:${NC}"
echo -e " kubectl create secret generic db-secret -n ${NAMESPACE} \\"
echo -e " --from-literal=host=<DB_HOST> \\"
echo -e " --from-literal=username=<DB_USERNAME> \\"
echo -e " --from-literal=password=<DB_PASSWORD>"
echo ""
read -p "Do you want to continue without secrets? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo -e "${RED}Deployment cancelled${NC}"
exit 1
fi
fi
# Configure ACR integration
echo -e "${YELLOW}Configuring ACR integration...${NC}"
az aks update -n ${AKS_NAME} -g ${RESOURCE_GROUP} --attach-acr ${ACR_NAME}
echo -e "${GREEN}✓ ACR integration configured${NC}"
# Deploy services
echo -e "${YELLOW}Deploying User Service...${NC}"
kubectl apply -f ${SCRIPT_DIR}/user-service.yaml
echo -e "${GREEN}✓ User Service deployed${NC}"
echo -e "${YELLOW}Deploying Notification Service...${NC}"
kubectl apply -f ${SCRIPT_DIR}/notification-service.yaml
echo -e "${GREEN}✓ Notification Service deployed${NC}"
echo -e "${YELLOW}Deploying Meeting Service...${NC}"
kubectl apply -f ${SCRIPT_DIR}/meeting-service.yaml
echo -e "${GREEN}✓ Meeting Service deployed${NC}"
# Wait for deployments to be ready
echo -e "${YELLOW}Waiting for deployments to be ready...${NC}"
kubectl wait --for=condition=available --timeout=300s \
deployment/user-service \
deployment/notification-service \
deployment/meeting-service \
-n ${NAMESPACE}
# Show deployment status
echo -e "${GREEN}======================================${NC}"
echo -e "${GREEN}Deployment Status${NC}"
echo -e "${GREEN}======================================${NC}"
kubectl get deployments -n ${NAMESPACE}
echo ""
kubectl get pods -n ${NAMESPACE}
echo ""
kubectl get services -n ${NAMESPACE}
echo -e "${GREEN}======================================${NC}"
echo -e "${GREEN}Deployment Completed Successfully!${NC}"
echo -e "${GREEN}======================================${NC}"
echo ""
echo -e "${YELLOW}Useful commands:${NC}"
echo -e " View logs: kubectl logs -f deployment/<service-name> -n ${NAMESPACE}"
echo -e " View pods: kubectl get pods -n ${NAMESPACE}"
echo -e " Describe pod: kubectl describe pod <pod-name> -n ${NAMESPACE}"
echo -e " Port forward: kubectl port-forward svc/<service-name> <local-port>:<service-port> -n ${NAMESPACE}"

View File

@ -0,0 +1,112 @@
---
# Meeting Service Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: meeting-service
namespace: hgzero
labels:
app: meeting-service
tier: backend
spec:
replicas: 1
selector:
matchLabels:
app: meeting-service
template:
metadata:
labels:
app: meeting-service
tier: backend
spec:
containers:
- name: meeting-service
image: acrdigitalgarage02.azurecr.io/hgzero/meeting-service:latest
imagePullPolicy: Always
ports:
- containerPort: 8081
name: http
- containerPort: 8082
name: websocket
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: SERVER_PORT
value: "8081"
- name: DB_HOST
valueFrom:
secretKeyRef:
name: db-secret
key: host
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
- name: REDIS_HOST
valueFrom:
configMapKeyRef:
name: redis-config
key: host
- name: REDIS_PORT
valueFrom:
configMapKeyRef:
name: redis-config
key: port
- name: AZURE_EVENTHUB_CONNECTION_STRING
valueFrom:
secretKeyRef:
name: azure-secret
key: eventhub-connection-string
- name: NOTIFICATION_SERVICE_URL
value: "http://notification-service:8082"
resources:
requests:
cpu: 256m
memory: 256Mi
limits:
cpu: 1024m
memory: 1024Mi
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8081
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8081
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
---
# Meeting Service Service
apiVersion: v1
kind: Service
metadata:
name: meeting-service
namespace: hgzero
labels:
app: meeting-service
spec:
type: ClusterIP
ports:
- port: 8081
targetPort: 8081
protocol: TCP
name: http
- port: 8082
targetPort: 8082
protocol: TCP
name: websocket
selector:
app: meeting-service

View File

@ -0,0 +1,9 @@
---
# Namespace for HGZero application
apiVersion: v1
kind: Namespace
metadata:
name: hgzero
labels:
name: hgzero
environment: production

View File

@ -0,0 +1,129 @@
---
# Notification Service Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: notification-service
namespace: hgzero
labels:
app: notification-service
tier: backend
spec:
replicas: 1
selector:
matchLabels:
app: notification-service
template:
metadata:
labels:
app: notification-service
tier: backend
spec:
containers:
- name: notification-service
image: acrdigitalgarage02.azurecr.io/hgzero/notification-service:latest
imagePullPolicy: Always
ports:
- containerPort: 8082
name: http
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: SERVER_PORT
value: "8082"
- name: DB_HOST
valueFrom:
secretKeyRef:
name: db-secret
key: host
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
- name: REDIS_HOST
valueFrom:
configMapKeyRef:
name: redis-config
key: host
- name: REDIS_PORT
valueFrom:
configMapKeyRef:
name: redis-config
key: port
- name: AZURE_EVENTHUB_CONNECTION_STRING
valueFrom:
secretKeyRef:
name: azure-secret
key: eventhub-connection-string
- name: AZURE_BLOB_CONNECTION_STRING
valueFrom:
secretKeyRef:
name: azure-secret
key: blob-connection-string
- name: MAIL_HOST
valueFrom:
configMapKeyRef:
name: mail-config
key: host
- name: MAIL_PORT
valueFrom:
configMapKeyRef:
name: mail-config
key: port
- name: MAIL_USERNAME
valueFrom:
secretKeyRef:
name: mail-secret
key: username
- name: MAIL_PASSWORD
valueFrom:
secretKeyRef:
name: mail-secret
key: password
resources:
requests:
cpu: 256m
memory: 256Mi
limits:
cpu: 1024m
memory: 1024Mi
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8082
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8082
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
---
# Notification Service Service
apiVersion: v1
kind: Service
metadata:
name: notification-service
namespace: hgzero
labels:
app: notification-service
spec:
type: ClusterIP
ports:
- port: 8082
targetPort: 8082
protocol: TCP
name: http
selector:
app: notification-service

View File

@ -0,0 +1,36 @@
---
# Database Secret Template
# Note: Replace base64 encoded values with your actual credentials
# To encode: echo -n 'your-value' | base64
apiVersion: v1
kind: Secret
metadata:
name: db-secret
namespace: hgzero
type: Opaque
data:
host: <BASE64_ENCODED_DB_HOST>
username: <BASE64_ENCODED_DB_USERNAME>
password: <BASE64_ENCODED_DB_PASSWORD>
---
# Azure Secret Template
apiVersion: v1
kind: Secret
metadata:
name: azure-secret
namespace: hgzero
type: Opaque
data:
eventhub-connection-string: <BASE64_ENCODED_EVENTHUB_CONNECTION_STRING>
blob-connection-string: <BASE64_ENCODED_BLOB_CONNECTION_STRING>
---
# Mail Secret Template
apiVersion: v1
kind: Secret
metadata:
name: mail-secret
namespace: hgzero
type: Opaque
data:
username: <BASE64_ENCODED_MAIL_USERNAME>
password: <BASE64_ENCODED_MAIL_PASSWORD>

89
deploy/k8s/backend/undeploy.sh Executable file
View File

@ -0,0 +1,89 @@
#!/bin/bash
# HGZero Backend Services Kubernetes Undeployment Script
set -e
# Color codes for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Configuration
NAMESPACE="hgzero"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo -e "${YELLOW}======================================${NC}"
echo -e "${YELLOW}HGZero Backend Services Undeployment${NC}"
echo -e "${YELLOW}======================================${NC}"
# Check if kubectl is installed
if ! command -v kubectl &> /dev/null; then
echo -e "${RED}Error: kubectl is not installed${NC}"
exit 1
fi
# Verify connection to cluster
echo -e "${YELLOW}Verifying connection to Kubernetes cluster...${NC}"
if ! kubectl cluster-info &> /dev/null; then
echo -e "${RED}Error: Cannot connect to Kubernetes cluster${NC}"
exit 1
fi
# Check if namespace exists
if ! kubectl get namespace ${NAMESPACE} &> /dev/null; then
echo -e "${YELLOW}Namespace '${NAMESPACE}' does not exist. Nothing to undeploy.${NC}"
exit 0
fi
echo -e "${YELLOW}This will delete all services in namespace '${NAMESPACE}'${NC}"
read -p "Are you sure you want to continue? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo -e "${YELLOW}Undeployment cancelled${NC}"
exit 0
fi
# Delete services
echo -e "${YELLOW}Deleting Meeting Service...${NC}"
kubectl delete -f ${SCRIPT_DIR}/meeting-service.yaml --ignore-not-found=true
echo -e "${GREEN}✓ Meeting Service deleted${NC}"
echo -e "${YELLOW}Deleting Notification Service...${NC}"
kubectl delete -f ${SCRIPT_DIR}/notification-service.yaml --ignore-not-found=true
echo -e "${GREEN}✓ Notification Service deleted${NC}"
echo -e "${YELLOW}Deleting User Service...${NC}"
kubectl delete -f ${SCRIPT_DIR}/user-service.yaml --ignore-not-found=true
echo -e "${GREEN}✓ User Service deleted${NC}"
# Delete ConfigMaps
echo -e "${YELLOW}Deleting ConfigMaps...${NC}"
kubectl delete -f ${SCRIPT_DIR}/configmap.yaml --ignore-not-found=true
echo -e "${GREEN}✓ ConfigMaps deleted${NC}"
# Ask about secrets deletion
echo ""
echo -e "${YELLOW}Do you want to delete secrets as well?${NC}"
echo -e "${RED}Warning: This will delete all database and Azure credentials${NC}"
read -p "Delete secrets? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
kubectl delete secret db-secret azure-secret mail-secret -n ${NAMESPACE} --ignore-not-found=true
echo -e "${GREEN}✓ Secrets deleted${NC}"
fi
# Ask about namespace deletion
echo ""
echo -e "${YELLOW}Do you want to delete the namespace '${NAMESPACE}'?${NC}"
read -p "Delete namespace? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
kubectl delete namespace ${NAMESPACE}
echo -e "${GREEN}✓ Namespace deleted${NC}"
fi
echo -e "${GREEN}======================================${NC}"
echo -e "${GREEN}Undeployment Completed${NC}"
echo -e "${GREEN}======================================${NC}"

View File

@ -0,0 +1,102 @@
---
# User Service Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
namespace: hgzero
labels:
app: user-service
tier: backend
spec:
replicas: 1
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
tier: backend
spec:
containers:
- name: user-service
image: acrdigitalgarage02.azurecr.io/hgzero/user-service:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
name: http
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: DB_HOST
valueFrom:
secretKeyRef:
name: db-secret
key: host
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
- name: REDIS_HOST
valueFrom:
configMapKeyRef:
name: redis-config
key: host
- name: REDIS_PORT
valueFrom:
configMapKeyRef:
name: redis-config
key: port
- name: AZURE_EVENTHUB_CONNECTION_STRING
valueFrom:
secretKeyRef:
name: azure-secret
key: eventhub-connection-string
resources:
requests:
cpu: 256m
memory: 256Mi
limits:
cpu: 1024m
memory: 1024Mi
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
---
# User Service Service
apiVersion: v1
kind: Service
metadata:
name: user-service
namespace: hgzero
labels:
app: user-service
spec:
type: ClusterIP
ports:
- port: 8080
targetPort: 8080
protocol: TCP
name: http
selector:
app: user-service