mirror of
https://github.com/cna-bootcamp/phonebill.git
synced 2026-06-12 19:49:10 +00:00
GitHub Actions CI/CD 파이프라인 구축 완료
- GitHub Actions 전용 Kustomize 매니페스트 구조 생성 - 환경별(dev/staging/prod) Overlay 및 Patch 파일 작성 - SonarQube 코드 품질 분석 통합 - Docker 이미지 빌드 및 Azure Container Registry 푸시 - Kubernetes 자동 배포 워크플로우 구성 - 수동 배포 스크립트 및 구축 가이드 문서 추가 주요 기능: - 자동 배포: Push/PR 시 dev 환경 자동 배포 - 수동 배포: 환경 선택 가능한 워크플로우 트리거 - 환경별 최적화: dev(1 replica), staging(2 replicas), prod(3 replicas) - 보안 설정: staging/prod HTTPS, JWT 토큰 유효시간 조정 - 롤백 지원: GitHub Actions, kubectl, 수동 스크립트 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Vendored
-225
@@ -1,225 +0,0 @@
|
||||
def PIPELINE_ID = "${env.BUILD_NUMBER}"
|
||||
|
||||
def getImageTag() {
|
||||
def dateFormat = new java.text.SimpleDateFormat('yyyyMMddHHmmss')
|
||||
def currentDate = new Date()
|
||||
return dateFormat.format(currentDate)
|
||||
}
|
||||
|
||||
podTemplate(
|
||||
label: "${PIPELINE_ID}",
|
||||
serviceAccount: 'jenkins',
|
||||
slaveConnectTimeout: 300,
|
||||
idleMinutes: 1,
|
||||
activeDeadlineSeconds: 3600,
|
||||
podRetention: never(), // 파드 자동 정리 옵션: never(), onFailure(), always(), default()
|
||||
yaml: '''
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 3
|
||||
restartPolicy: Never
|
||||
tolerations:
|
||||
- effect: NoSchedule
|
||||
key: dedicated
|
||||
operator: Equal
|
||||
value: cicd
|
||||
''',
|
||||
containers: [
|
||||
containerTemplate(
|
||||
name: 'podman',
|
||||
image: "mgoltzsche/podman",
|
||||
ttyEnabled: true,
|
||||
command: 'cat',
|
||||
privileged: true,
|
||||
resourceRequestCpu: '500m',
|
||||
resourceRequestMemory: '2Gi',
|
||||
resourceLimitCpu: '2000m',
|
||||
resourceLimitMemory: '4Gi'
|
||||
),
|
||||
containerTemplate(
|
||||
name: 'gradle',
|
||||
image: 'gradle:jdk21',
|
||||
ttyEnabled: true,
|
||||
command: 'cat',
|
||||
resourceRequestCpu: '500m',
|
||||
resourceRequestMemory: '1Gi',
|
||||
resourceLimitCpu: '1000m',
|
||||
resourceLimitMemory: '2Gi',
|
||||
envVars: [
|
||||
envVar(key: 'DOCKER_HOST', value: 'unix:///run/podman/podman.sock'),
|
||||
envVar(key: 'TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE', value: '/run/podman/podman.sock'),
|
||||
envVar(key: 'TESTCONTAINERS_RYUK_DISABLED', value: 'true')
|
||||
]
|
||||
),
|
||||
containerTemplate(
|
||||
name: 'azure-cli',
|
||||
image: 'hiondal/azure-kubectl:latest',
|
||||
command: 'cat',
|
||||
ttyEnabled: true,
|
||||
resourceRequestCpu: '200m',
|
||||
resourceRequestMemory: '512Mi',
|
||||
resourceLimitCpu: '500m',
|
||||
resourceLimitMemory: '1Gi'
|
||||
)
|
||||
],
|
||||
volumes: [
|
||||
emptyDirVolume(mountPath: '/home/gradle/.gradle', memory: false),
|
||||
emptyDirVolume(mountPath: '/root/.azure', memory: false),
|
||||
emptyDirVolume(mountPath: '/run/podman', memory: false)
|
||||
]
|
||||
) {
|
||||
node(PIPELINE_ID) {
|
||||
def props
|
||||
def imageTag = getImageTag()
|
||||
def environment = params.ENVIRONMENT ?: 'dev'
|
||||
def id = params.ID ?: 'dg0500'
|
||||
def skipSonarQube = (params.SKIP_SONARQUBE?.toLowerCase() == 'true')
|
||||
def services = ['api-gateway', 'user-service', 'bill-service', 'product-service', 'kos-mock']
|
||||
|
||||
try {
|
||||
stage("Get Source") {
|
||||
checkout scm
|
||||
props = readProperties file: "deployment/cicd/config/deploy_env_vars_${environment}"
|
||||
}
|
||||
|
||||
stage("Setup AKS") {
|
||||
container('azure-cli') {
|
||||
withCredentials([azureServicePrincipal('azure-credentials')]) {
|
||||
sh """
|
||||
az login --service-principal -u \$AZURE_CLIENT_ID -p \$AZURE_CLIENT_SECRET -t \$AZURE_TENANT_ID
|
||||
az aks get-credentials --resource-group ${props.resource_group} --name ${props.cluster_name} --overwrite-existing
|
||||
kubectl create namespace phonebill-${id} --dry-run=client -o yaml | kubectl apply -f -
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build') {
|
||||
container('gradle') {
|
||||
sh """
|
||||
chmod +x gradlew
|
||||
./gradlew build -x test
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
stage('SonarQube Analysis & Quality Gate') {
|
||||
if (skipSonarQube) {
|
||||
echo "⏭️ Skipping SonarQube Analysis (SKIP_SONARQUBE=${params.SKIP_SONARQUBE})"
|
||||
} else {
|
||||
container('gradle') {
|
||||
withSonarQubeEnv('SonarQube') {
|
||||
// 각 서비스별 테스트 및 SonarQube 분석
|
||||
services.each { service ->
|
||||
sh """
|
||||
./gradlew :${service}:test :${service}:jacocoTestReport :${service}:sonar \\
|
||||
-Dsonar.projectKey=phonebill-${service}-${id} \\
|
||||
-Dsonar.projectName=phonebill-${service}-${id} \\
|
||||
-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/**
|
||||
"""
|
||||
}
|
||||
|
||||
// Quality Gate 확인
|
||||
timeout(time: 10, unit: 'MINUTES') {
|
||||
def qg = waitForQualityGate()
|
||||
if (qg.status != 'OK') {
|
||||
error "Pipeline aborted due to quality gate failure: ${qg.status}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build & Push Images') {
|
||||
timeout(time: 30, unit: 'MINUTES') {
|
||||
container('podman') {
|
||||
withCredentials([
|
||||
usernamePassword(
|
||||
credentialsId: 'acr-credentials',
|
||||
usernameVariable: 'ACR_USERNAME',
|
||||
passwordVariable: 'ACR_PASSWORD'
|
||||
),
|
||||
usernamePassword(
|
||||
credentialsId: 'dockerhub-credentials',
|
||||
usernameVariable: 'DOCKERHUB_USERNAME',
|
||||
passwordVariable: 'DOCKERHUB_PASSWORD'
|
||||
)
|
||||
]) {
|
||||
// Docker Hub 로그인 (rate limit 해결)
|
||||
sh "podman login docker.io --username \$DOCKERHUB_USERNAME --password \$DOCKERHUB_PASSWORD"
|
||||
|
||||
// ACR 로그인
|
||||
sh "podman login acrdigitalgarage01.azurecr.io --username \$ACR_USERNAME --password \$ACR_PASSWORD"
|
||||
|
||||
services.each { service ->
|
||||
sh """
|
||||
podman build \\
|
||||
--build-arg BUILD_LIB_DIR="${service}/build/libs" \\
|
||||
--build-arg ARTIFACTORY_FILE="${service}.jar" \\
|
||||
-f deployment/container/Dockerfile-backend \\
|
||||
-t acrdigitalgarage01.azurecr.io/phonebill/${service}:${id}-${imageTag} .
|
||||
|
||||
podman push acrdigitalgarage01.azurecr.io/phonebill/${service}:${id}-${imageTag}
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Update Kustomize & Deploy') {
|
||||
container('azure-cli') {
|
||||
sh """
|
||||
# Kustomize 설치 (sudo 없이 사용자 디렉토리에 설치)
|
||||
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
|
||||
mkdir -p \$HOME/bin
|
||||
mv kustomize \$HOME/bin/
|
||||
export PATH=\$PATH:\$HOME/bin
|
||||
|
||||
# 환경별 디렉토리로 이동
|
||||
cd deployment/cicd/kustomize/overlays/${environment}
|
||||
|
||||
# 서비스 목록 정의 (공백으로 구분)
|
||||
services="api-gateway user-service bill-service product-service kos-mock"
|
||||
|
||||
# 이미지 태그 업데이트
|
||||
for service in \$services; do
|
||||
\$HOME/bin/kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/\$service:${id}-${imageTag}
|
||||
done
|
||||
|
||||
# 매니페스트 적용
|
||||
kubectl apply -k .
|
||||
|
||||
# 배포 상태 확인
|
||||
echo "Waiting for deployments to be ready..."
|
||||
for service in \$services; do
|
||||
kubectl -n phonebill-${id} wait --for=condition=available deployment/\$service --timeout=300s
|
||||
done
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
// 파이프라인 완료 로그 (Scripted Pipeline 방식)
|
||||
stage('Pipeline Complete') {
|
||||
echo "🧹 Pipeline completed. Pod cleanup handled by Jenkins Kubernetes Plugin."
|
||||
|
||||
// 성공/실패 여부 로깅
|
||||
if (currentBuild.result == null || currentBuild.result == 'SUCCESS') {
|
||||
echo "✅ Pipeline completed successfully!"
|
||||
} else {
|
||||
echo "❌ Pipeline failed with result: ${currentBuild.result}"
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
currentBuild.result = 'FAILURE'
|
||||
echo "❌ Pipeline failed with exception: ${e.getMessage()}"
|
||||
throw e
|
||||
} finally {
|
||||
echo "🧹 Cleaning up resources and preparing for pod termination..."
|
||||
echo "Pod will be terminated in 3 seconds due to terminationGracePeriodSeconds: 3"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
def PIPELINE_ID = "${env.BUILD_NUMBER}"
|
||||
|
||||
def getImageTag() {
|
||||
def dateFormat = new java.text.SimpleDateFormat('yyyyMMddHHmmss')
|
||||
def currentDate = new Date()
|
||||
return dateFormat.format(currentDate)
|
||||
}
|
||||
|
||||
podTemplate(
|
||||
label: "${PIPELINE_ID}",
|
||||
serviceAccount: 'jenkins',
|
||||
slaveConnectTimeout: 300,
|
||||
idleMinutes: 1,
|
||||
activeDeadlineSeconds: 3600,
|
||||
podRetention: never(), // 파드 자동 정리 옵션: never(), onFailure(), always(), default()
|
||||
yaml: '''
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 3
|
||||
restartPolicy: Never
|
||||
tolerations:
|
||||
- effect: NoSchedule
|
||||
key: dedicated
|
||||
operator: Equal
|
||||
value: cicd
|
||||
''',
|
||||
containers: [
|
||||
containerTemplate(
|
||||
name: 'podman',
|
||||
image: "mgoltzsche/podman",
|
||||
ttyEnabled: true,
|
||||
command: 'cat',
|
||||
privileged: true,
|
||||
resourceRequestCpu: '500m',
|
||||
resourceRequestMemory: '2Gi',
|
||||
resourceLimitCpu: '2000m',
|
||||
resourceLimitMemory: '4Gi'
|
||||
),
|
||||
containerTemplate(
|
||||
name: 'gradle',
|
||||
image: 'gradle:jdk21',
|
||||
ttyEnabled: true,
|
||||
command: 'cat',
|
||||
resourceRequestCpu: '500m',
|
||||
resourceRequestMemory: '1Gi',
|
||||
resourceLimitCpu: '1000m',
|
||||
resourceLimitMemory: '2Gi',
|
||||
envVars: [
|
||||
envVar(key: 'DOCKER_HOST', value: 'unix:///run/podman/podman.sock'),
|
||||
envVar(key: 'TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE', value: '/run/podman/podman.sock'),
|
||||
envVar(key: 'TESTCONTAINERS_RYUK_DISABLED', value: 'true')
|
||||
]
|
||||
),
|
||||
containerTemplate(
|
||||
name: 'azure-cli',
|
||||
image: 'hiondal/azure-kubectl:latest',
|
||||
command: 'cat',
|
||||
ttyEnabled: true,
|
||||
resourceRequestCpu: '200m',
|
||||
resourceRequestMemory: '512Mi',
|
||||
resourceLimitCpu: '500m',
|
||||
resourceLimitMemory: '1Gi'
|
||||
),
|
||||
containerTemplate(
|
||||
name: 'git',
|
||||
image: 'alpine/git:latest',
|
||||
command: 'cat',
|
||||
ttyEnabled: true,
|
||||
resourceRequestCpu: '100m',
|
||||
resourceRequestMemory: '256Mi',
|
||||
resourceLimitCpu: '300m',
|
||||
resourceLimitMemory: '512Mi'
|
||||
)
|
||||
],
|
||||
volumes: [
|
||||
emptyDirVolume(mountPath: '/home/gradle/.gradle', memory: false),
|
||||
emptyDirVolume(mountPath: '/root/.azure', memory: false),
|
||||
emptyDirVolume(mountPath: '/run/podman', memory: false)
|
||||
]
|
||||
) {
|
||||
node(PIPELINE_ID) {
|
||||
def props
|
||||
def imageTag = getImageTag()
|
||||
def environment = params.ENVIRONMENT ?: 'dev'
|
||||
def skipSonarQube = (params.SKIP_SONARQUBE?.toLowerCase() == 'true')
|
||||
def services = ['api-gateway', 'user-service', 'bill-service', 'product-service', 'kos-mock']
|
||||
|
||||
try {
|
||||
stage("Get Source") {
|
||||
checkout scm
|
||||
props = readProperties file: "deployment/cicd/config/deploy_env_vars_${environment}"
|
||||
}
|
||||
|
||||
stage('Build') {
|
||||
container('gradle') {
|
||||
sh """
|
||||
chmod +x gradlew
|
||||
./gradlew build -x test
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
stage('SonarQube Analysis & Quality Gate') {
|
||||
if (skipSonarQube) {
|
||||
echo "⏭️ Skipping SonarQube Analysis (SKIP_SONARQUBE=${params.SKIP_SONARQUBE})"
|
||||
} else {
|
||||
container('gradle') {
|
||||
withSonarQubeEnv('SonarQube') {
|
||||
// 각 서비스별 테스트 및 SonarQube 분석
|
||||
services.each { service ->
|
||||
sh """
|
||||
./gradlew :${service}:test :${service}:jacocoTestReport :${service}:sonar \\
|
||||
-Dsonar.projectKey=phonebill-${service}-${environment} \\
|
||||
-Dsonar.projectName=phonebill-${service}-${environment} \\
|
||||
-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/**
|
||||
"""
|
||||
}
|
||||
|
||||
// Quality Gate 확인
|
||||
timeout(time: 10, unit: 'MINUTES') {
|
||||
def qg = waitForQualityGate()
|
||||
if (qg.status != 'OK') {
|
||||
error "Pipeline aborted due to quality gate failure: ${qg.status}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build & Push Images') {
|
||||
timeout(time: 30, unit: 'MINUTES') {
|
||||
container('podman') {
|
||||
withCredentials([
|
||||
usernamePassword(
|
||||
credentialsId: 'acr-credentials',
|
||||
usernameVariable: 'ACR_USERNAME',
|
||||
passwordVariable: 'ACR_PASSWORD'
|
||||
),
|
||||
usernamePassword(
|
||||
credentialsId: 'dockerhub-credentials',
|
||||
usernameVariable: 'DOCKERHUB_USERNAME',
|
||||
passwordVariable: 'DOCKERHUB_PASSWORD'
|
||||
)
|
||||
]) {
|
||||
// Docker Hub 로그인 (rate limit 해결)
|
||||
sh "podman login docker.io --username \$DOCKERHUB_USERNAME --password \$DOCKERHUB_PASSWORD"
|
||||
|
||||
// ACR 로그인
|
||||
sh "podman login acrdigitalgarage01.azurecr.io --username \$ACR_USERNAME --password \$ACR_PASSWORD"
|
||||
|
||||
services.each { service ->
|
||||
sh """
|
||||
podman build \\
|
||||
--build-arg BUILD_LIB_DIR="${service}/build/libs" \\
|
||||
--build-arg ARTIFACTORY_FILE="${service}.jar" \\
|
||||
-f deployment/container/Dockerfile-backend \\
|
||||
-t acrdigitalgarage01.azurecr.io/phonebill/${service}:${environment}-${imageTag} .
|
||||
|
||||
podman push acrdigitalgarage01.azurecr.io/phonebill/${service}:${environment}-${imageTag}
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Update Manifest Repository') {
|
||||
container('git') {
|
||||
withCredentials([usernamePassword(
|
||||
credentialsId: 'github-credentials-dg0500',
|
||||
usernameVariable: 'GIT_USERNAME',
|
||||
passwordVariable: 'GIT_TOKEN'
|
||||
)]) {
|
||||
sh """
|
||||
# 매니페스트 레포지토리 클론
|
||||
REPO_URL=\$(echo "https://github.com/cna-bootcamp/phonebill-manifest.git" | sed 's|https://||')
|
||||
git clone https://\${GIT_USERNAME}:\${GIT_TOKEN}@\${REPO_URL} manifest-repo
|
||||
cd manifest-repo
|
||||
|
||||
# 각 서비스별 이미지 태그 업데이트 (sed 명령 사용)
|
||||
services="api-gateway user-service bill-service product-service kos-mock"
|
||||
for service in \$services; do
|
||||
echo "Updating \$service image tag..."
|
||||
sed -i "s|image: acrdigitalgarage01.azurecr.io/phonebill/\$service:.*|image: acrdigitalgarage01.azurecr.io/phonebill/\$service:${environment}-${imageTag}|g" \\
|
||||
phonebill/kustomize/base/\$service/deployment.yaml
|
||||
|
||||
# 변경 사항 확인
|
||||
echo "Updated \$service deployment.yaml:"
|
||||
grep "image: acrdigitalgarage01.azurecr.io/phonebill/\$service" phonebill/kustomize/base/\$service/deployment.yaml
|
||||
done
|
||||
|
||||
# Git 설정 및 푸시
|
||||
git config user.name "Jenkins CI"
|
||||
git config user.email "jenkins@example.com"
|
||||
git add .
|
||||
git commit -m "🚀 Update phonebill ${environment} images to ${environment}-${imageTag}"
|
||||
git push origin main
|
||||
|
||||
echo "✅ 매니페스트 업데이트 완료. ArgoCD가 자동으로 배포합니다."
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 파이프라인 완료 로그 (Scripted Pipeline 방식)
|
||||
stage('Pipeline Complete') {
|
||||
echo "🧹 Pipeline completed. Pod cleanup handled by Jenkins Kubernetes Plugin."
|
||||
|
||||
// 성공/실패 여부 로깅
|
||||
if (currentBuild.result == null || currentBuild.result == 'SUCCESS') {
|
||||
echo "✅ Pipeline completed successfully!"
|
||||
echo "✅ 매니페스트가 업데이트되었습니다. ArgoCD에서 배포를 확인하세요."
|
||||
} else {
|
||||
echo "❌ Pipeline failed with result: ${currentBuild.result}"
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
currentBuild.result = 'FAILURE'
|
||||
echo "❌ Pipeline failed with exception: ${e.getMessage()}"
|
||||
throw e
|
||||
} finally {
|
||||
echo "🧹 Cleaning up resources and preparing for pod termination..."
|
||||
echo "Pod will be terminated in 3 seconds due to terminationGracePeriodSeconds: 3"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# dev Environment Configuration
|
||||
resource_group=rg-digitalgarage-01
|
||||
cluster_name=aks-digitalgarage-01
|
||||
@@ -1,3 +0,0 @@
|
||||
# prod Environment Configuration
|
||||
resource_group=rg-digitalgarage-01
|
||||
cluster_name=aks-digitalgarage-01
|
||||
@@ -1,3 +0,0 @@
|
||||
# staging Environment Configuration
|
||||
resource_group=rg-digitalgarage-01
|
||||
cluster_name=aks-digitalgarage-01
|
||||
@@ -1,350 +0,0 @@
|
||||
# Jenkins CI/CD 파이프라인 구축 가이드
|
||||
|
||||
**최운영/데옵스**가 작성한 통신요금 관리 서비스 Jenkins CI/CD 파이프라인 구축 가이드입니다.
|
||||
|
||||
## 📋 프로젝트 정보
|
||||
|
||||
### 시스템 정보
|
||||
- **시스템명**: phonebill
|
||||
- **서비스**: api-gateway, user-service, bill-service, product-service, kos-mock
|
||||
- **JDK 버전**: 21
|
||||
- **Container Registry**: acrdigitalgarage01.azurecr.io
|
||||
- **Resource Group**: rg-digitalgarage-01
|
||||
- **AKS Cluster**: aks-digitalgarage-01
|
||||
|
||||
## 🏗️ 아키텍처 개요
|
||||
|
||||
본 CI/CD 파이프라인은 다음 구성 요소들로 이루어져 있습니다:
|
||||
|
||||
- **Jenkins**: 파이프라인 오케스트레이션
|
||||
- **Kustomize**: 환경별 Kubernetes 매니페스트 관리
|
||||
- **SonarQube**: 코드 품질 분석 및 Quality Gate
|
||||
- **Azure Container Registry (ACR)**: 컨테이너 이미지 저장소
|
||||
- **Azure Kubernetes Service (AKS)**: 배포 대상 클러스터
|
||||
|
||||
## 🔧 사전 준비사항
|
||||
|
||||
### 1. Jenkins 서버 환경 구성
|
||||
|
||||
#### 필수 플러그인 설치
|
||||
```
|
||||
- Kubernetes
|
||||
- Pipeline Utility Steps
|
||||
- Docker Pipeline
|
||||
- GitHub
|
||||
- SonarQube Scanner
|
||||
- Azure Credentials
|
||||
```
|
||||
|
||||
#### Jenkins Credentials 등록
|
||||
|
||||
**Azure Service Principal**
|
||||
```
|
||||
Manage Jenkins > Credentials > Add Credentials
|
||||
- Kind: Microsoft Azure Service Principal
|
||||
- ID: azure-credentials
|
||||
- Subscription ID: {구독ID}
|
||||
- Client ID: {클라이언트ID}
|
||||
- Client Secret: {클라이언트시크릿}
|
||||
- Tenant ID: {테넌트ID}
|
||||
- Azure Environment: Azure
|
||||
```
|
||||
|
||||
**ACR Credentials**
|
||||
```
|
||||
- Kind: Username with password
|
||||
- ID: acr-credentials
|
||||
- Username: acrdigitalgarage01
|
||||
- Password: {ACR_PASSWORD}
|
||||
```
|
||||
|
||||
**Docker Hub Credentials** (Rate Limit 해결용)
|
||||
```
|
||||
- Kind: Username with password
|
||||
- ID: dockerhub-credentials
|
||||
- Username: {DOCKERHUB_USERNAME}
|
||||
- Password: {DOCKERHUB_PASSWORD}
|
||||
참고: Docker Hub 무료 계정 생성 (https://hub.docker.com)
|
||||
```
|
||||
|
||||
**SonarQube Token**
|
||||
```
|
||||
- Kind: Secret text
|
||||
- ID: sonarqube-token
|
||||
- Secret: {SonarQube토큰}
|
||||
```
|
||||
|
||||
### 2. SonarQube 프로젝트 설정
|
||||
|
||||
각 서비스별 프로젝트 생성 및 Quality Gate 설정:
|
||||
```
|
||||
Coverage: >= 80%
|
||||
Duplicated Lines: <= 3%
|
||||
Maintainability Rating: <= A
|
||||
Reliability Rating: <= A
|
||||
Security Rating: <= A
|
||||
```
|
||||
|
||||
## 📁 디렉토리 구조
|
||||
|
||||
구축 완료된 디렉토리 구조:
|
||||
```
|
||||
deployment/cicd/
|
||||
├── kustomize/
|
||||
│ ├── base/
|
||||
│ │ ├── common/
|
||||
│ │ │ ├── cm-common.yaml
|
||||
│ │ │ ├── secret-common.yaml
|
||||
│ │ │ ├── secret-imagepull.yaml
|
||||
│ │ │ └── ingress.yaml
|
||||
│ │ ├── api-gateway/
|
||||
│ │ ├── user-service/
|
||||
│ │ ├── bill-service/
|
||||
│ │ ├── product-service/
|
||||
│ │ ├── kos-mock/
|
||||
│ │ ├── namespace.yaml
|
||||
│ │ └── kustomization.yaml
|
||||
│ └── overlays/
|
||||
│ ├── dev/
|
||||
│ ├── staging/
|
||||
│ └── prod/
|
||||
├── config/
|
||||
│ ├── deploy_env_vars_dev
|
||||
│ ├── deploy_env_vars_staging
|
||||
│ └── deploy_env_vars_prod
|
||||
├── scripts/
|
||||
│ ├── deploy.sh
|
||||
│ └── validate-cicd-setup.sh
|
||||
└── Jenkinsfile
|
||||
```
|
||||
|
||||
## 🚀 파이프라인 단계
|
||||
|
||||
### 1. Get Source
|
||||
- GitHub에서 소스코드 체크아웃
|
||||
- 환경별 설정 파일 읽기
|
||||
|
||||
### 2. Setup AKS
|
||||
- Azure CLI로 인증
|
||||
- AKS 클러스터 연결
|
||||
- 환경별 네임스페이스 생성
|
||||
|
||||
### 3. Build & SonarQube Analysis
|
||||
- Gradle 빌드 (테스트 제외)
|
||||
- 각 서비스별 단위 테스트 실행
|
||||
- JaCoCo 커버리지 리포트 생성
|
||||
- SonarQube 코드 품질 분석
|
||||
|
||||
### 4. Quality Gate
|
||||
- SonarQube Quality Gate 대기 (10분 타임아웃)
|
||||
- 품질 기준 미달 시 파이프라인 중단
|
||||
|
||||
### 5. Build & Push Images
|
||||
- Podman을 사용한 컨테이너 이미지 빌드
|
||||
- 환경별 이미지 태그로 ACR에 푸시
|
||||
- 30분 타임아웃 설정
|
||||
|
||||
### 6. Update Kustomize & Deploy
|
||||
- Kustomize를 사용한 이미지 태그 업데이트
|
||||
- Kubernetes 매니페스트 적용
|
||||
- 배포 상태 확인 (5분 타임아웃)
|
||||
|
||||
### 7. Pipeline Complete
|
||||
- 성공/실패 로깅
|
||||
- 자동 파드 정리
|
||||
|
||||
## 🔄 파이프라인 실행 방법
|
||||
|
||||
### Jenkins 파이프라인 Job 생성
|
||||
|
||||
1. Jenkins 웹 UI에서 **New Item > Pipeline** 선택
|
||||
2. **Pipeline script from SCM** 설정:
|
||||
```
|
||||
SCM: Git
|
||||
Repository URL: {Git저장소URL}
|
||||
Branch: main
|
||||
Script Path: deployment/cicd/Jenkinsfile
|
||||
```
|
||||
3. **Pipeline Parameters** 설정:
|
||||
```
|
||||
ENVIRONMENT: Choice Parameter (dev, staging, prod)
|
||||
IMAGE_TAG: String Parameter (default: latest)
|
||||
```
|
||||
|
||||
### 배포 실행
|
||||
|
||||
1. Jenkins > {프로젝트명} > **Build with Parameters**
|
||||
2. **ENVIRONMENT** 선택 (dev/staging/prod)
|
||||
3. **IMAGE_TAG** 입력 (선택사항)
|
||||
4. **Build** 클릭
|
||||
|
||||
## 📊 환경별 설정
|
||||
|
||||
### DEV 환경
|
||||
- **네임스페이스**: phonebill-dev
|
||||
- **Replicas**: 1
|
||||
- **Resources**: 256m CPU/256Mi Memory → 1024m CPU/1024Mi Memory
|
||||
- **Database**: DDL update 모드
|
||||
- **Ingress**: HTTP, SSL 리다이렉션 비활성화
|
||||
|
||||
### STAGING 환경
|
||||
- **네임스페이스**: phonebill-staging
|
||||
- **Replicas**: 2
|
||||
- **Resources**: 512m CPU/512Mi Memory → 2048m CPU/2048Mi Memory
|
||||
- **Database**: DDL validate 모드
|
||||
- **Ingress**: HTTPS, SSL 리다이렉션 활성화
|
||||
|
||||
### PROD 환경
|
||||
- **네임스페이스**: phonebill-prod
|
||||
- **Replicas**: 3
|
||||
- **Resources**: 1024m CPU/1024Mi Memory → 4096m CPU/4096Mi Memory
|
||||
- **Database**: DDL validate 모드, 짧은 JWT 토큰 (1시간)
|
||||
- **Ingress**: HTTPS, SSL 리다이렉션 활성화, Let's Encrypt 인증서
|
||||
|
||||
## 🛠️ 수동 배포 방법
|
||||
|
||||
스크립트를 사용한 수동 배포:
|
||||
```bash
|
||||
# DEV 환경 배포
|
||||
./deployment/cicd/scripts/deploy.sh dev latest
|
||||
|
||||
# STAGING 환경 배포
|
||||
./deployment/cicd/scripts/deploy.sh staging 20241213151500
|
||||
|
||||
# PROD 환경 배포
|
||||
./deployment/cicd/scripts/deploy.sh prod 20241213151500
|
||||
```
|
||||
|
||||
## 📋 배포 상태 확인
|
||||
|
||||
```bash
|
||||
# 파드 상태 확인
|
||||
kubectl get pods -n phonebill-{환경}
|
||||
|
||||
# 서비스 확인
|
||||
kubectl get services -n phonebill-{환경}
|
||||
|
||||
# Ingress 확인
|
||||
kubectl get ingress -n phonebill-{환경}
|
||||
|
||||
# 배포 히스토리 확인
|
||||
kubectl rollout history deployment/{서비스명} -n phonebill-{환경}
|
||||
```
|
||||
|
||||
## 🔄 롤백 방법
|
||||
|
||||
### 이전 리비전으로 롤백
|
||||
```bash
|
||||
# 특정 버전으로 롤백
|
||||
kubectl rollout undo deployment/{서비스명} -n phonebill-{환경} --to-revision=2
|
||||
|
||||
# 롤백 상태 확인
|
||||
kubectl rollout status deployment/{서비스명} -n phonebill-{환경}
|
||||
```
|
||||
|
||||
### 이미지 태그 기반 롤백
|
||||
```bash
|
||||
# 이전 안정 버전 이미지 태그로 업데이트
|
||||
cd deployment/cicd/kustomize/overlays/{환경}
|
||||
kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/{서비스명}:{환경}-{이전태그}
|
||||
kubectl apply -k .
|
||||
```
|
||||
|
||||
## 🔍 트러블슈팅
|
||||
|
||||
### 일반적인 문제 해결
|
||||
|
||||
**1. SonarQube Quality Gate 실패**
|
||||
- 코드 커버리지 확인 (80% 이상)
|
||||
- 코드 중복도 확인 (3% 이하)
|
||||
- 보안/신뢰성 등급 확인 (A등급)
|
||||
|
||||
**2. 컨테이너 이미지 빌드 실패**
|
||||
- Dockerfile 경로 확인: `deployment/container/Dockerfile-backend`
|
||||
- JAR 파일 경로 확인: `{서비스명}/build/libs/{서비스명}.jar`
|
||||
- ACR 인증 상태 확인
|
||||
|
||||
**3. 배포 실패**
|
||||
- Kubernetes 매니페스트 문법 확인
|
||||
- 네임스페이스 존재 확인
|
||||
- 리소스 할당량 확인
|
||||
|
||||
**4. 파드 시작 실패**
|
||||
- 환경변수 설정 확인
|
||||
- Secret/ConfigMap 존재 확인
|
||||
- 이미지 태그 정확성 확인
|
||||
|
||||
### 검증 스크립트
|
||||
|
||||
리소스 누락 검증:
|
||||
```bash
|
||||
./deployment/cicd/scripts/validate-cicd-setup.sh
|
||||
```
|
||||
|
||||
## 🔐 보안 고려사항
|
||||
|
||||
### Jenkins 보안
|
||||
- **Service Account**: jenkins 전용 계정 사용
|
||||
- **Pod Security**: 최소 권한 원칙 적용
|
||||
- **Credential 관리**: Jenkins Credential Store 사용
|
||||
|
||||
### 컨테이너 보안
|
||||
- **Base Image**: 공식 이미지 사용
|
||||
- **Image Scanning**: ACR 취약점 스캔 활용
|
||||
- **Secrets 관리**: Kubernetes Secret으로 관리
|
||||
|
||||
### 네트워크 보안
|
||||
- **TLS**: HTTPS 강제 적용 (Staging/Prod)
|
||||
- **Network Policy**: 네임스페이스 격리
|
||||
- **Ingress**: 인증서 자동 갱신
|
||||
|
||||
## 📈 성능 최적화
|
||||
|
||||
### 빌드 최적화
|
||||
- **Gradle Daemon**: 빌드 속도 향상
|
||||
- **Docker Layer Caching**: 이미지 빌드 최적화
|
||||
- **Parallel Build**: 병렬 빌드 활용
|
||||
|
||||
### 배포 최적화
|
||||
- **Rolling Update**: 무중단 배포
|
||||
- **Health Check**: 정확한 상태 확인
|
||||
- **Resource Limit**: 적절한 리소스 할당
|
||||
|
||||
## 🔧 유지보수 가이드
|
||||
|
||||
### 정기 점검 항목
|
||||
- [ ] Jenkins 플러그인 업데이트
|
||||
- [ ] SonarQube 룰 세트 검토
|
||||
- [ ] ACR 이미지 정리
|
||||
- [ ] 인증서 만료일 확인
|
||||
|
||||
### 모니터링 권장사항
|
||||
- 빌드 실패율 모니터링
|
||||
- 배포 소요시간 추적
|
||||
- Quality Gate 통과율 확인
|
||||
- 리소스 사용률 모니터링
|
||||
|
||||
---
|
||||
|
||||
## ✅ 체크리스트
|
||||
|
||||
### 사전 준비 완료
|
||||
- [x] Jenkins 필수 플러그인 설치
|
||||
- [x] Jenkins Credentials 등록
|
||||
- [x] SonarQube 프로젝트 설정
|
||||
- [x] ACR 접근 권한 설정
|
||||
- [x] AKS 클러스터 연결 설정
|
||||
|
||||
### Kustomize 구성 완료
|
||||
- [x] Base 매니페스트 생성
|
||||
- [x] 환경별 Overlay 생성
|
||||
- [x] Patch 파일 작성
|
||||
- [x] 매니페스트 검증 완료
|
||||
|
||||
### 파이프라인 구성 완료
|
||||
- [x] Jenkinsfile 작성
|
||||
- [x] 환경별 설정 파일 생성
|
||||
- [x] 배포 스크립트 작성
|
||||
- [x] 검증 스크립트 작성
|
||||
|
||||
**🎯 모든 구성이 완료되어 Jenkins CI/CD 파이프라인을 실행할 준비가 완료되었습니다!**
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm-api-gateway
|
||||
|
||||
data:
|
||||
SERVER_PORT: "8080"
|
||||
BILL_SERVICE_URL: "http://bill-service"
|
||||
PRODUCT_SERVICE_URL: "http://product-service"
|
||||
USER_SERVICE_URL: "http://user-service"
|
||||
KOS_MOCK_URL: "http://kos-mock"
|
||||
@@ -1,58 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: api-gateway
|
||||
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: api-gateway
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: api-gateway
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: phonebill
|
||||
containers:
|
||||
- name: api-gateway
|
||||
image: acrdigitalgarage01.azurecr.io/phonebill/api-gateway:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: cm-common
|
||||
- configMapRef:
|
||||
name: cm-api-gateway
|
||||
- secretRef:
|
||||
name: secret-common
|
||||
resources:
|
||||
requests:
|
||||
cpu: 256m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1024m
|
||||
memory: 1024Mi
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
failureThreshold: 6
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
failureThreshold: 3
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
failureThreshold: 3
|
||||
@@ -1,12 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: api-gateway
|
||||
|
||||
spec:
|
||||
selector:
|
||||
app: api-gateway
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
type: ClusterIP
|
||||
@@ -1,22 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm-bill-service
|
||||
|
||||
data:
|
||||
SERVER_PORT: "8082"
|
||||
DB_KIND: "postgresql"
|
||||
DB_PORT: "5432"
|
||||
DB_CONNECTION_TIMEOUT: "30000"
|
||||
DB_IDLE_TIMEOUT: "600000"
|
||||
DB_LEAK_DETECTION: "60000"
|
||||
DB_MAX_LIFETIME: "1800000"
|
||||
DB_MAX_POOL: "20"
|
||||
DB_MIN_IDLE: "5"
|
||||
KOS_BASE_URL: "http://kos-mock"
|
||||
REDIS_DATABASE: "1"
|
||||
REDIS_MAX_ACTIVE: "8"
|
||||
REDIS_MAX_IDLE: "8"
|
||||
REDIS_MAX_WAIT: "-1"
|
||||
REDIS_MIN_IDLE: "0"
|
||||
REDIS_TIMEOUT: "2000"
|
||||
@@ -1,60 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: bill-service
|
||||
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: bill-service
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: bill-service
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: phonebill
|
||||
containers:
|
||||
- name: bill-service
|
||||
image: acrdigitalgarage01.azurecr.io/phonebill/bill-service:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8082
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: cm-common
|
||||
- configMapRef:
|
||||
name: cm-bill-service
|
||||
- secretRef:
|
||||
name: secret-common
|
||||
- secretRef:
|
||||
name: secret-bill-service
|
||||
resources:
|
||||
requests:
|
||||
cpu: 256m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1024m
|
||||
memory: 1024Mi
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: 8082
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
failureThreshold: 6
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health/readiness
|
||||
port: 8082
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
failureThreshold: 3
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health/liveness
|
||||
port: 8082
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
failureThreshold: 3
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-bill-service
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
DB_HOST: "bill-inquiry-postgres-dev-postgresql"
|
||||
DB_NAME: "bill_inquiry_db"
|
||||
DB_USERNAME: "bill_inquiry_user"
|
||||
DB_PASSWORD: "BillUser2025!"
|
||||
@@ -1,12 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: bill-service
|
||||
|
||||
spec:
|
||||
selector:
|
||||
app: bill-service
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8082
|
||||
type: ClusterIP
|
||||
@@ -1,12 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm-common
|
||||
|
||||
data:
|
||||
CORS_ALLOWED_ORIGINS: "http://localhost:8081,http://localhost:8082,http://localhost:8083,http://localhost:8084,http://phonebill.20.214.196.128.nip.io"
|
||||
JWT_ACCESS_TOKEN_VALIDITY: "18000000"
|
||||
JWT_REFRESH_TOKEN_VALIDITY: "86400000"
|
||||
REDIS_PORT: "6379"
|
||||
SPRING_PROFILES_ACTIVE: "dev"
|
||||
DDL_AUTO: "update"
|
||||
@@ -1,49 +0,0 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: phonebill
|
||||
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "false"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: phonebill-api.20.214.196.128.nip.io
|
||||
http:
|
||||
paths:
|
||||
- path: /api/v1/auth
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: user-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/users
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: user-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/bills
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: bill-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/products
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: product-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/kos
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: kos-mock
|
||||
port:
|
||||
number: 80
|
||||
@@ -1,10 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-common
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
JWT_SECRET: "nwe5Yo9qaJ6FBD/Thl2/j6/SFAfNwUorAY1ZcWO2KI7uA4bmVLOCPxE9hYuUpRCOkgV2UF2DdHXtqHi3+BU/ecbz2zpHyf/720h48UbA3XOMYOX1sdM+dQ=="
|
||||
REDIS_HOST: "redis-cache-dev-master"
|
||||
REDIS_PASSWORD: "Redis2025Dev!"
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: phonebill
|
||||
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
stringData:
|
||||
.dockerconfigjson: |
|
||||
{
|
||||
"auths": {
|
||||
"acrdigitalgarage01.azurecr.io": {
|
||||
"username": "acrdigitalgarage01",
|
||||
"password": "+OY+rmOagorjWvQe/tTk6oqvnZI8SmNbY/Y2o5EDcY+ACRDCDbYk",
|
||||
"auth": "YWNyZGlnaXRhbGdhcmFnZTAxOitPWStybU9hZ29yald2UWUvdFRrNm9xdm5aSThTbU5iWS9ZMm81RURjWStBQ1JEQ0RiWWs="
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm-kos-mock
|
||||
|
||||
data:
|
||||
SERVER_PORT: "8084"
|
||||
@@ -1,58 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: kos-mock
|
||||
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: kos-mock
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: kos-mock
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: phonebill
|
||||
containers:
|
||||
- name: kos-mock
|
||||
image: acrdigitalgarage01.azurecr.io/phonebill/kos-mock:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8084
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: cm-common
|
||||
- configMapRef:
|
||||
name: cm-kos-mock
|
||||
- secretRef:
|
||||
name: secret-common
|
||||
resources:
|
||||
requests:
|
||||
cpu: 256m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1024m
|
||||
memory: 1024Mi
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: 8084
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
failureThreshold: 6
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health/readiness
|
||||
port: 8084
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
failureThreshold: 3
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health/liveness
|
||||
port: 8084
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
failureThreshold: 3
|
||||
@@ -1,12 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: kos-mock
|
||||
|
||||
spec:
|
||||
selector:
|
||||
app: kos-mock
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8084
|
||||
type: ClusterIP
|
||||
@@ -1,53 +0,0 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
metadata:
|
||||
name: phonebill-base
|
||||
|
||||
resources:
|
||||
|
||||
# Common resources
|
||||
- common/cm-common.yaml
|
||||
- common/secret-common.yaml
|
||||
- common/secret-imagepull.yaml
|
||||
- common/ingress.yaml
|
||||
|
||||
# api-gateway
|
||||
- api-gateway/deployment.yaml
|
||||
- api-gateway/service.yaml
|
||||
- api-gateway/cm-api-gateway.yaml
|
||||
|
||||
# user-service
|
||||
- user-service/deployment.yaml
|
||||
- user-service/service.yaml
|
||||
- user-service/cm-user-service.yaml
|
||||
- user-service/secret-user-service.yaml
|
||||
|
||||
# bill-service
|
||||
- bill-service/deployment.yaml
|
||||
- bill-service/service.yaml
|
||||
- bill-service/cm-bill-service.yaml
|
||||
- bill-service/secret-bill-service.yaml
|
||||
|
||||
# product-service
|
||||
- product-service/deployment.yaml
|
||||
- product-service/service.yaml
|
||||
- product-service/cm-product-service.yaml
|
||||
- product-service/secret-product-service.yaml
|
||||
|
||||
# kos-mock
|
||||
- kos-mock/deployment.yaml
|
||||
- kos-mock/service.yaml
|
||||
- kos-mock/cm-kos-mock.yaml
|
||||
|
||||
images:
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/api-gateway
|
||||
newTag: latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/user-service
|
||||
newTag: latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/bill-service
|
||||
newTag: latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/product-service
|
||||
newTag: latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/kos-mock
|
||||
newTag: latest
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm-product-service
|
||||
|
||||
data:
|
||||
SERVER_PORT: "8083"
|
||||
DB_KIND: "postgresql"
|
||||
DB_PORT: "5432"
|
||||
KOS_BASE_URL: "http://kos-mock"
|
||||
REDIS_DATABASE: "2"
|
||||
@@ -1,60 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: product-service
|
||||
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: product-service
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: product-service
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: phonebill
|
||||
containers:
|
||||
- name: product-service
|
||||
image: acrdigitalgarage01.azurecr.io/phonebill/product-service:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8083
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: cm-common
|
||||
- configMapRef:
|
||||
name: cm-product-service
|
||||
- secretRef:
|
||||
name: secret-common
|
||||
- secretRef:
|
||||
name: secret-product-service
|
||||
resources:
|
||||
requests:
|
||||
cpu: 256m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1024m
|
||||
memory: 1024Mi
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: 8083
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
failureThreshold: 6
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health/readiness
|
||||
port: 8083
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
failureThreshold: 3
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health/liveness
|
||||
port: 8083
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
failureThreshold: 3
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-product-service
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
DB_HOST: "product-change-postgres-dev-postgresql"
|
||||
DB_NAME: "product_change_db"
|
||||
DB_USERNAME: "product_change_user"
|
||||
DB_PASSWORD: "ProductUser2025!"
|
||||
@@ -1,12 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: product-service
|
||||
|
||||
spec:
|
||||
selector:
|
||||
app: product-service
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8083
|
||||
type: ClusterIP
|
||||
@@ -1,12 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm-user-service
|
||||
|
||||
data:
|
||||
SERVER_PORT: "8081"
|
||||
DB_KIND: "postgresql"
|
||||
DB_PORT: "5432"
|
||||
DDL_AUTO: "update"
|
||||
REDIS_DATABASE: "0"
|
||||
SHOW_SQL: "true"
|
||||
@@ -1,60 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: user-service
|
||||
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: user-service
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: user-service
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: phonebill
|
||||
containers:
|
||||
- name: user-service
|
||||
image: acrdigitalgarage01.azurecr.io/phonebill/user-service:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: cm-common
|
||||
- configMapRef:
|
||||
name: cm-user-service
|
||||
- secretRef:
|
||||
name: secret-common
|
||||
- secretRef:
|
||||
name: secret-user-service
|
||||
resources:
|
||||
requests:
|
||||
cpu: 256m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1024m
|
||||
memory: 1024Mi
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: 8081
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
failureThreshold: 6
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health/readiness
|
||||
port: 8081
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
failureThreshold: 3
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health/liveness
|
||||
port: 8081
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
failureThreshold: 3
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-user-service
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
DB_HOST: "auth-postgres-dev-postgresql"
|
||||
DB_NAME: "phonebill_auth"
|
||||
DB_USERNAME: "auth_user"
|
||||
DB_PASSWORD: "AuthUser2025!"
|
||||
@@ -1,12 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: user-service
|
||||
|
||||
spec:
|
||||
selector:
|
||||
app: user-service
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8081
|
||||
type: ClusterIP
|
||||
@@ -1,12 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm-common
|
||||
|
||||
data:
|
||||
CORS_ALLOWED_ORIGINS: "http://localhost:8081,http://localhost:8082,http://localhost:8083,http://localhost:8084,http://phonebill-dg0500.20.214.196.128.nip.io"
|
||||
JWT_ACCESS_TOKEN_VALIDITY: "18000000"
|
||||
JWT_REFRESH_TOKEN_VALIDITY: "86400000"
|
||||
REDIS_PORT: "6379"
|
||||
SPRING_PROFILES_ACTIVE: "dev"
|
||||
DDL_AUTO: "update"
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: api-gateway
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: api-gateway
|
||||
resources:
|
||||
requests:
|
||||
cpu: 256m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1024m
|
||||
memory: 1024Mi
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: bill-service
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: bill-service
|
||||
resources:
|
||||
requests:
|
||||
cpu: 256m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1024m
|
||||
memory: 1024Mi
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: kos-mock
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: kos-mock
|
||||
resources:
|
||||
requests:
|
||||
cpu: 256m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1024m
|
||||
memory: 1024Mi
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: product-service
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: product-service
|
||||
resources:
|
||||
requests:
|
||||
cpu: 256m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1024m
|
||||
memory: 1024Mi
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: user-service
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: user-service
|
||||
resources:
|
||||
requests:
|
||||
cpu: 256m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1024m
|
||||
memory: 1024Mi
|
||||
@@ -1,48 +0,0 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: phonebill-ingress
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "false"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: phonebill-dg0500-api.20.214.196.128.nip.io
|
||||
http:
|
||||
paths:
|
||||
- path: /api/v1/auth
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: user-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/users
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: user-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/bills
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: bill-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/products
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: product-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/kos
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: kos-mock
|
||||
port:
|
||||
number: 80
|
||||
@@ -1,65 +0,0 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
namespace: phonebill-dg0500
|
||||
|
||||
resources:
|
||||
- ../../base
|
||||
|
||||
patches:
|
||||
- path: cm-common-patch.yaml
|
||||
target:
|
||||
kind: ConfigMap
|
||||
name: cm-common
|
||||
- path: deployment-api-gateway-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: api-gateway
|
||||
- path: deployment-user-service-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: user-service
|
||||
- path: deployment-bill-service-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: bill-service
|
||||
- path: deployment-product-service-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: product-service
|
||||
- path: deployment-kos-mock-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: kos-mock
|
||||
- path: ingress-patch.yaml
|
||||
target:
|
||||
kind: Ingress
|
||||
name: phonebill
|
||||
- path: secret-common-patch.yaml
|
||||
target:
|
||||
kind: Secret
|
||||
name: secret-common
|
||||
- path: secret-user-service-patch.yaml
|
||||
target:
|
||||
kind: Secret
|
||||
name: secret-user-service
|
||||
- path: secret-bill-service-patch.yaml
|
||||
target:
|
||||
kind: Secret
|
||||
name: secret-bill-service
|
||||
- path: secret-product-service-patch.yaml
|
||||
target:
|
||||
kind: Secret
|
||||
name: secret-product-service
|
||||
|
||||
images:
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/api-gateway
|
||||
newTag: dev-latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/user-service
|
||||
newTag: dev-latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/bill-service
|
||||
newTag: dev-latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/product-service
|
||||
newTag: dev-latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/kos-mock
|
||||
newTag: dev-latest
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-bill-service
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
DB_HOST: "bill-inquiry-postgres-dev-postgresql"
|
||||
DB_NAME: "bill_inquiry_db"
|
||||
DB_USERNAME: "bill_inquiry_user"
|
||||
DB_PASSWORD: "BillUser2025!"
|
||||
@@ -1,10 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-common
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
JWT_SECRET: "nwe5Yo9qaJ6FBD/Thl2/j6/SFAfNwUorAY1ZcWO2KI7uA4bmVLOCPxE9hYuUpRCOkgV2UF2DdHXtqHi3+BU/ecbz2zpHyf/720h48UbA3XOMYOX1sdM+dQ=="
|
||||
REDIS_HOST: "redis-cache-dev-master"
|
||||
REDIS_PASSWORD: "Redis2025Dev!"
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-product-service
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
DB_HOST: "product-change-postgres-dev-postgresql"
|
||||
DB_NAME: "product_change_db"
|
||||
DB_USERNAME: "product_change_user"
|
||||
DB_PASSWORD: "ProductUser2025!"
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-user-service
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
DB_HOST: "auth-postgres-dev-postgresql"
|
||||
DB_NAME: "phonebill_auth"
|
||||
DB_USERNAME: "auth_user"
|
||||
DB_PASSWORD: "AuthUser2025!"
|
||||
@@ -1,12 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm-common
|
||||
|
||||
data:
|
||||
CORS_ALLOWED_ORIGINS: "https://phonebill.example.com"
|
||||
JWT_ACCESS_TOKEN_VALIDITY: "3600000"
|
||||
JWT_REFRESH_TOKEN_VALIDITY: "86400000"
|
||||
REDIS_PORT: "6379"
|
||||
SPRING_PROFILES_ACTIVE: "prod"
|
||||
DDL_AUTO: "validate"
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: api-gateway
|
||||
spec:
|
||||
replicas: 3
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: api-gateway
|
||||
resources:
|
||||
requests:
|
||||
cpu: 1024m
|
||||
memory: 1024Mi
|
||||
limits:
|
||||
cpu: 4096m
|
||||
memory: 4096Mi
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: bill-service
|
||||
spec:
|
||||
replicas: 3
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: bill-service
|
||||
resources:
|
||||
requests:
|
||||
cpu: 1024m
|
||||
memory: 1024Mi
|
||||
limits:
|
||||
cpu: 4096m
|
||||
memory: 4096Mi
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: kos-mock
|
||||
spec:
|
||||
replicas: 3
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: kos-mock
|
||||
resources:
|
||||
requests:
|
||||
cpu: 1024m
|
||||
memory: 1024Mi
|
||||
limits:
|
||||
cpu: 4096m
|
||||
memory: 4096Mi
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: product-service
|
||||
spec:
|
||||
replicas: 3
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: product-service
|
||||
resources:
|
||||
requests:
|
||||
cpu: 1024m
|
||||
memory: 1024Mi
|
||||
limits:
|
||||
cpu: 4096m
|
||||
memory: 4096Mi
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: user-service
|
||||
spec:
|
||||
replicas: 3
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: user-service
|
||||
resources:
|
||||
requests:
|
||||
cpu: 1024m
|
||||
memory: 1024Mi
|
||||
limits:
|
||||
cpu: 4096m
|
||||
memory: 4096Mi
|
||||
@@ -1,54 +0,0 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: phonebill-ingress
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- phonebill.example.com
|
||||
secretName: phonebill-tls-secret
|
||||
rules:
|
||||
- host: phonebill.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /api/v1/auth
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: user-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/users
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: user-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/bills
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: bill-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/products
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: product-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/kos
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: kos-mock
|
||||
port:
|
||||
number: 80
|
||||
@@ -1,65 +0,0 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
namespace: phonebill-prod
|
||||
|
||||
resources:
|
||||
- ../../base
|
||||
|
||||
patches:
|
||||
- path: configmap-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: phonebill
|
||||
- path: deployment-api-gateway-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: api-gateway
|
||||
- path: deployment-user-service-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: user-service
|
||||
- path: deployment-bill-service-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: bill-service
|
||||
- path: deployment-product-service-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: product-service
|
||||
- path: deployment-kos-mock-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: kos-mock
|
||||
- path: secret-user-service-patch.yaml
|
||||
target:
|
||||
kind: Secret
|
||||
name: secret-user-service
|
||||
- path: secret-bill-service-patch.yaml
|
||||
target:
|
||||
kind: Secret
|
||||
name: secret-bill-service
|
||||
- path: secret-product-service-patch.yaml
|
||||
target:
|
||||
kind: Secret
|
||||
name: secret-product-service
|
||||
|
||||
images:
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/api-gateway
|
||||
newTag: prod-latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/user-service
|
||||
newTag: prod-latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/bill-service
|
||||
newTag: prod-latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/product-service
|
||||
newTag: prod-latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/kos-mock
|
||||
newTag: prod-latest
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-bill-service
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
DB_HOST: "bill-inquiry-postgres-prod-postgresql"
|
||||
DB_NAME: "bill_inquiry_db"
|
||||
DB_USERNAME: "bill_inquiry_user"
|
||||
DB_PASSWORD: "BillUserProd2025!"
|
||||
@@ -1,10 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-common
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
JWT_SECRET: "nwe5Yo9qaJ6FBD/Thl2/j6/SFAfNwUorAY1ZcWO2KI7uA4bmVLOCPxE9hYuUpRCOkgV2UF2DdHXtqHi3+BU/ecbz2zpHyf/720h48UbA3XOMYOX1sdM+dQ=="
|
||||
REDIS_HOST: "redis-cache-prod-master"
|
||||
REDIS_PASSWORD: "Redis2025Prod!"
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-product-service
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
DB_HOST: "product-change-postgres-prod-postgresql"
|
||||
DB_NAME: "product_change_db"
|
||||
DB_USERNAME: "product_change_user"
|
||||
DB_PASSWORD: "ProductUserProd2025!"
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-user-service
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
DB_HOST: "auth-postgres-prod-postgresql"
|
||||
DB_NAME: "phonebill_auth"
|
||||
DB_USERNAME: "auth_user"
|
||||
DB_PASSWORD: "AuthUserProd2025!"
|
||||
@@ -1,12 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm-common
|
||||
|
||||
data:
|
||||
CORS_ALLOWED_ORIGINS: "https://phonebill.example.com"
|
||||
JWT_ACCESS_TOKEN_VALIDITY: "18000000"
|
||||
JWT_REFRESH_TOKEN_VALIDITY: "86400000"
|
||||
REDIS_PORT: "6379"
|
||||
SPRING_PROFILES_ACTIVE: "staging"
|
||||
DDL_AUTO: "validate"
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: api-gateway
|
||||
spec:
|
||||
replicas: 2
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: api-gateway
|
||||
resources:
|
||||
requests:
|
||||
cpu: 512m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 2048m
|
||||
memory: 2048Mi
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: bill-service
|
||||
spec:
|
||||
replicas: 2
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: bill-service
|
||||
resources:
|
||||
requests:
|
||||
cpu: 512m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 2048m
|
||||
memory: 2048Mi
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: kos-mock
|
||||
spec:
|
||||
replicas: 2
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: kos-mock
|
||||
resources:
|
||||
requests:
|
||||
cpu: 512m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 2048m
|
||||
memory: 2048Mi
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: product-service
|
||||
spec:
|
||||
replicas: 2
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: product-service
|
||||
resources:
|
||||
requests:
|
||||
cpu: 512m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 2048m
|
||||
memory: 2048Mi
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: user-service
|
||||
spec:
|
||||
replicas: 2
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: user-service
|
||||
resources:
|
||||
requests:
|
||||
cpu: 512m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
cpu: 2048m
|
||||
memory: 2048Mi
|
||||
@@ -1,53 +0,0 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: phonebill
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- phonebill.example.com
|
||||
secretName: phonebill-tls-cert
|
||||
rules:
|
||||
- host: phonebill.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /api/v1/auth
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: user-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/users
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: user-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/bills
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: bill-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/products
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: product-service
|
||||
port:
|
||||
number: 80
|
||||
- path: /api/v1/kos
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: kos-mock
|
||||
port:
|
||||
number: 80
|
||||
@@ -1,65 +0,0 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
namespace: phonebill-staging
|
||||
|
||||
resources:
|
||||
- ../../base
|
||||
|
||||
patches:
|
||||
- path: configmap-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: phonebill
|
||||
- path: deployment-api-gateway-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: api-gateway
|
||||
- path: deployment-user-service-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: user-service
|
||||
- path: deployment-bill-service-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: bill-service
|
||||
- path: deployment-product-service-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: product-service
|
||||
- path: deployment-kos-mock-patch.yaml
|
||||
target:
|
||||
kind: Deployment
|
||||
name: kos-mock
|
||||
- path: secret-user-service-patch.yaml
|
||||
target:
|
||||
kind: Secret
|
||||
name: secret-user-service
|
||||
- path: secret-bill-service-patch.yaml
|
||||
target:
|
||||
kind: Secret
|
||||
name: secret-bill-service
|
||||
- path: secret-product-service-patch.yaml
|
||||
target:
|
||||
kind: Secret
|
||||
name: secret-product-service
|
||||
|
||||
images:
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/api-gateway
|
||||
newTag: staging-latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/user-service
|
||||
newTag: staging-latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/bill-service
|
||||
newTag: staging-latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/product-service
|
||||
newTag: staging-latest
|
||||
- name: acrdigitalgarage01.azurecr.io/phonebill/kos-mock
|
||||
newTag: staging-latest
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-bill-service
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
DB_HOST: "bill-inquiry-postgres-staging-postgresql"
|
||||
DB_NAME: "bill_inquiry_db"
|
||||
DB_USERNAME: "bill_inquiry_user"
|
||||
DB_PASSWORD: "BillUser2025Staging!"
|
||||
@@ -1,10 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-common
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
JWT_SECRET: "nwe5Yo9qaJ6FBD/Thl2/j6/SFAfNwUorAY1ZcWO2KI7uA4bmVLOCPxE9hYuUpRCOkgV2UF2DdHXtqHi3+BU/ecbz2zpHyf/720h48UbA3XOMYOX1sdM+dQ=="
|
||||
REDIS_HOST: "redis-cache-staging-master"
|
||||
REDIS_PASSWORD: "Redis2025Staging!"
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-product-service
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
DB_HOST: "product-change-postgres-staging-postgresql"
|
||||
DB_NAME: "product_change_db"
|
||||
DB_USERNAME: "product_change_user"
|
||||
DB_PASSWORD: "ProductUser2025Staging!"
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: secret-user-service
|
||||
|
||||
type: Opaque
|
||||
stringData:
|
||||
DB_HOST: "auth-postgres-staging-postgresql"
|
||||
DB_NAME: "phonebill_auth"
|
||||
DB_USERNAME: "auth_user"
|
||||
DB_PASSWORD: "AuthUser2025Staging!"
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
ENVIRONMENT=${1:-dev}
|
||||
IMAGE_TAG=${2:-latest}
|
||||
|
||||
echo "🚀 Starting deployment for environment: $ENVIRONMENT with image tag: $IMAGE_TAG"
|
||||
|
||||
# 환경별 이미지 태그 업데이트
|
||||
cd deployment/cicd/kustomize/overlays/${ENVIRONMENT}
|
||||
|
||||
# 서비스 목록 (공백으로 구분)
|
||||
services="api-gateway user-service bill-service product-service kos-mock"
|
||||
|
||||
# 각 서비스 이미지 태그 업데이트
|
||||
for service in $services; do
|
||||
echo "📦 Updating image tag for $service to ${ENVIRONMENT}-${IMAGE_TAG}"
|
||||
kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/$service:${ENVIRONMENT}-${IMAGE_TAG}
|
||||
done
|
||||
|
||||
# 배포 실행
|
||||
echo "🔧 Applying manifests to Kubernetes cluster..."
|
||||
kubectl apply -k .
|
||||
|
||||
# 배포 상태 확인
|
||||
echo "⏳ Waiting for deployments to be ready..."
|
||||
for service in $services; do
|
||||
echo " Checking $service..."
|
||||
kubectl rollout status deployment/$service -n phonebill-${ENVIRONMENT} --timeout=300s
|
||||
done
|
||||
|
||||
echo "✅ Deployment completed successfully!"
|
||||
echo "🌐 Application endpoints:"
|
||||
kubectl get ingress -n phonebill-${ENVIRONMENT} -o wide
|
||||
@@ -1,128 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Base 리소스 누락 검증 스크립트 (범용)
|
||||
|
||||
echo "🔍 phonebill Base 리소스 누락 검증 시작..."
|
||||
|
||||
BASE_DIR="deployment/cicd/kustomize/base"
|
||||
MISSING_RESOURCES=0
|
||||
REQUIRED_FILES=("deployment.yaml" "service.yaml")
|
||||
OPTIONAL_FILES=("cm-" "secret-")
|
||||
|
||||
# 1. 각 서비스 디렉토리의 파일 확인
|
||||
echo "1. 서비스 디렉토리별 파일 목록:"
|
||||
for dir in $BASE_DIR/*/; do
|
||||
if [ -d "$dir" ] && [[ $(basename "$dir") != "common" ]]; then
|
||||
service=$(basename "$dir")
|
||||
echo "=== $service ==="
|
||||
|
||||
# 필수 파일 확인
|
||||
for required in "${REQUIRED_FILES[@]}"; do
|
||||
if [ -f "$dir$required" ]; then
|
||||
echo " ✅ $required"
|
||||
else
|
||||
echo " ❌ MISSING REQUIRED: $required"
|
||||
((MISSING_RESOURCES++))
|
||||
fi
|
||||
done
|
||||
|
||||
# 선택적 파일 확인
|
||||
for optional in "${OPTIONAL_FILES[@]}"; do
|
||||
files=($(ls "$dir"$optional*".yaml" 2>/dev/null))
|
||||
if [ ${#files[@]} -gt 0 ]; then
|
||||
for file in "${files[@]}"; do
|
||||
echo " ✅ $(basename "$file")"
|
||||
done
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
|
||||
# 2. Common 리소스 확인
|
||||
echo "2. Common 리소스 확인:"
|
||||
COMMON_DIR="$BASE_DIR/common"
|
||||
if [ -d "$COMMON_DIR" ]; then
|
||||
common_files=($(ls "$COMMON_DIR"/*.yaml 2>/dev/null))
|
||||
if [ ${#common_files[@]} -gt 0 ]; then
|
||||
for file in "${common_files[@]}"; do
|
||||
echo " ✅ common/$(basename "$file")"
|
||||
done
|
||||
else
|
||||
echo " ❌ Common 디렉토리에 YAML 파일이 없습니다"
|
||||
((MISSING_RESOURCES++))
|
||||
fi
|
||||
else
|
||||
echo " ❌ Common 디렉토리가 없습니다"
|
||||
((MISSING_RESOURCES++))
|
||||
fi
|
||||
|
||||
# 3. kustomization.yaml과 실제 파일 비교
|
||||
echo ""
|
||||
echo "3. kustomization.yaml 리소스 검증:"
|
||||
if [ -f "$BASE_DIR/kustomization.yaml" ]; then
|
||||
while IFS= read -r line; do
|
||||
# resources 섹션의 YAML 파일 경로 추출
|
||||
if [[ $line =~ ^[[:space:]]*-[[:space:]]*([^#]+\.yaml)[[:space:]]*$ ]]; then
|
||||
resource_path=$(echo "${BASH_REMATCH[1]}" | xargs) # 공백 제거
|
||||
full_path="$BASE_DIR/$resource_path"
|
||||
if [ -f "$full_path" ]; then
|
||||
echo " ✅ $resource_path"
|
||||
else
|
||||
echo " ❌ MISSING: $resource_path"
|
||||
((MISSING_RESOURCES++))
|
||||
fi
|
||||
fi
|
||||
done < "$BASE_DIR/kustomization.yaml"
|
||||
else
|
||||
echo " ❌ kustomization.yaml 파일이 없습니다"
|
||||
((MISSING_RESOURCES++))
|
||||
fi
|
||||
|
||||
# 4. kubectl kustomize 검증
|
||||
echo ""
|
||||
echo "4. Kustomize 빌드 테스트:"
|
||||
if kubectl kustomize "$BASE_DIR" > /dev/null 2>&1; then
|
||||
echo " ✅ Base kustomization 빌드 성공"
|
||||
else
|
||||
echo " ❌ Base kustomization 빌드 실패:"
|
||||
kubectl kustomize "$BASE_DIR" 2>&1 | head -5 | sed 's/^/ /'
|
||||
((MISSING_RESOURCES++))
|
||||
fi
|
||||
|
||||
# 5. 환경별 overlay 검증
|
||||
echo ""
|
||||
echo "5. 환경별 Overlay 검증:"
|
||||
for env in dev staging prod; do
|
||||
overlay_dir="deployment/cicd/kustomize/overlays/$env"
|
||||
if [ -d "$overlay_dir" ] && [ -f "$overlay_dir/kustomization.yaml" ]; then
|
||||
if kubectl kustomize "$overlay_dir" > /dev/null 2>&1; then
|
||||
echo " ✅ $env 환경 빌드 성공"
|
||||
else
|
||||
echo " ❌ $env 환경 빌드 실패"
|
||||
((MISSING_RESOURCES++))
|
||||
fi
|
||||
else
|
||||
echo " ⚠️ $env 환경 설정 없음 (선택사항)"
|
||||
fi
|
||||
done
|
||||
|
||||
# 결과 출력
|
||||
echo ""
|
||||
echo "======================================"
|
||||
if [ $MISSING_RESOURCES -eq 0 ]; then
|
||||
echo "🎯 검증 완료! 모든 리소스가 정상입니다."
|
||||
echo "======================================"
|
||||
exit 0
|
||||
else
|
||||
echo "❌ $MISSING_RESOURCES개의 문제가 발견되었습니다."
|
||||
echo "======================================"
|
||||
echo ""
|
||||
echo "💡 문제 해결 가이드:"
|
||||
echo "1. 누락된 파일들을 base 디렉토리에 추가하세요"
|
||||
echo "2. kustomization.yaml에서 존재하지 않는 파일 참조를 제거하세요"
|
||||
echo "3. 파일명이 명명 규칙을 따르는지 확인하세요:"
|
||||
echo " - ConfigMap: cm-{서비스명}.yaml"
|
||||
echo " - Secret: secret-{서비스명}.yaml"
|
||||
echo "4. 다시 검증: ./deployment/cicd/scripts/validate-cicd-setup.sh"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user