diff --git a/deployment/cicd/Jenkinsfile b/deployment/cicd/Jenkinsfile index 927c4a3..b1bc636 100644 --- a/deployment/cicd/Jenkinsfile +++ b/deployment/cicd/Jenkinsfile @@ -1,425 +1,149 @@ -#!/usr/bin/env groovy +def PIPELINE_ID = "${env.BUILD_NUMBER}" -/** - * Jenkins Pipeline for phonebill Microservices - * Supports multi-environment deployment (dev, staging, prod) - * Services: api-gateway, user-service, bill-service, product-service, kos-mock - */ +def getImageTag() { + def dateFormat = new java.text.SimpleDateFormat('yyyyMMddHHmmss') + def currentDate = new Date() + return dateFormat.format(currentDate) +} -pipeline { - agent { - kubernetes { - yaml ''' -apiVersion: v1 -kind: Pod -metadata: - labels: - jenkins: agent -spec: - serviceAccountName: jenkins-agent - containers: - - name: gradle - image: gradle:8.5-jdk17 - command: - - cat - tty: true - resources: - requests: - memory: "1Gi" - cpu: "500m" - limits: - memory: "2Gi" - cpu: "1" - volumeMounts: - - name: gradle-cache - mountPath: /home/gradle/.gradle - - name: podman - image: quay.io/podman/stable:latest - command: - - cat - tty: true - securityContext: - privileged: true - resources: - requests: - memory: "1Gi" - cpu: "500m" - limits: - memory: "2Gi" - cpu: "1" - - name: azure-cli - image: mcr.microsoft.com/azure-cli:latest - command: - - cat - tty: true - resources: - requests: - memory: "512Mi" - cpu: "250m" - limits: - memory: "1Gi" - cpu: "500m" - - name: kubectl - image: bitnami/kubectl:latest - command: - - cat - tty: true - resources: - requests: - memory: "256Mi" - cpu: "100m" - limits: - memory: "512Mi" - cpu: "250m" - volumes: - - name: gradle-cache - persistentVolumeClaim: - claimName: jenkins-gradle-cache - ''' +podTemplate( + label: "${PIPELINE_ID}", + serviceAccount: 'jenkins', + containers: [ + containerTemplate(name: 'podman', image: "mgoltzsche/podman", ttyEnabled: true, command: 'cat', privileged: true), + containerTemplate(name: 'gradle', image: 'gradle:jdk17', ttyEnabled: true, command: 'cat'), + containerTemplate(name: 'azure-cli', image: 'hiondal/azure-kubectl:latest', command: 'cat', ttyEnabled: true) + ] +) { + node(PIPELINE_ID) { + def props + def imageTag = getImageTag() + def environment = params.ENVIRONMENT ?: 'dev' + def services = ['api-gateway', 'user-service', 'bill-service', 'product-service', 'kos-mock'] + + stage("Get Source") { + checkout scm + props = readProperties file: "deployment/cicd/config/deploy_env_vars_${environment}" } - } - - parameters { - choice( - name: 'ENVIRONMENT', - choices: ['dev', 'staging', 'prod'], - description: 'Target deployment environment' - ) - choice( - name: 'SERVICES_TO_BUILD', - choices: ['all', 'api-gateway', 'user-service', 'bill-service', 'product-service', 'kos-mock'], - description: 'Services to build and deploy' - ) - booleanParam( - name: 'SKIP_TESTS', - defaultValue: false, - description: 'Skip unit tests during build' - ) - booleanParam( - name: 'SKIP_SONAR', - defaultValue: false, - description: 'Skip SonarQube analysis' - ) - booleanParam( - name: 'FORCE_DEPLOY', - defaultValue: false, - description: 'Force deployment even if no changes detected' - ) - } - - environment { - // Load environment-specific variables - CONFIG_FILE = "deployment/cicd/config/deploy_env_vars_${params.ENVIRONMENT}" - - // Build configuration - GRADLE_USER_HOME = '/home/gradle/.gradle' - GRADLE_OPTS = '-Xmx2048m -XX:MaxPermSize=512m' - - // Azure credentials - AZURE_CREDENTIALS = credentials('azure-service-principal') - ACR_CREDENTIALS = credentials('acr-credentials') - - // SonarQube - SONAR_TOKEN = credentials('sonarqube-token') - - // Slack notification - SLACK_TOKEN = credentials('slack-token') - } - - stages { - stage('Initialize') { - steps { - script { - echo "๐Ÿš€ Starting phonebill pipeline for ${params.ENVIRONMENT} environment" - - // Load environment-specific configuration - if (fileExists(env.CONFIG_FILE)) { - def props = readProperties file: env.CONFIG_FILE - props.each { key, value -> - env[key] = value - } - echo "โœ… Loaded configuration from ${env.CONFIG_FILE}" - } else { - error "โŒ Configuration file not found: ${env.CONFIG_FILE}" - } - - // Set services to build - if (params.SERVICES_TO_BUILD == 'all') { - env.SERVICES_LIST = env.SERVICES - } else { - env.SERVICES_LIST = params.SERVICES_TO_BUILD - } - - echo "๐ŸŽฏ Services to build: ${env.SERVICES_LIST}" - echo "๐Ÿ“ฆ Target namespace: ${env.AKS_NAMESPACE}" + + 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-\${environment} --dry-run=client -o yaml | kubectl apply -f - + """ } } } - - stage('Checkout & Prepare') { - steps { - checkout scm - script { - env.BUILD_TIMESTAMP = sh( - script: 'date +%Y%m%d-%H%M%S', - returnStdout: true - ).trim() - - env.IMAGE_TAG = "${env.BUILD_NUMBER}-${params.ENVIRONMENT}-${env.BUILD_TIMESTAMP}" - echo "๐Ÿท๏ธ Image tag: ${env.IMAGE_TAG}" - } - } - } - - stage('Build & Test') { - parallel { - stage('Gradle Build') { - steps { - container('gradle') { - script { - def services = env.SERVICES_LIST.split(',') - for (service in services) { - echo "๐Ÿ”จ Building ${service}..." - - if (!params.SKIP_TESTS) { - sh """ - ./gradlew ${service}:clean ${service}:test ${service}:build \ - --no-daemon \ - --parallel \ - --build-cache - """ - } else { - sh """ - ./gradlew ${service}:clean ${service}:build -x test \ - --no-daemon \ - --parallel \ - --build-cache - """ - } - } - } - } - } - post { - always { - // Publish test results - script { - def services = env.SERVICES_LIST.split(',') - for (service in services) { - if (fileExists("${service}/build/test-results/test/*.xml")) { - publishTestResults( - testResultsPattern: "${service}/build/test-results/test/*.xml", - allowEmptyResults: true - ) - } - } - } - } - } - } - } - } - - stage('SonarQube Analysis') { - when { - not { params.SKIP_SONAR } - } - steps { - container('gradle') { - withSonarQubeEnv('SonarQube') { - sh ''' - ./gradlew sonarqube \ - -Dsonar.projectKey=${SONAR_PROJECT_KEY} \ - -Dsonar.sources=${SONAR_SOURCES} \ - -Dsonar.exclusions="${SONAR_EXCLUSIONS}" \ - --no-daemon - ''' - } - } - } - } - - stage('Quality Gate') { - when { - not { params.SKIP_SONAR } - } - steps { - timeout(time: 5, unit: 'MINUTES') { - waitForQualityGate abortPipeline: true - } - } - } - - stage('Container Build & Push') { - parallel { - stage('Build Images') { - steps { - container('podman') { - script { - // Login to ACR - sh """ - echo "${ACR_CREDENTIALS_PSW}" | podman login \ - --username "${ACR_CREDENTIALS_USR}" \ - --password-stdin \ - ${REGISTRY_URL} - """ - - def services = env.SERVICES_LIST.split(',') - for (service in services) { - echo "๐Ÿณ Building container image for ${service}..." - - sh """ - cd ${service} - podman build \ - --tag ${REGISTRY_URL}/phonebill/${service}:${IMAGE_TAG} \ - --tag ${REGISTRY_URL}/phonebill/${service}:latest-${params.ENVIRONMENT} \ - --file Dockerfile \ - . - - podman push ${REGISTRY_URL}/phonebill/${service}:${IMAGE_TAG} - podman push ${REGISTRY_URL}/phonebill/${service}:latest-${params.ENVIRONMENT} - """ - } - } - } - } - } - } - } - - stage('Deploy to Kubernetes') { - steps { - container('kubectl') { - script { - // Login to Azure and get AKS credentials - sh """ - az login --service-principal \ - --username "${AZURE_CREDENTIALS_USR}" \ - --password "${AZURE_CREDENTIALS_PSW}" \ - --tenant "${AZURE_CREDENTIALS_TENANT_ID}" - - az aks get-credentials \ - --resource-group ${AZURE_RESOURCE_GROUP} \ - --name ${AKS_CLUSTER_NAME} \ - --overwrite-existing - """ + + stage('Build & SonarQube Analysis') { + container('gradle') { + withSonarQubeEnv('SonarQube') { + sh """ + chmod +x gradlew + ./gradlew build -x test - // Deploy services using kustomize - def services = env.SERVICES_LIST.split(',') - for (service in services) { - echo "๐Ÿš€ Deploying ${service} to ${params.ENVIRONMENT}..." + # ๊ฐ ์„œ๋น„์Šค๋ณ„ ํ…Œ์ŠคํŠธ ๋ฐ ๋ถ„์„ + ./gradlew :api-gateway:test :api-gateway:jacocoTestReport :api-gateway:sonar \\ + -Dsonar.projectKey=phonebill-api-gateway-\${environment} \\ + -Dsonar.projectName=phonebill-api-gateway + + ./gradlew :user-service:test :user-service:jacocoTestReport :user-service:sonar \\ + -Dsonar.projectKey=phonebill-user-service-\${environment} \\ + -Dsonar.projectName=phonebill-user-service - sh """ - cd ${KUSTOMIZE_BASE}/${service} - - # Update image tag in kustomization.yaml - sed -i 's|newTag:.*|newTag: ${IMAGE_TAG}|' ${KUSTOMIZE_OVERLAY}/kustomization.yaml - - # Apply deployment - kubectl apply -k ${KUSTOMIZE_OVERLAY} -n ${AKS_NAMESPACE} - - # Wait for rollout - kubectl rollout status deployment/${service} -n ${AKS_NAMESPACE} --timeout=300s - """ - } + ./gradlew :bill-service:test :bill-service:jacocoTestReport :bill-service:sonar \\ + -Dsonar.projectKey=phonebill-bill-service-\${environment} \\ + -Dsonar.projectName=phonebill-bill-service + + ./gradlew :product-service:test :product-service:jacocoTestReport :product-service:sonar \\ + -Dsonar.projectKey=phonebill-product-service-\${environment} \\ + -Dsonar.projectName=phonebill-product-service + + ./gradlew :kos-mock:test :kos-mock:jacocoTestReport :kos-mock:sonar \\ + -Dsonar.projectKey=phonebill-kos-mock-\${environment} \\ + -Dsonar.projectName=phonebill-kos-mock + """ + } + } + } + + stage('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') { + container('podman') { + withCredentials([usernamePassword( + credentialsId: 'acr-credentials', + usernameVariable: 'USERNAME', + passwordVariable: 'PASSWORD' + )]) { + sh "podman login acrdigitalgarage01.azurecr.io --username \$USERNAME --password \$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 \\ + -t acrdigitalgarage01.azurecr.io/phonebill/\${service}:\${environment}-\${imageTag} . + + podman push acrdigitalgarage01.azurecr.io/phonebill/\${service}:\${environment}-\${imageTag} + """ } } } } - + + stage('Update Kustomize & Deploy') { + container('azure-cli') { + sh """ + # Kustomize ์„ค์น˜ + curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash + sudo mv kustomize /usr/local/bin/ + + # ํ™˜๊ฒฝ๋ณ„ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™ + cd deployment/cicd/kustomize/overlays/\${environment} + + # ์ด๋ฏธ์ง€ ํƒœ๊ทธ ์—…๋ฐ์ดํŠธ + kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/api-gateway:\${environment}-\${imageTag} + kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/user-service:\${environment}-\${imageTag} + kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/bill-service:\${environment}-\${imageTag} + kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/product-service:\${environment}-\${imageTag} + kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/kos-mock:\${environment}-\${imageTag} + + # ๋งค๋‹ˆํŽ˜์ŠคํŠธ ์ ์šฉ + kubectl apply -k . + + echo "Waiting for deployments to be ready..." + kubectl -n phonebill-\${environment} wait --for=condition=available deployment/\${environment}-api-gateway --timeout=300s + kubectl -n phonebill-\${environment} wait --for=condition=available deployment/\${environment}-user-service --timeout=300s + kubectl -n phonebill-\${environment} wait --for=condition=available deployment/\${environment}-bill-service --timeout=300s + kubectl -n phonebill-\${environment} wait --for=condition=available deployment/\${environment}-product-service --timeout=300s + kubectl -n phonebill-\${environment} wait --for=condition=available deployment/\${environment}-kos-mock --timeout=300s + """ + } + } + stage('Health Check') { - steps { - container('kubectl') { - script { - def services = env.SERVICES_LIST.split(',') - for (service in services) { - echo "๐Ÿฅ Health checking ${service}..." - - retry(count: env.HEALTH_CHECK_RETRY as Integer) { - sh """ - kubectl get deployment ${service} -n ${AKS_NAMESPACE} -o json | \ - jq -e '.status.readyReplicas == .status.replicas and .status.replicas > 0' - """ - - sleep time: 30, unit: 'SECONDS' - } - - echo "โœ… ${service} is healthy" - } - } - } - } - } - } - - post { - always { - script { - // Archive build artifacts - archiveArtifacts( - artifacts: '**/build/libs/*.jar', - allowEmptyArchive: true, - fingerprint: true - ) - - // Clean workspace - cleanWs() - } - } - - success { - script { - def message = """ - โœ… *phonebill Deployment Successful* - โ€ข Environment: `${params.ENVIRONMENT}` - โ€ข Services: `${env.SERVICES_LIST}` - โ€ข Image Tag: `${env.IMAGE_TAG}` - โ€ข Build: `${env.BUILD_NUMBER}` - โ€ข Duration: `${currentBuild.durationString}` - """.stripIndent() - - // Send Slack notification - slackSend( - channel: env.SLACK_CHANNEL, - color: 'good', - message: message, - token: env.SLACK_TOKEN - ) - - // Send email notification - emailext( - subject: "โœ… phonebill Deployment Success - ${params.ENVIRONMENT}", - body: message, - to: env.EMAIL_RECIPIENTS - ) - } - } - - failure { - script { - def message = """ - โŒ *phonebill Deployment Failed* - โ€ข Environment: `${params.ENVIRONMENT}` - โ€ข Services: `${env.SERVICES_LIST}` - โ€ข Build: `${env.BUILD_NUMBER}` - โ€ข Error: `${currentBuild.result}` - โ€ข Console: ${env.BUILD_URL}console - """.stripIndent() - - // Send Slack notification - slackSend( - channel: env.SLACK_CHANNEL, - color: 'danger', - message: message, - token: env.SLACK_TOKEN - ) - - // Send email notification - emailext( - subject: "โŒ phonebill Deployment Failed - ${params.ENVIRONMENT}", - body: message, - to: env.EMAIL_RECIPIENTS - ) + container('azure-cli') { + sh """ + echo "๐Ÿ” Health Check starting..." + + # API Gateway Health Check + GATEWAY_POD=\$(kubectl get pod -n phonebill-\${environment} -l app=api-gateway -o jsonpath='{.items[0].metadata.name}') + kubectl -n phonebill-\${environment} exec \$GATEWAY_POD -- curl -f http://localhost:8080/actuator/health || exit 1 + + echo "โœ… All services are healthy!" + """ } } } diff --git a/deployment/cicd/README.md b/deployment/cicd/README.md deleted file mode 100644 index 9ef4685..0000000 --- a/deployment/cicd/README.md +++ /dev/null @@ -1,77 +0,0 @@ -# Phonebill CI/CD ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ - -## ๊ฐœ์š” -์ด ๋””๋ ‰ํ† ๋ฆฌ๋Š” Phonebill ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค์˜ CI/CD ํŒŒ์ดํ”„๋ผ์ธ์„ ์œ„ํ•œ Kustomize ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. - -## ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ - -``` -deployment/cicd/ -โ”œโ”€โ”€ kustomize/ -โ”‚ โ”œโ”€โ”€ base/ # Base ๋งค๋‹ˆํŽ˜์ŠคํŠธ (ํ™˜๊ฒฝ ๋…๋ฆฝ์ ) -โ”‚ โ”‚ โ”œโ”€โ”€ common/ # ๊ณตํ†ต ๋ฆฌ์†Œ์Šค (Ingress, Secret ๋“ฑ) -โ”‚ โ”‚ โ”œโ”€โ”€ api-gateway/ # API Gateway ์„œ๋น„์Šค -โ”‚ โ”‚ โ”œโ”€โ”€ user-service/ # ์‚ฌ์šฉ์ž ์„œ๋น„์Šค -โ”‚ โ”‚ โ”œโ”€โ”€ bill-service/ # ์š”๊ธˆ ์กฐํšŒ ์„œ๋น„์Šค -โ”‚ โ”‚ โ”œโ”€โ”€ product-service/ # ์ƒํ’ˆ ๋ณ€๊ฒฝ ์„œ๋น„์Šค -โ”‚ โ”‚ โ”œโ”€โ”€ kos-mock/ # KOS Mock ์„œ๋น„์Šค -โ”‚ โ”‚ โ””โ”€โ”€ kustomization.yaml # Base ํ†ตํ•ฉ ์„ค์ • -โ”‚ โ””โ”€โ”€ overlays/ # ํ™˜๊ฒฝ๋ณ„ ์˜ค๋ฒ„๋ ˆ์ด -โ”‚ โ”œโ”€โ”€ dev/ # ๊ฐœ๋ฐœ ํ™˜๊ฒฝ -โ”‚ โ”œโ”€โ”€ staging/ # ์Šคํ…Œ์ด์ง• ํ™˜๊ฒฝ -โ”‚ โ””โ”€โ”€ prod/ # ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ -โ”œโ”€โ”€ config/ # CI/CD ์„ค์ • ํŒŒ์ผ -โ””โ”€โ”€ scripts/ # ๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ -``` - -## ์ฃผ์š” ํŠน์ง• - -### 1. ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๋ถ„๋ฆฌ -- **๊ฐœ๋ฐœ**: `phonebill-dev` -- **์Šคํ…Œ์ด์ง•**: `phonebill-staging` -- **ํ”„๋กœ๋•์…˜**: `phonebill-prod` - -### 2. ํ™˜๊ฒฝ๋ณ„ ๋ฆฌ์†Œ์Šค ์„ค์ • -- **๊ฐœ๋ฐœ**: ์ตœ์†Œ ๋ฆฌ์†Œ์Šค (CPU: 250m, Memory: 512Mi) -- **์Šคํ…Œ์ด์ง•**: ์ค‘๊ฐ„ ๋ฆฌ์†Œ์Šค, ๋ณต์ œ๋ณธ 2๊ฐœ -- **ํ”„๋กœ๋•์…˜**: ์ตœ๋Œ€ ๋ฆฌ์†Œ์Šค, ๋ณต์ œ๋ณธ 3๊ฐœ - -### 3. ์„œ๋น„์Šค ๊ตฌ์„ฑ -- **api-gateway**: API ๊ฒŒ์ดํŠธ์›จ์ด -- **user-service**: ์‚ฌ์šฉ์ž ์ธ์ฆ/๊ด€๋ฆฌ -- **bill-service**: ์š”๊ธˆ ์กฐํšŒ -- **product-service**: ์ƒํ’ˆ ๋ณ€๊ฒฝ -- **kos-mock**: KOS ์‹œ์Šคํ…œ ๋ชจํ‚น - -## ์‚ฌ์šฉ ๋ฐฉ๋ฒ• - -### ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ๋ฐฐํฌ -```bash -kubectl apply -k deployment/cicd/kustomize/overlays/dev -``` - -### ์Šคํ…Œ์ด์ง• ํ™˜๊ฒฝ ๋ฐฐํฌ -```bash -kubectl apply -k deployment/cicd/kustomize/overlays/staging -``` - -### ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ ๋ฐฐํฌ -```bash -kubectl apply -k deployment/cicd/kustomize/overlays/prod -``` - -### ๋งค๋‹ˆํŽ˜์ŠคํŠธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ -```bash -kubectl kustomize deployment/cicd/kustomize/overlays/dev -``` - -## ์ฃผ์š” ๋ณ€๊ฒฝ์‚ฌํ•ญ -1. ๊ธฐ์กด `deployment/k8s/` ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ `base/`๋กœ ๋ณต์‚ฌ -2. ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ œ๊ฑฐ (`phonebill-dev`) -3. ํ™˜๊ฒฝ๋ณ„ ์˜ค๋ฒ„๋ ˆ์ด ๊ตฌ์กฐ ์ ์šฉ -4. ๋ฆฌ์†Œ์Šค ์ œํ•œ ๋ฐ ๋ณต์ œ๋ณธ ์ˆ˜ ํ™˜๊ฒฝ๋ณ„ ์ฐจ๋ณ„ํ™” - -## Azure ์—ฐ๋™ ์ •๋ณด -- **ACR**: acrdigitalgarage01 -- **๋ฆฌ์†Œ์Šค๊ทธ๋ฃน**: rg-digitalgarage-01 -- **AKSํด๋Ÿฌ์Šคํ„ฐ**: aks-digitalgarage-01 \ No newline at end of file diff --git a/deployment/cicd/config/deploy_env_vars_dev b/deployment/cicd/config/deploy_env_vars_dev index a9611b7..d2b1855 100644 --- a/deployment/cicd/config/deploy_env_vars_dev +++ b/deployment/cicd/config/deploy_env_vars_dev @@ -1,34 +1,3 @@ -# Development Environment Configuration for phonebill -# Jenkins Pipeline Environment Variables - -# Azure Configuration -AZURE_RESOURCE_GROUP=rg-digitalgarage-01 -ACR_NAME=acrdigitalgarage01 -AKS_CLUSTER_NAME=aks-digitalgarage-01 -AKS_NAMESPACE=phonebill-dev - -# Service Names -SERVICES=api-gateway,user-service,bill-service,product-service,kos-mock - -# Build Configuration -GRADLE_OPTS="-Xmx2048m -XX:MaxPermSize=512m" -JAVA_OPTS="-Xmx1024m -Xms512m" - -# Docker Configuration -REGISTRY_URL=${ACR_NAME}.azurecr.io -IMAGE_TAG_PATTERN=${BUILD_NUMBER}-dev - -# Deployment Configuration -KUSTOMIZE_BASE=deployment/k8s -KUSTOMIZE_OVERLAY=overlays/dev -HEALTH_CHECK_TIMEOUT=300 -HEALTH_CHECK_RETRY=10 - -# SonarQube Configuration -SONAR_PROJECT_KEY=phonebill-dev -SONAR_SOURCES=. -SONAR_EXCLUSIONS=**/target/**,**/build/**,**/*.generated.java - -# Notification Configuration -SLACK_CHANNEL=#phonebill-dev -EMAIL_RECIPIENTS=dev-team@company.com \ No newline at end of file +# DEV Environment Configuration +resource_group=rg-digitalgarage-01 +cluster_name=aks-digitalgarage-01 \ No newline at end of file diff --git a/deployment/cicd/config/deploy_env_vars_prod b/deployment/cicd/config/deploy_env_vars_prod index bf0282f..f0c04c4 100644 --- a/deployment/cicd/config/deploy_env_vars_prod +++ b/deployment/cicd/config/deploy_env_vars_prod @@ -1,34 +1,3 @@ -# Production Environment Configuration for phonebill -# Jenkins Pipeline Environment Variables - -# Azure Configuration -AZURE_RESOURCE_GROUP=rg-digitalgarage-01 -ACR_NAME=acrdigitalgarage01 -AKS_CLUSTER_NAME=aks-digitalgarage-01 -AKS_NAMESPACE=phonebill-prod - -# Service Names -SERVICES=api-gateway,user-service,bill-service,product-service,kos-mock - -# Build Configuration -GRADLE_OPTS="-Xmx3072m -XX:MaxPermSize=1024m" -JAVA_OPTS="-Xmx2048m -Xms1024m" - -# Docker Configuration -REGISTRY_URL=${ACR_NAME}.azurecr.io -IMAGE_TAG_PATTERN=${BUILD_NUMBER}-prod - -# Deployment Configuration -KUSTOMIZE_BASE=deployment/k8s -KUSTOMIZE_OVERLAY=overlays/prod -HEALTH_CHECK_TIMEOUT=600 -HEALTH_CHECK_RETRY=15 - -# SonarQube Configuration -SONAR_PROJECT_KEY=phonebill-prod -SONAR_SOURCES=. -SONAR_EXCLUSIONS=**/target/**,**/build/**,**/*.generated.java - -# Notification Configuration -SLACK_CHANNEL=#phonebill-prod -EMAIL_RECIPIENTS=prod-team@company.com,ops-team@company.com \ No newline at end of file +# PROD Environment Configuration +resource_group=rg-digitalgarage-01 +cluster_name=aks-digitalgarage-01 \ No newline at end of file diff --git a/deployment/cicd/config/deploy_env_vars_staging b/deployment/cicd/config/deploy_env_vars_staging index 68914b8..21423e5 100644 --- a/deployment/cicd/config/deploy_env_vars_staging +++ b/deployment/cicd/config/deploy_env_vars_staging @@ -1,34 +1,3 @@ -# Staging Environment Configuration for phonebill -# Jenkins Pipeline Environment Variables - -# Azure Configuration -AZURE_RESOURCE_GROUP=rg-digitalgarage-01 -ACR_NAME=acrdigitalgarage01 -AKS_CLUSTER_NAME=aks-digitalgarage-01 -AKS_NAMESPACE=phonebill-staging - -# Service Names -SERVICES=api-gateway,user-service,bill-service,product-service,kos-mock - -# Build Configuration -GRADLE_OPTS="-Xmx2048m -XX:MaxPermSize=512m" -JAVA_OPTS="-Xmx1024m -Xms512m" - -# Docker Configuration -REGISTRY_URL=${ACR_NAME}.azurecr.io -IMAGE_TAG_PATTERN=${BUILD_NUMBER}-staging - -# Deployment Configuration -KUSTOMIZE_BASE=deployment/k8s -KUSTOMIZE_OVERLAY=overlays/staging -HEALTH_CHECK_TIMEOUT=300 -HEALTH_CHECK_RETRY=10 - -# SonarQube Configuration -SONAR_PROJECT_KEY=phonebill-staging -SONAR_SOURCES=. -SONAR_EXCLUSIONS=**/target/**,**/build/**,**/*.generated.java - -# Notification Configuration -SLACK_CHANNEL=#phonebill-staging -EMAIL_RECIPIENTS=staging-team@company.com \ No newline at end of file +# STAGING Environment Configuration +resource_group=rg-digitalgarage-01 +cluster_name=aks-digitalgarage-01 \ No newline at end of file diff --git a/deployment/cicd/jenkins-pipeline-guide.md b/deployment/cicd/jenkins-pipeline-guide.md index d10666d..a8ee796 100644 --- a/deployment/cicd/jenkins-pipeline-guide.md +++ b/deployment/cicd/jenkins-pipeline-guide.md @@ -1,423 +1,424 @@ -# Jenkins CI/CD Pipeline ๊ตฌ์ถ• ๊ฐ€์ด๋“œ +# Jenkins CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ• ๊ฐ€์ด๋“œ ## ๐Ÿ“‹ ๊ฐœ์š” -phonebill ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค๋ฅผ ์œ„ํ•œ Jenkins CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ• ๊ฐ€์ด๋“œ์ž…๋‹ˆ๋‹ค. -Azure Kubernetes Service(AKS)์™€ Azure Container Registry(ACR)๋ฅผ ํ™œ์šฉํ•œ ์ž๋™ํ™”๋œ ๋ฐฐํฌ ์‹œ์Šคํ…œ์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. +์ด ๊ฐ€์ด๋“œ๋Š” ํ†ต์‹ ์š”๊ธˆ ๊ด€๋ฆฌ ์„œ๋น„์Šค(phonebill)๋ฅผ ์œ„ํ•œ Jenkins + Kustomize ๊ธฐ๋ฐ˜ CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ• ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. -## ๐Ÿ—๏ธ ์•„ํ‚คํ…์ฒ˜ +### ๐ŸŽฏ ์ฃผ์š” ํŠน์ง• +- **ํ™˜๊ฒฝ๋ณ„ ๋ฐฐํฌ**: dev, staging, prod ํ™˜๊ฒฝ ๋ถ„๋ฆฌ ๊ด€๋ฆฌ +- **Kustomize ๊ธฐ๋ฐ˜**: ํ™˜๊ฒฝ๋ณ„ ๋งค๋‹ˆํŽ˜์ŠคํŠธ ๊ด€๋ฆฌ ๋ฐ ๋ฐฐํฌ +- **SonarQube ์—ฐ๋™**: ์ฝ”๋“œ ํ’ˆ์งˆ ๋ถ„์„ ๋ฐ Quality Gate ์ ์šฉ +- **Azure ํ†ตํ•ฉ**: ACR, AKS์™€ ์™„์ „ ํ†ตํ•ฉ +- **Health Check**: ๋ฐฐํฌ ํ›„ ์„œ๋น„์Šค ์ƒํƒœ ์ž๋™ ํ™•์ธ -### ์‹œ์Šคํ…œ ๊ตฌ์„ฑ์š”์†Œ -- **Jenkins**: CI/CD ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ -- **Azure Container Registry (ACR)**: ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ์ €์žฅ์†Œ -- **Azure Kubernetes Service (AKS)**: ์ปจํ…Œ์ด๋„ˆ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ -- **SonarQube**: ์ฝ”๋“œ ํ’ˆ์งˆ ๋ถ„์„ -- **Gradle**: ๋นŒ๋“œ ๋„๊ตฌ -- **Kustomize**: Kubernetes ๋งค๋‹ˆํŽ˜์ŠคํŠธ ๊ด€๋ฆฌ +--- -### ๋ฐฐํฌ ํ™˜๊ฒฝ -- **Development** (`phonebill-dev`) -- **Staging** (`phonebill-staging`) -- **Production** (`phonebill-prod`) +## ๐Ÿ—๏ธ ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜ -## ๐Ÿš€ ํŒŒ์ดํ”„๋ผ์ธ ์›Œํฌํ”Œ๋กœ์šฐ +### ์„œ๋น„์Šค ๊ตฌ์„ฑ +- **์‹œ์Šคํ…œ๋ช…**: phonebill +- **์„œ๋น„์Šค ๋ชฉ๋ก**: + - api-gateway (API ๊ฒŒ์ดํŠธ์›จ์ด) + - user-service (์‚ฌ์šฉ์ž ์„œ๋น„์Šค) + - bill-service (์š”๊ธˆ ์กฐํšŒ ์„œ๋น„์Šค) + - product-service (์ƒํ’ˆ ๋ณ€๊ฒฝ ์„œ๋น„์Šค) + - kos-mock (KOS Mock ์„œ๋น„์Šค) -```mermaid -graph LR - A[Code Commit] --> B[Jenkins Trigger] - B --> C[Build & Test] - C --> D[SonarQube Analysis] - D --> E[Quality Gate] - E --> F[Container Build] - F --> G[Push to ACR] - G --> H[Deploy to AKS] - H --> I[Health Check] - I --> J[Notification] +### Azure ๋ฆฌ์†Œ์Šค ์ •๋ณด +- **ACR**: acrdigitalgarage01.azurecr.io +- **๋ฆฌ์†Œ์Šค ๊ทธ๋ฃน**: rg-digitalgarage-01 +- **AKS ํด๋Ÿฌ์Šคํ„ฐ**: aks-digitalgarage-01 + +--- + +## ๐Ÿ› ๏ธ Jenkins ์„œ๋ฒ„ ํ™˜๊ฒฝ ๊ตฌ์„ฑ + +### 1. ํ•„์ˆ˜ ํ”Œ๋Ÿฌ๊ทธ์ธ ์„ค์น˜ + +Jenkins ๊ด€๋ฆฌ > ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ด€๋ฆฌ์—์„œ ๋‹ค์Œ ํ”Œ๋Ÿฌ๊ทธ์ธ๋“ค์„ ์„ค์น˜ํ•˜์„ธ์š”: + +``` +๐Ÿ“ฆ ํ•„์ˆ˜ ํ”Œ๋Ÿฌ๊ทธ์ธ ๋ชฉ๋ก: +- Kubernetes +- Pipeline Utility Steps +- Docker Pipeline +- GitHub +- SonarQube Scanner +- Azure Credentials ``` -### ์ฃผ์š” ๋‹จ๊ณ„ +### 2. Jenkins Credentials ๋“ฑ๋ก -1. **Initialize**: ํ™˜๊ฒฝ๋ณ„ ์„ค์ • ๋กœ๋“œ ๋ฐ ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ • -2. **Checkout & Prepare**: ์†Œ์Šค ์ฝ”๋“œ ์ฒดํฌ์•„์›ƒ ๋ฐ ๋นŒ๋“œ ํƒœ๊ทธ ์ƒ์„ฑ -3. **Build & Test**: Gradle์„ ์ด์šฉํ•œ ๋นŒ๋“œ ๋ฐ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ -4. **SonarQube Analysis**: ์ฝ”๋“œ ํ’ˆ์งˆ ๋ถ„์„ -5. **Quality Gate**: ํ’ˆ์งˆ ๊ธฐ์ค€ ๊ฒ€์ฆ -6. **Container Build & Push**: ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ๋นŒ๋“œ ๋ฐ ACR ํ‘ธ์‹œ -7. **Deploy to Kubernetes**: AKS ํด๋Ÿฌ์Šคํ„ฐ์— ๋ฐฐํฌ -8. **Health Check**: ๋ฐฐํฌ๋œ ์„œ๋น„์Šค ์ƒํƒœ ํ™•์ธ +Manage Jenkins > Credentials > Add Credentials์—์„œ ๋‹ค์Œ ์ •๋ณด๋“ค์„ ๋“ฑ๋กํ•˜์„ธ์š”: -## ๐Ÿ“‚ ํŒŒ์ผ ๊ตฌ์กฐ +#### Azure Service Principal +```yaml +Kind: Microsoft Azure Service Principal +ID: azure-credentials +Subscription ID: {๊ตฌ๋…ID} +Client ID: {ํด๋ผ์ด์–ธํŠธID} +Client Secret: {ํด๋ผ์ด์–ธํŠธ์‹œํฌ๋ฆฟ} +Tenant ID: {ํ…Œ๋„ŒํŠธID} +Azure Environment: Azure +``` +#### ACR Credentials +```yaml +Kind: Username with password +ID: acr-credentials +Username: acrdigitalgarage01 +Password: {ACRํŒจ์Šค์›Œ๋“œ} +``` + +#### SonarQube Token +```yaml +Kind: Secret text +ID: sonarqube-token +Secret: {SonarQubeํ† ํฐ} +``` + +--- + +## ๐Ÿ“‚ Kustomize ๊ตฌ์กฐ + +### ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ ``` deployment/cicd/ -โ”œโ”€โ”€ Jenkinsfile # Jenkins ํŒŒ์ดํ”„๋ผ์ธ ์ •์˜ -โ”œโ”€โ”€ config/ -โ”‚ โ”œโ”€โ”€ deploy_env_vars_dev # ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ • -โ”‚ โ”œโ”€โ”€ deploy_env_vars_staging # ์Šคํ…Œ์ด์ง• ํ™˜๊ฒฝ ์„ค์ • -โ”‚ โ””โ”€โ”€ deploy_env_vars_prod # ์šด์˜ ํ™˜๊ฒฝ ์„ค์ • -โ”œโ”€โ”€ scripts/ -โ”‚ โ””โ”€โ”€ deploy.sh # ์ˆ˜๋™ ๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ -โ””โ”€โ”€ jenkins-pipeline-guide.md # ์ด ๊ฐ€์ด๋“œ ๋ฌธ์„œ +โ”œโ”€โ”€ kustomize/ +โ”‚ โ”œโ”€โ”€ base/ # ๊ธฐ๋ณธ ๋งค๋‹ˆํŽ˜์ŠคํŠธ +โ”‚ โ”‚ โ”œโ”€โ”€ common/ # ๊ณตํ†ต ๋ฆฌ์†Œ์Šค +โ”‚ โ”‚ โ”œโ”€โ”€ api-gateway/ # API Gateway ๋ฆฌ์†Œ์Šค +โ”‚ โ”‚ โ”œโ”€โ”€ user-service/ # User Service ๋ฆฌ์†Œ์Šค +โ”‚ โ”‚ โ”œโ”€โ”€ bill-service/ # Bill Service ๋ฆฌ์†Œ์Šค +โ”‚ โ”‚ โ”œโ”€โ”€ product-service/ # Product Service ๋ฆฌ์†Œ์Šค +โ”‚ โ”‚ โ”œโ”€โ”€ kos-mock/ # KOS Mock ๋ฆฌ์†Œ์Šค +โ”‚ โ”‚ โ””โ”€โ”€ kustomization.yaml # Base Kustomization +โ”‚ โ””โ”€โ”€ overlays/ # ํ™˜๊ฒฝ๋ณ„ ์˜ค๋ฒ„๋ ˆ์ด +โ”‚ โ”œโ”€โ”€ dev/ # ๊ฐœ๋ฐœ ํ™˜๊ฒฝ +โ”‚ โ”œโ”€โ”€ staging/ # ์Šคํ…Œ์ด์ง• ํ™˜๊ฒฝ +โ”‚ โ””โ”€โ”€ prod/ # ์šด์˜ ํ™˜๊ฒฝ +โ”œโ”€โ”€ config/ # ํ™˜๊ฒฝ๋ณ„ ์„ค์ • +โ”œโ”€โ”€ scripts/ # ๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ +โ””โ”€โ”€ Jenkinsfile # Jenkins ํŒŒ์ดํ”„๋ผ์ธ ``` -## ๐Ÿ”ง Jenkins ๊ตฌ์„ฑ +### ํ™˜๊ฒฝ๋ณ„ ํŠน์„ฑ -### 1. Jenkins ํ”Œ๋Ÿฌ๊ทธ์ธ ์„ค์น˜ +#### ๐Ÿ”ง DEV ํ™˜๊ฒฝ +- **๋„ค์ž„์ŠคํŽ˜์ด์Šค**: phonebill-dev +- **๋„๋ฉ”์ธ**: phonebill-api.20.214.196.128.nip.io (HTTP) +- **ํ”„๋กœํŒŒ์ผ**: dev +- **DDL**: update (ํ…Œ์ด๋ธ” ์ž๋™ ์ƒ์„ฑ/์ˆ˜์ •) +- **JWT ํ† ํฐ**: 5์‹œ๊ฐ„ ์œ ํšจ +- **Replica**: ๋ชจ๋“  ์„œ๋น„์Šค 1๊ฐœ +- **๋ฆฌ์†Œ์Šค**: requests(256m CPU, 256Mi Memory), limits(1024m CPU, 1024Mi Memory) -ํ•„์ˆ˜ ํ”Œ๋Ÿฌ๊ทธ์ธ ๋ชฉ๋ก: -```bash -# Kubernetes ๊ด€๋ จ -Kubernetes Plugin -Pipeline: Kubernetes Steps +#### ๐Ÿ”„ STAGING ํ™˜๊ฒฝ +- **๋„ค์ž„์ŠคํŽ˜์ด์Šค**: phonebill-staging +- **๋„๋ฉ”์ธ**: phonebill-staging.20.214.196.128.nip.io (HTTPS) +- **ํ”„๋กœํŒŒ์ผ**: staging +- **DDL**: validate (์Šคํ‚ค๋งˆ ๊ฒ€์ฆ๋งŒ) +- **JWT ํ† ํฐ**: 5์‹œ๊ฐ„ ์œ ํšจ +- **Replica**: ๋ชจ๋“  ์„œ๋น„์Šค 2๊ฐœ +- **๋ฆฌ์†Œ์Šค**: requests(512m CPU, 512Mi Memory), limits(2048m CPU, 2048Mi Memory) -# Azure ๊ด€๋ จ -Azure CLI Plugin -Azure Container Registry Plugin +#### ๐Ÿš€ PROD ํ™˜๊ฒฝ +- **๋„ค์ž„์ŠคํŽ˜์ด์Šค**: phonebill-prod +- **๋„๋ฉ”์ธ**: phonebill.20.214.196.128.nip.io (HTTPS + SSL ๊ฐ•ํ™”) +- **ํ”„๋กœํŒŒ์ผ**: prod +- **DDL**: validate (์Šคํ‚ค๋งˆ ๊ฒ€์ฆ๋งŒ) +- **JWT ํ† ํฐ**: 1์‹œ๊ฐ„ ์œ ํšจ (๋ณด์•ˆ ๊ฐ•ํ™”) +- **Replica**: ๋ชจ๋“  ์„œ๋น„์Šค 3๊ฐœ +- **๋ฆฌ์†Œ์Šค**: requests(1024m CPU, 1024Mi Memory), limits(4096m CPU, 4096Mi Memory) -# ๋นŒ๋“œ ๋„๊ตฌ -Gradle Plugin -Pipeline: Gradle Plugin - -# ์ฝ”๋“œ ํ’ˆ์งˆ -SonarQube Scanner Plugin -Pipeline: SonarQube Plugin - -# ์•Œ๋ฆผ -Slack Notification Plugin -Email Extension Plugin - -# Git ๊ด€๋ จ -Git Plugin -GitHub Plugin -Pipeline: GitHub Plugin - -# ๊ธฐํƒ€ -Pipeline Plugin -Pipeline: Stage View Plugin -Blue Ocean Plugin -``` - -### 2. ๊ธ€๋กœ๋ฒŒ ์„ค์ • - -#### Azure Service Principal ์„ค์ • -```bash -# Jenkins ๊ด€๋ฆฌ > ์‹œ์Šคํ…œ ์„ค์ • > Global properties -# Environment variables ์ถ”๊ฐ€ -AZURE_TENANT_ID= -AZURE_SUBSCRIPTION_ID= -``` - -#### Credentials ์„ค์ • -Jenkins ๊ด€๋ฆฌ > Manage Credentials์—์„œ ๋‹ค์Œ ์„ค์ •: - -1. **azure-service-principal** (Azure Service Principal) - - ID: `azure-service-principal` - - Type: Microsoft Azure Service Principal - - Tenant ID: Azure ํ…Œ๋„ŒํŠธ ID - - Client ID: ์„œ๋น„์Šค ํ”„๋ฆฐ์‹œpal ํด๋ผ์ด์–ธํŠธ ID - - Client Secret: ์„œ๋น„์Šค ํ”„๋ฆฐ์‹œpal ์‹œํฌ๋ฆฟ - -2. **acr-credentials** (ACR ์ธ์ฆ ์ •๋ณด) - - ID: `acr-credentials` - - Type: Username with password - - Username: ACR ์‚ฌ์šฉ์ž๋ช… - - Password: ACR ํŒจ์Šค์›Œ๋“œ - -3. **sonarqube-token** (SonarQube ํ† ํฐ) - - ID: `sonarqube-token` - - Type: Secret text - - Secret: SonarQube ์•ก์„ธ์Šค ํ† ํฐ - -4. **slack-token** (Slack ํ† ํฐ) - - ID: `slack-token` - - Type: Secret text - - Secret: Slack Bot ํ† ํฐ - -### 3. Kubernetes Agent ์„ค์ • - -Jenkins๊ฐ€ Kubernetes ํด๋Ÿฌ์Šคํ„ฐ์—์„œ ๋นŒ๋“œ ์—์ด์ „ํŠธ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •: - -#### ServiceAccount ๋ฐ RBAC ์ƒ์„ฑ -```yaml -# jenkins-rbac.yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: jenkins-agent - namespace: jenkins --- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: jenkins-agent -rules: -- apiGroups: [\"\"] - resources: [\"pods\", \"pods/exec\", \"pods/log\", \"persistentvolumeclaims\"] - verbs: [\"*\"] -- apiGroups: [\"apps\"] - resources: [\"deployments\", \"replicasets\"] - verbs: [\"*\"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: jenkins-agent -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: jenkins-agent -subjects: -- kind: ServiceAccount - name: jenkins-agent - namespace: jenkins -``` -#### Gradle Cache PVC ์ƒ์„ฑ +## ๐Ÿ”„ CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๋‹จ๊ณ„ + +### Pipeline ๋‹จ๊ณ„ ์„ค๋ช… + +1. **Get Source** ๐Ÿ“ฅ + - Git ์†Œ์Šค ์ฝ”๋“œ ์ฒดํฌ์•„์›ƒ + - ํ™˜๊ฒฝ๋ณ„ ์„ค์ • ํŒŒ์ผ ๋กœ๋”ฉ + +2. **Setup AKS** โš™๏ธ + - Azure Service Principal๋กœ ๋กœ๊ทธ์ธ + - AKS ํด๋Ÿฌ์Šคํ„ฐ ์—ฐ๊ฒฐ ์„ค์ • + - ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ƒ์„ฑ + +3. **Build & SonarQube Analysis** ๐Ÿ” + - Gradle ๋นŒ๋“œ ์‹คํ–‰ + - ๊ฐ ์„œ๋น„์Šค๋ณ„ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ + - SonarQube ์ฝ”๋“œ ํ’ˆ์งˆ ๋ถ„์„ + - ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€ ๋ฆฌํฌํŠธ ์ƒ์„ฑ + +4. **Quality Gate** ๐Ÿšช + - SonarQube Quality Gate ๊ฒ€์ฆ + - ํ’ˆ์งˆ ๊ธฐ์ค€ ๋ฏธ๋‹ฌ ์‹œ ํŒŒ์ดํ”„๋ผ์ธ ์ค‘๋‹จ + +5. **Build & Push Images** ๐Ÿณ + - ๊ฐ ์„œ๋น„์Šค๋ณ„ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ๋นŒ๋“œ + - ACR์— ์ด๋ฏธ์ง€ ํ‘ธ์‹œ + - ํ™˜๊ฒฝ๋ณ„ ์ด๋ฏธ์ง€ ํƒœ๊ทธ ์ ์šฉ + +6. **Update Kustomize & Deploy** ๐Ÿš€ + - Kustomize๋ฅผ ํ†ตํ•œ ๋งค๋‹ˆํŽ˜์ŠคํŠธ ์ƒ์„ฑ + - ์ด๋ฏธ์ง€ ํƒœ๊ทธ ์—…๋ฐ์ดํŠธ + - Kubernetes ํด๋Ÿฌ์Šคํ„ฐ์— ๋ฐฐํฌ + - ๋ฐฐํฌ ์™„๋ฃŒ ๋Œ€๊ธฐ + +7. **Health Check** ๐Ÿ” + - API Gateway Health Check + - ์„œ๋น„์Šค ์ •์ƒ ๋™์ž‘ ํ™•์ธ + +### SonarQube Quality Gate ๊ธฐ์ค€ + ```yaml -# gradle-cache-pvc.yaml -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: jenkins-gradle-cache - namespace: jenkins -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi - storageClassName: managed-premium +ํ’ˆ์งˆ ๊ธฐ์ค€: +- Coverage: >= 80% +- Duplicated Lines: <= 3% +- Maintainability Rating: <= A +- Reliability Rating: <= A +- Security Rating: <= A ``` -์ ์šฉ: -```bash -kubectl apply -f jenkins-rbac.yaml -kubectl apply -f gradle-cache-pvc.yaml -``` +--- -### 4. SonarQube ์„ค์ • - -#### SonarQube Server ๊ตฌ์„ฑ -Jenkins ๊ด€๋ฆฌ > Configure System > SonarQube servers: -- Name: `SonarQube` -- Server URL: `http://sonarqube.example.com` -- Server authentication token: `sonarqube-token` credential ์„ ํƒ - -## ๐Ÿ”จ ํŒŒ์ดํ”„๋ผ์ธ ์ƒ์„ฑ +## ๐Ÿš€ Jenkins Pipeline Job ์ƒ์„ฑ ### 1. ์ƒˆ Pipeline Job ์ƒ์„ฑ -1. Jenkins ๋Œ€์‹œ๋ณด๋“œ์—์„œ \"New Item\" ํด๋ฆญ -2. Job ์ด๋ฆ„: `phonebill-pipeline` -3. Type: \"Pipeline\" ์„ ํƒ -4. OK ํด๋ฆญ + +1. Jenkins ์›น UI์—์„œ **New Item** ํด๋ฆญ +2. **Pipeline** ์„ ํƒ ํ›„ ํ”„๋กœ์ ํŠธ๋ช… ์ž…๋ ฅ +3. **OK** ํด๋ฆญ ### 2. Pipeline ์„ค์ • -1. **General** ํƒญ: - - Description: \"phonebill microservices CI/CD pipeline\" - - \"GitHub project\" ์ฒดํฌํ•˜๊ณ  ํ”„๋กœ์ ํŠธ URL ์ž…๋ ฅ -2. **Build Triggers** ํƒญ: - - \"GitHub hook trigger for GITScm polling\" ์ฒดํฌ (GitHub Webhook ์‚ฌ์šฉ ์‹œ) - - \"Poll SCM\" ์„ค์ •: `H/5 * * * *` (5๋ถ„๋งˆ๋‹ค ํด๋ง) +#### Source Code Management +```yaml +SCM: Git +Repository URL: {Git์ €์žฅ์†ŒURL} +Branch: main (๋˜๋Š” develop) +Script Path: deployment/cicd/Jenkinsfile +``` -3. **Pipeline** ํƒญ: - - Definition: \"Pipeline script from SCM\" - - SCM: Git - - Repository URL: GitHub ์ €์žฅ์†Œ URL - - Credentials: GitHub ์ธ์ฆ ์ •๋ณด - - Branch: `*/main` - - Script Path: `deployment/cicd/Jenkinsfile` +#### Pipeline Parameters +```yaml +ENVIRONMENT: + - Type: Choice Parameter + - Choices: dev, staging, prod + - Default: dev -### 3. ํ™˜๊ฒฝ๋ณ„ ํŒŒ์ดํ”„๋ผ์ธ ์ƒ์„ฑ -๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ํ™˜๊ฒฝ๋ณ„ ํŒŒ์ดํ”„๋ผ์ธ ์ƒ์„ฑ: -- `phonebill-dev-pipeline` -- `phonebill-staging-pipeline` -- `phonebill-prod-pipeline` +IMAGE_TAG: + - Type: String Parameter + - Default: latest +``` -## ๐Ÿงช ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ +--- -### 1. ์ˆ˜๋™ ์‹คํ–‰ -1. Jenkins์—์„œ ํŒŒ์ดํ”„๋ผ์ธ Job ์„ ํƒ -2. \"Build with Parameters\" ํด๋ฆญ -3. ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ •: - - **ENVIRONMENT**: `dev` / `staging` / `prod` - - **SERVICES_TO_BUILD**: `all` ๋˜๋Š” ํŠน์ • ์„œ๋น„์Šค - - **SKIP_TESTS**: ํ…Œ์ŠคํŠธ ์Šคํ‚ต ์—ฌ๋ถ€ - - **SKIP_SONAR**: SonarQube ๋ถ„์„ ์Šคํ‚ต ์—ฌ๋ถ€ - - **FORCE_DEPLOY**: ๊ฐ•์ œ ๋ฐฐํฌ ์—ฌ๋ถ€ -4. \"Build\" ํด๋ฆญ +## ๐Ÿ“ฆ ๋ฐฐํฌ ์‹คํ–‰ ๋ฐฉ๋ฒ• -### 2. ์ž๋™ ์‹คํ–‰ (Webhook) -GitHub์—์„œ ์ฝ”๋“œ ํ‘ธ์‹œ ์‹œ ์ž๋™์œผ๋กœ ํŒŒ์ดํ”„๋ผ์ธ์ด ํŠธ๋ฆฌ๊ฑฐ๋ฉ๋‹ˆ๋‹ค. +### 1. Jenkins UI๋ฅผ ํ†ตํ•œ ๋ฐฐํฌ -#### GitHub Webhook ์„ค์ • -1. GitHub ์ €์žฅ์†Œ > Settings > Webhooks -2. Add webhook: - - Payload URL: `http://jenkins.example.com/github-webhook/` - - Content type: `application/json` - - Secret: ์„ค์ •ํ•œ ์‹œํฌ๋ฆฟ - - Events: \"Just the push event\" +1. Jenkins > {ํ”„๋กœ์ ํŠธ๋ช…} > **Build with Parameters** ํด๋ฆญ +2. **ENVIRONMENT** ์„ ํƒ (dev/staging/prod) +3. **IMAGE_TAG** ์ž…๋ ฅ (์„ ํƒ์‚ฌํ•ญ, ๊ธฐ๋ณธ๊ฐ’: latest) +4. **Build** ํด๋ฆญ -## ๐Ÿ“Š ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ ์•Œ๋ฆผ +### 2. ์ˆ˜๋™ ๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ ์‚ฌ์šฉ -### 1. ๋นŒ๋“œ ์ƒํƒœ ๋ชจ๋‹ˆํ„ฐ๋ง -- Jenkins Blue Ocean ์ธํ„ฐํŽ˜์ด์Šค ํ™œ์šฉ -- ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ์ƒํƒœ ์‹ค์‹œ๊ฐ„ ํ™•์ธ -- ๋กœ๊ทธ ๋ฐ ์•„ํ‹ฐํŒฉํŠธ ํ™•์ธ +```bash +# ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ๋ฐฐํฌ +./deployment/cicd/scripts/deploy.sh dev latest -### 2. ์•Œ๋ฆผ ์„ค์ • -ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์Œ ์ฑ„๋„๋กœ ์•Œ๋ฆผ: -- **Slack**: ์ง€์ •๋œ ์ฑ„๋„์— ๋นŒ๋“œ ์ƒํƒœ ์•Œ๋ฆผ -- **Email**: ๋‹ด๋‹น์ž์—๊ฒŒ ๊ฒฐ๊ณผ ๋ฉ”์ผ ๋ฐœ์†ก +# ์Šคํ…Œ์ด์ง• ํ™˜๊ฒฝ ๋ฐฐํฌ +./deployment/cicd/scripts/deploy.sh staging v1.2.0 -### 3. ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘ -- ๋นŒ๋“œ ์‹œ๊ฐ„ ์ถ”์  -- ์„ฑ๊ณต/์‹คํŒจ์œจ ๋ชจ๋‹ˆํ„ฐ๋ง -- ๋ฐฐํฌ ๋นˆ๋„ ์ธก์ • +# ์šด์˜ ํ™˜๊ฒฝ ๋ฐฐํฌ +./deployment/cicd/scripts/deploy.sh prod v1.2.0 +``` -## ๐Ÿ” ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… +### 3. ๋ฐฐํฌ ์ƒํƒœ ํ™•์ธ + +```bash +# Pod ์ƒํƒœ ํ™•์ธ +kubectl get pods -n phonebill-{ํ™˜๊ฒฝ} + +# ์„œ๋น„์Šค ์ƒํƒœ ํ™•์ธ +kubectl get services -n phonebill-{ํ™˜๊ฒฝ} + +# Ingress ์ƒํƒœ ํ™•์ธ +kubectl get ingress -n phonebill-{ํ™˜๊ฒฝ} + +# ๋กœ๊ทธ ํ™•์ธ +kubectl logs -n phonebill-{ํ™˜๊ฒฝ} deployment/{ํ™˜๊ฒฝ}-api-gateway +``` + +--- + +## ๐Ÿ”„ ๋กค๋ฐฑ ๋ฐฉ๋ฒ• + +### 1. Kubernetes ๊ธฐ๋ณธ ๋กค๋ฐฑ + +```bash +# ์ด์ „ ๋ฒ„์ „์œผ๋กœ ๋กค๋ฐฑ +kubectl rollout undo deployment/{ํ™˜๊ฒฝ}-{์„œ๋น„์Šค๋ช…} -n phonebill-{ํ™˜๊ฒฝ} + +# ํŠน์ • ๋ฆฌ๋น„์ „์œผ๋กœ ๋กค๋ฐฑ +kubectl rollout undo deployment/{ํ™˜๊ฒฝ}-{์„œ๋น„์Šค๋ช…} -n phonebill-{ํ™˜๊ฒฝ} --to-revision=2 + +# ๋กค๋ฐฑ ์ƒํƒœ ํ™•์ธ +kubectl rollout status deployment/{ํ™˜๊ฒฝ}-{์„œ๋น„์Šค๋ช…} -n phonebill-{ํ™˜๊ฒฝ} +``` + +### 2. ์ด๋ฏธ์ง€ ํƒœ๊ทธ ๊ธฐ๋ฐ˜ ๋กค๋ฐฑ + +```bash +# ์•ˆ์ • ๋ฒ„์ „ ํƒœ๊ทธ๋กœ ์ˆ˜๋™ ๋ฐฐํฌ +./deployment/cicd/scripts/deploy.sh prod {์ด์ „์•ˆ์ •๋ฒ„์ „ํƒœ๊ทธ} +``` + +--- + +## ๐Ÿ”ง ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… ### ์ผ๋ฐ˜์ ์ธ ๋ฌธ์ œ ํ•ด๊ฒฐ -#### 1. Azure ์ธ์ฆ ์‹คํŒจ +#### 1. ํŒŒ์ดํ”„๋ผ์ธ ์‹คํŒจ ์‹œ ```bash -# ์„œ๋น„์Šค ํ”„๋ฆฐ์‹œpal ๊ถŒํ•œ ํ™•์ธ -az role assignment list --assignee - -# ํ•„์š”ํ•œ ๊ถŒํ•œ ํ• ๋‹น -az role assignment create \ - --assignee \ - --role \"AKS Cluster Admin\" \ - --scope /subscriptions//resourceGroups/ +# Jenkins ์ฝ˜์†” ๋กœ๊ทธ ํ™•์ธ +# SonarQube Quality Gate ์ƒํƒœ ํ™•์ธ +# Kubernetes ์ด๋ฒคํŠธ ํ™•์ธ +kubectl get events -n phonebill-{ํ™˜๊ฒฝ} --sort-by='.lastTimestamp' ``` -#### 2. ACR ํ‘ธ์‹œ ์‹คํŒจ +#### 2. ๋ฐฐํฌ ์‹คํŒจ ์‹œ ```bash -# ACR ๋กœ๊ทธ์ธ ํ™•์ธ -az acr login --name +# Pod ์ƒํƒœ ๋ฐ ๋กœ๊ทธ ํ™•์ธ +kubectl describe pod {pod-name} -n phonebill-{ํ™˜๊ฒฝ} +kubectl logs {pod-name} -n phonebill-{ํ™˜๊ฒฝ} -# ACR ๊ถŒํ•œ ํ™•์ธ -az acr show --name --resource-group +# ConfigMap/Secret ํ™•์ธ +kubectl get configmap -n phonebill-{ํ™˜๊ฒฝ} +kubectl get secret -n phonebill-{ํ™˜๊ฒฝ} ``` -#### 3. Kubernetes ๋ฐฐํฌ ์‹คํŒจ +#### 3. ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ ๋ฌธ์ œ ```bash -# kubectl ์ปจํ…์ŠคํŠธ ํ™•์ธ -kubectl config current-context +# Service์™€ Endpoint ํ™•์ธ +kubectl get svc,endpoints -n phonebill-{ํ™˜๊ฒฝ} -# ๋„ค์ž„์ŠคํŽ˜์ด์Šค ํ™•์ธ -kubectl get namespaces - -# ๋ฆฌ์†Œ์Šค ์ƒํƒœ ํ™•์ธ -kubectl get all -n +# Ingress ์„ค์ • ํ™•์ธ +kubectl describe ingress -n phonebill-{ํ™˜๊ฒฝ} ``` -#### 4. ํŒŒ๋“œ ์‹œ์ž‘ ์‹คํŒจ -```bash -# ํŒŒ๋“œ ๋กœ๊ทธ ํ™•์ธ -kubectl logs -n - -# ํŒŒ๋“œ ์ƒ์„ธ ์ •๋ณด ํ™•์ธ -kubectl describe pod -n - -# ์ด๋ฒคํŠธ ํ™•์ธ -kubectl get events -n --sort-by='.lastTimestamp' -``` - -### ๋กœ๊ทธ ์œ„์น˜ -- **Jenkins ๋กœ๊ทธ**: `/var/log/jenkins/jenkins.log` -- **ํŒŒ์ดํ”„๋ผ์ธ ๋กœ๊ทธ**: Jenkins UI์—์„œ Build History > Console Output -- **Kubernetes ๋กœ๊ทธ**: `kubectl logs` ๋ช…๋ น์–ด ์‚ฌ์šฉ - -## ๐Ÿš€ ์ˆ˜๋™ ๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ ์‚ฌ์šฉ๋ฒ• - -Jenkins ํŒŒ์ดํ”„๋ผ์ธ ์™ธ์—๋„ ์ˆ˜๋™ ๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. - -### ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ• -```bash -# ๋ชจ๋“  ์„œ๋น„์Šค๋ฅผ dev ํ™˜๊ฒฝ์— ๋ฐฐํฌ -./deployment/cicd/scripts/deploy.sh dev - -# ํŠน์ • ์„œ๋น„์Šค๋งŒ staging ํ™˜๊ฒฝ์— ๋ฐฐํฌ -./deployment/cicd/scripts/deploy.sh staging user-service - -# ์—ฌ๋Ÿฌ ์„œ๋น„์Šค๋ฅผ prod ํ™˜๊ฒฝ์— ๋ฐฐํฌ -./deployment/cicd/scripts/deploy.sh prod api-gateway,user-service,bill-service - -# ์˜ต์…˜ ์‚ฌ์šฉ ์˜ˆ์‹œ -./deployment/cicd/scripts/deploy.sh dev all --skip-build --skip-test -``` - -### ์ฃผ์š” ์˜ต์…˜ -- `--skip-build`: Gradle ๋นŒ๋“œ ์Šคํ‚ต -- `--skip-test`: ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์Šคํ‚ต -- `--skip-push`: ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ํ‘ธ์‹œ ์Šคํ‚ต -- `--force`: ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์—†์–ด๋„ ๊ฐ•์ œ ๋ฐฐํฌ -- `--dry-run`: ์‹ค์ œ ๋ฐฐํฌ ์—†์ด ๋ฏธ๋ฆฌ๋ณด๊ธฐ - -## ๐Ÿ“ˆ ์„ฑ๋Šฅ ์ตœ์ ํ™” - -### 1. ๋นŒ๋“œ ์„ฑ๋Šฅ ๊ฐœ์„  -- **Gradle Daemon** ํ™œ์šฉ: `--daemon` ์˜ต์…˜ -- **๋ณ‘๋ ฌ ๋นŒ๋“œ**: `--parallel` ์˜ต์…˜ -- **Build Cache** ํ™œ์šฉ: `--build-cache` ์˜ต์…˜ -- **Incremental Build** ํ™œ์šฉ - -### 2. ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ์ตœ์ ํ™” -- **Multi-stage Build** ์‚ฌ์šฉ -- **Layer Caching** ์ตœ์ ํ™” -- **Base Image** ์ตœ์ ํ™” -- **.dockerignore** ํ™œ์šฉ - -### 3. Kubernetes ๋ฐฐํฌ ์ตœ์ ํ™” -- **Rolling Update** ์ „๋žต ์‚ฌ์šฉ -- **Resource Limits** ์„ค์ • -- **Readiness/Liveness Probe** ์„ค์ • -- **Pod Disruption Budget** ์„ค์ • - -## ๐Ÿ”’ ๋ณด์•ˆ ๊ณ ๋ ค์‚ฌํ•ญ - -### 1. ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๊ด€๋ฆฌ -- Azure Service Principal ์ตœ์†Œ ๊ถŒํ•œ ์›์น™ -- Jenkins Credentials ์•”ํ˜ธํ™” ์ €์žฅ -- Kubernetes RBAC ์ ์ ˆํ•œ ๊ถŒํ•œ ํ• ๋‹น -- ์‹œํฌ๋ฆฟ ์ •๋ณด ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ๋ถ„๋ฆฌ - -### 2. ์ปจํ…Œ์ด๋„ˆ ๋ณด์•ˆ -- ์ทจ์•ฝ์  ์Šค์บ๋‹ ๋„๊ตฌ ํ†ตํ•ฉ -- ๋น„ํŠน๊ถŒ ์‚ฌ์šฉ์ž๋กœ ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰ -- ์ฝ๊ธฐ ์ „์šฉ ๋ฃจํŠธ ํŒŒ์ผ์‹œ์Šคํ…œ -- ๋ณด์•ˆ ์ปจํ…์ŠคํŠธ ์„ค์ • - -### 3. ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ -- Private Registry ์‚ฌ์šฉ -- Network Policy ์ ์šฉ -- Service Mesh ๋ณด์•ˆ ์ •์ฑ… -- TLS/SSL ์•”ํ˜ธํ™” - -## ๐Ÿ“š ์ฐธ๊ณ  ์ž๋ฃŒ - -### ๊ณต์‹ ๋ฌธ์„œ -- [Jenkins Pipeline](https://jenkins.io/doc/book/pipeline/) -- [Azure Kubernetes Service](https://docs.microsoft.com/en-us/azure/aks/) -- [Azure Container Registry](https://docs.microsoft.com/en-us/azure/container-registry/) -- [Kubernetes](https://kubernetes.io/docs/) -- [Gradle](https://docs.gradle.org/) - -### ๋ชจ๋ฒ” ์‚ฌ๋ก€ -- [Jenkins Best Practices](https://wiki.jenkins.io/display/JENKINS/Jenkins+Best+Practices) -- [Kubernetes Best Practices](https://kubernetes.io/docs/concepts/configuration/overview/) -- [Docker Best Practices](https://docs.docker.com/develop/dev-best-practices/) - -## ๐Ÿ“ž ์ง€์› - -๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ ์ถ”๊ฐ€ ์ง€์›์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ: - -1. **๋กœ๊ทธ ํ™•์ธ**: Jenkins ์ฝ˜์†” ์ถœ๋ ฅ ๋ฐ Kubernetes ๋กœ๊ทธ ๊ฒ€ํ†  -2. **๋ฌธ์„œ ๊ฒ€ํ† **: ์ด ๊ฐ€์ด๋“œ ๋ฐ ๊ณต์‹ ๋ฌธ์„œ ์ฐธ์กฐ -3. **์ปค๋ฎค๋‹ˆํ‹ฐ**: Stack Overflow, Jenkins ์ปค๋ฎค๋‹ˆํ‹ฐ ํฌ๋Ÿผ ํ™œ์šฉ -4. **ํŒ€ ์ง€์›**: DevOps ํŒ€ ๋˜๋Š” ํ”Œ๋žซํผ ํŒ€์— ๋ฌธ์˜ - --- -*์ด ๊ฐ€์ด๋“œ๋Š” phonebill ํ”„๋กœ์ ํŠธ์˜ Jenkins CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ•์„ ์œ„ํ•œ ์™„์ „ํ•œ ๊ฐ€์ด๋“œ์ž…๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ ์š”๊ตฌ์‚ฌํ•ญ์— ๋”ฐ๋ผ ์„ค์ •์„ ์กฐ์ •ํ•˜์—ฌ ์‚ฌ์šฉํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.* \ No newline at end of file +## ๐Ÿ“ ์ฒดํฌ๋ฆฌ์ŠคํŠธ + +### ๐Ÿ“‹ Kustomize ๊ตฌ์„ฑ ์ฒดํฌ๋ฆฌ์ŠคํŠธ + +#### ๐Ÿ“‚ ๊ธฐ๋ณธ ๊ตฌ์กฐ ๊ฒ€์ฆ +- [ ] ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ: `deployment/cicd/kustomize/{base,overlays/{dev,staging,prod}}` +- [ ] ์„œ๋น„์Šค๋ณ„ base ๋””๋ ‰ํ† ๋ฆฌ: `base/{common,api-gateway,user-service,bill-service,product-service,kos-mock}` +- [ ] Base kustomization.yaml ํŒŒ์ผ ์ƒ์„ฑ ์™„๋ฃŒ + +#### ๐Ÿ”ง ํ™˜๊ฒฝ๋ณ„ Overlay ๊ฒ€์ฆ +**๊ฐ ํ™˜๊ฒฝ(dev/staging/prod)๋ณ„๋กœ ๋‹ค์Œ ํŒŒ์ผ๋“ค์ด ๋ชจ๋‘ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•จ:** + +**ํ•„์ˆ˜ ํŒŒ์ผ ๋ชฉ๋ก:** +- [ ] `kustomization.yaml` - ํ™˜๊ฒฝ ์„ค์ • ๋ฐ patch ํŒŒ์ผ ์ฐธ์กฐ +- [ ] `configmap-common-patch.yaml` - ํ™˜๊ฒฝ๋ณ„ ๊ณตํ†ต ์„ค์ • (ํ”„๋กœํŒŒ์ผ, DDL, JWT ์„ค์ •) +- [ ] `secret-common-patch.yaml` - ํ™˜๊ฒฝ๋ณ„ ๊ณตํ†ต ์‹œํฌ๋ฆฟ (JWT Secret, Redis ์ •๋ณด) +- [ ] `ingress-patch.yaml` - ํ™˜๊ฒฝ๋ณ„ ๋„๋ฉ”์ธ ๋ฐ ๋ณด์•ˆ ์„ค์ • +- [ ] **`deployment-patch.yaml`** - **ํ™˜๊ฒฝ๋ณ„ replicas AND resources ์„ค์ •** โš ๏ธ +- [ ] `secret-user-service-patch.yaml` - User Service DB ์ •๋ณด +- [ ] `secret-bill-service-patch.yaml` - Bill Service DB ์ •๋ณด +- [ ] `secret-product-service-patch.yaml` - Product Service DB ์ •๋ณด + +**โš ๏ธ deployment-patch.yaml ํ•„์ˆ˜ ๊ฒ€์ฆ ์‚ฌํ•ญ:** +- [ ] **ํŒŒ์ผ๋ช…์ด ์ •ํ™•ํ•œ์ง€**: `deployment-patch.yaml` (โŒ `replica-patch.yaml` ์•„๋‹˜) +- [ ] **Strategic Merge Patch ํ˜•์‹ ์‚ฌ์šฉ**: YAML ํ˜•์‹, JSON Patch ์•„๋‹˜ +- [ ] **replicas ์„ค์ •**: dev(1), staging(2), prod(3) +- [ ] **resources ์„ค์ •**: ํ™˜๊ฒฝ๋ณ„ ์ฐจ๋“ฑ ์ ์šฉ + - dev: requests(256m CPU, 256Mi Memory), limits(1024m CPU, 1024Mi Memory) + - staging: requests(512m CPU, 512Mi Memory), limits(2048m CPU, 2048Mi Memory) + - prod: requests(1024m CPU, 1024Mi Memory), limits(4096m CPU, 4096Mi Memory) +- [ ] **๋ชจ๋“  ์„œ๋น„์Šค ํฌํ•จ**: api-gateway, user-service, bill-service, product-service, kos-mock + +#### ๐Ÿ” ํ˜ธํ™˜์„ฑ ๊ฒ€์ฆ +- [ ] base ๋งค๋‹ˆํŽ˜์ŠคํŠธ์— ์—†๋Š” ํ•ญ๋ชฉ์„ patch์— ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์Œ +- [ ] base ๋งค๋‹ˆํŽ˜์ŠคํŠธ์™€ patch ํ•„๋“œ ๊ตฌ์กฐ ์ผ์น˜ +- [ ] Secret ๋งค๋‹ˆํŽ˜์ŠคํŠธ์— 'data' ๋Œ€์‹  'stringData' ์‚ฌ์šฉ + +### ๐Ÿ“‹ ๋ฐฐํฌ ์ „ ์ฒดํฌ๋ฆฌ์ŠคํŠธ + +- [ ] Jenkins ํ•„์ˆ˜ ํ”Œ๋Ÿฌ๊ทธ์ธ ์„ค์น˜ ์™„๋ฃŒ +- [ ] Credentials ๋“ฑ๋ก ์™„๋ฃŒ (Azure, ACR, SonarQube) +- [ ] SonarQube ํ”„๋กœ์ ํŠธ ์„ค์ • ์™„๋ฃŒ +- [ ] ํ™˜๊ฒฝ๋ณ„ Database/Redis ์ค€๋น„ ์™„๋ฃŒ +- [ ] ๋„คํŠธ์›Œํฌ ๋ฐ ๋„๋ฉ”์ธ ์„ค์ • ์™„๋ฃŒ + +### ๐Ÿš€ ๋ฐฐํฌ ํ›„ ์ฒดํฌ๋ฆฌ์ŠคํŠธ + +- [ ] ๋ชจ๋“  Pod๊ฐ€ Running ์ƒํƒœ +- [ ] Health Check ํ†ต๊ณผ +- [ ] Ingress๋กœ ์™ธ๋ถ€ ์ ‘๊ทผ ๊ฐ€๋Šฅ +- [ ] ๋กœ๊ทธ์— ์˜ค๋ฅ˜ ์—†์Œ +- [ ] ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ ์™„๋ฃŒ + +### ๐Ÿ’ก ์ผ๋ฐ˜์ ์ธ ์‹ค์ˆ˜ ๋ฐฉ์ง€ ๊ฐ€์ด๋“œ + +**โŒ ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ์‹ค์ˆ˜๋“ค:** +1. **ํŒŒ์ผ๋ช… ์‹ค์ˆ˜**: `replica-patch.yaml` ์ƒ์„ฑ โ†’ ์ •๋‹ต: `deployment-patch.yaml` +2. **๋‚ด์šฉ ๋ˆ„๋ฝ**: replicas๋งŒ ์„ค์ •ํ•˜๊ณ  resources ๋ˆ„๋ฝ โ†’ ์ •๋‹ต: ๋‘˜ ๋‹ค ์„ค์ • +3. **ํ˜•์‹ ์‹ค์ˆ˜**: JSON Patch ์‚ฌ์šฉ โ†’ ์ •๋‹ต: Strategic Merge Patch ์‚ฌ์šฉ +4. **ํ™˜๊ฒฝ๋ณ„ ์ฐจ์ด ์—†์Œ**: ๋ชจ๋“  ํ™˜๊ฒฝ ๋™์ผ ์„ค์ • โ†’ ์ •๋‹ต: ํ™˜๊ฒฝ๋ณ„ ์ฐจ๋“ฑ ์„ค์ • + +**โœ… ์˜ฌ๋ฐ”๋ฅธ deployment-patch.yaml ์˜ˆ์‹œ:** +```yaml +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 # ํ™˜๊ฒฝ๋ณ„ ์ฐจ๋“ฑ ์ ์šฉ +``` + +--- + +## ๐Ÿ“ž ์ง€์› ์ •๋ณด + +### ํ™˜๊ฒฝ ์ •๋ณด +- **์‹œ์Šคํ…œ**: phonebill (ํ†ต์‹ ์š”๊ธˆ ๊ด€๋ฆฌ ์„œ๋น„์Šค) +- **Git ์ €์žฅ์†Œ**: [Repository URL] +- **Jenkins**: [Jenkins URL] +- **SonarQube**: [SonarQube URL] + +### ์—ฐ๋ฝ์ฒ˜ +- **DevOps ํŒ€**: ์ตœ์šด์˜ (๋ฐ์˜ต์Šค) +- **๋ฐฑ์—”๋“œ ํŒ€**: ์ด๊ฐœ๋ฐœ (๋ฐฑ์—”๋”) +- **QA ํŒ€**: ์ •ํ…Œ์ŠคํŠธ (QA๋งค๋‹ˆ์ €) + +--- + +## ๐Ÿ“š ์ถ”๊ฐ€ ๋ฆฌ์†Œ์Šค + +- [Kustomize ๊ณต์‹ ๋ฌธ์„œ](https://kustomize.io/) +- [Jenkins Pipeline ๋ฌธ๋ฒ•](https://www.jenkins.io/doc/book/pipeline/syntax/) +- [Azure DevOps ๊ฐ€์ด๋“œ](https://docs.microsoft.com/en-us/azure/devops/) + +--- + +*์ด ๊ฐ€์ด๋“œ๋Š” phonebill ํ”„๋กœ์ ํŠธ์˜ CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ•์„ ์œ„ํ•œ ์™„์ „ํ•œ ๊ฐ€์ด๋“œ์ž…๋‹ˆ๋‹ค. ์ถ”๊ฐ€ ์งˆ๋ฌธ์ด๋‚˜ ์ง€์›์ด ํ•„์š”ํ•˜์‹œ๋ฉด DevOps ํŒ€์— ๋ฌธ์˜ํ•˜์„ธ์š”.* \ No newline at end of file diff --git a/deployment/cicd/kustomize/base/api-gateway/cm-api-gateway.yaml b/deployment/cicd/kustomize/base/api-gateway/cm-api-gateway.yaml index aa83a94..2feab2a 100644 --- a/deployment/cicd/kustomize/base/api-gateway/cm-api-gateway.yaml +++ b/deployment/cicd/kustomize/base/api-gateway/cm-api-gateway.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: ConfigMap metadata: name: cm-api-gateway + namespace: phonebill-dev data: SERVER_PORT: "8080" BILL_SERVICE_URL: "http://bill-service" diff --git a/deployment/cicd/kustomize/base/api-gateway/deployment.yaml b/deployment/cicd/kustomize/base/api-gateway/deployment.yaml index ceb7e8c..05c6ec7 100644 --- a/deployment/cicd/kustomize/base/api-gateway/deployment.yaml +++ b/deployment/cicd/kustomize/base/api-gateway/deployment.yaml @@ -2,6 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: api-gateway + namespace: phonebill-dev spec: replicas: 1 selector: diff --git a/deployment/cicd/kustomize/base/api-gateway/kustomization.yaml b/deployment/cicd/kustomize/base/api-gateway/kustomization.yaml deleted file mode 100644 index 0d4ae64..0000000 --- a/deployment/cicd/kustomize/base/api-gateway/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- cm-api-gateway.yaml -- deployment.yaml -- service.yaml \ No newline at end of file diff --git a/deployment/cicd/kustomize/base/api-gateway/service.yaml b/deployment/cicd/kustomize/base/api-gateway/service.yaml index f446bd0..dda5887 100644 --- a/deployment/cicd/kustomize/base/api-gateway/service.yaml +++ b/deployment/cicd/kustomize/base/api-gateway/service.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Service metadata: name: api-gateway + namespace: phonebill-dev spec: selector: app: api-gateway diff --git a/deployment/cicd/kustomize/base/bill-service/cm-bill-service.yaml b/deployment/cicd/kustomize/base/bill-service/cm-bill-service.yaml index 9281f36..f3a3868 100644 --- a/deployment/cicd/kustomize/base/bill-service/cm-bill-service.yaml +++ b/deployment/cicd/kustomize/base/bill-service/cm-bill-service.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: ConfigMap metadata: name: cm-bill-service + namespace: phonebill-dev data: SERVER_PORT: "8082" DB_KIND: "postgresql" diff --git a/deployment/cicd/kustomize/base/bill-service/deployment.yaml b/deployment/cicd/kustomize/base/bill-service/deployment.yaml index 78a42dd..f63ff8c 100644 --- a/deployment/cicd/kustomize/base/bill-service/deployment.yaml +++ b/deployment/cicd/kustomize/base/bill-service/deployment.yaml @@ -2,6 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: bill-service + namespace: phonebill-dev spec: replicas: 1 selector: diff --git a/deployment/cicd/kustomize/base/bill-service/kustomization.yaml b/deployment/cicd/kustomize/base/bill-service/kustomization.yaml deleted file mode 100644 index 3f272bf..0000000 --- a/deployment/cicd/kustomize/base/bill-service/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- cm-bill-service.yaml -- deployment.yaml -- secret-bill-service.yaml -- service.yaml \ No newline at end of file diff --git a/deployment/cicd/kustomize/base/bill-service/secret-bill-service.yaml b/deployment/cicd/kustomize/base/bill-service/secret-bill-service.yaml index 72b5ee6..a6a503d 100644 --- a/deployment/cicd/kustomize/base/bill-service/secret-bill-service.yaml +++ b/deployment/cicd/kustomize/base/bill-service/secret-bill-service.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Secret metadata: name: secret-bill-service + namespace: phonebill-dev type: Opaque stringData: DB_HOST: "bill-inquiry-postgres-dev-postgresql" diff --git a/deployment/cicd/kustomize/base/bill-service/service.yaml b/deployment/cicd/kustomize/base/bill-service/service.yaml index 1e6373b..7df0a93 100644 --- a/deployment/cicd/kustomize/base/bill-service/service.yaml +++ b/deployment/cicd/kustomize/base/bill-service/service.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Service metadata: name: bill-service + namespace: phonebill-dev spec: selector: app: bill-service diff --git a/deployment/cicd/kustomize/base/common/cm-common.yaml b/deployment/cicd/kustomize/base/common/cm-common.yaml index 0511102..b9a425a 100644 --- a/deployment/cicd/kustomize/base/common/cm-common.yaml +++ b/deployment/cicd/kustomize/base/common/cm-common.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: ConfigMap metadata: name: cm-common + namespace: phonebill-dev 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" diff --git a/deployment/cicd/kustomize/base/common/ingress.yaml b/deployment/cicd/kustomize/base/common/ingress.yaml index 3c5cec7..2986e68 100644 --- a/deployment/cicd/kustomize/base/common/ingress.yaml +++ b/deployment/cicd/kustomize/base/common/ingress.yaml @@ -2,6 +2,7 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: phonebill + namespace: phonebill-dev annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/ssl-redirect: "false" diff --git a/deployment/cicd/kustomize/base/common/kustomization.yaml b/deployment/cicd/kustomize/base/common/kustomization.yaml deleted file mode 100644 index d815c12..0000000 --- a/deployment/cicd/kustomize/base/common/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- cm-common.yaml -- ingress.yaml -- secret-common.yaml -- secret-imagepull.yaml \ No newline at end of file diff --git a/deployment/cicd/kustomize/base/common/secret-common.yaml b/deployment/cicd/kustomize/base/common/secret-common.yaml index b641d81..e98607e 100644 --- a/deployment/cicd/kustomize/base/common/secret-common.yaml +++ b/deployment/cicd/kustomize/base/common/secret-common.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Secret metadata: name: secret-common + namespace: phonebill-dev type: Opaque stringData: JWT_SECRET: "nwe5Yo9qaJ6FBD/Thl2/j6/SFAfNwUorAY1ZcWO2KI7uA4bmVLOCPxE9hYuUpRCOkgV2UF2DdHXtqHi3+BU/ecbz2zpHyf/720h48UbA3XOMYOX1sdM+dQ==" diff --git a/deployment/cicd/kustomize/base/common/secret-imagepull.yaml b/deployment/cicd/kustomize/base/common/secret-imagepull.yaml index 6bd576e..f9b5028 100644 --- a/deployment/cicd/kustomize/base/common/secret-imagepull.yaml +++ b/deployment/cicd/kustomize/base/common/secret-imagepull.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Secret metadata: name: phonebill + namespace: phonebill-dev type: kubernetes.io/dockerconfigjson stringData: .dockerconfigjson: | diff --git a/deployment/cicd/kustomize/base/kos-mock/cm-kos-mock.yaml b/deployment/cicd/kustomize/base/kos-mock/cm-kos-mock.yaml index 3e55476..8cd3571 100644 --- a/deployment/cicd/kustomize/base/kos-mock/cm-kos-mock.yaml +++ b/deployment/cicd/kustomize/base/kos-mock/cm-kos-mock.yaml @@ -2,5 +2,6 @@ apiVersion: v1 kind: ConfigMap metadata: name: cm-kos-mock + namespace: phonebill-dev data: SERVER_PORT: "8084" \ No newline at end of file diff --git a/deployment/cicd/kustomize/base/kos-mock/deployment.yaml b/deployment/cicd/kustomize/base/kos-mock/deployment.yaml index bd588f4..c58ddb5 100644 --- a/deployment/cicd/kustomize/base/kos-mock/deployment.yaml +++ b/deployment/cicd/kustomize/base/kos-mock/deployment.yaml @@ -2,6 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: kos-mock + namespace: phonebill-dev spec: replicas: 1 selector: diff --git a/deployment/cicd/kustomize/base/kos-mock/kustomization.yaml b/deployment/cicd/kustomize/base/kos-mock/kustomization.yaml deleted file mode 100644 index edbf030..0000000 --- a/deployment/cicd/kustomize/base/kos-mock/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- cm-kos-mock.yaml -- deployment.yaml -- service.yaml \ No newline at end of file diff --git a/deployment/cicd/kustomize/base/kos-mock/service.yaml b/deployment/cicd/kustomize/base/kos-mock/service.yaml index fdb5336..4c315b8 100644 --- a/deployment/cicd/kustomize/base/kos-mock/service.yaml +++ b/deployment/cicd/kustomize/base/kos-mock/service.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Service metadata: name: kos-mock + namespace: phonebill-dev spec: selector: app: kos-mock diff --git a/deployment/cicd/kustomize/base/kustomization.yaml b/deployment/cicd/kustomize/base/kustomization.yaml index 4872533..184c099 100644 --- a/deployment/cicd/kustomize/base/kustomization.yaml +++ b/deployment/cicd/kustomize/base/kustomization.yaml @@ -1,10 +1,56 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization +metadata: + name: phonebill-base + resources: -- common -- api-gateway -- user-service -- bill-service -- product-service -- kos-mock \ No newline at end of file + # 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 + +commonLabels: + app: phonebill + version: v1 + +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 \ No newline at end of file diff --git a/deployment/cicd/kustomize/base/product-service/cm-product-service.yaml b/deployment/cicd/kustomize/base/product-service/cm-product-service.yaml index 5a3893d..288a11b 100644 --- a/deployment/cicd/kustomize/base/product-service/cm-product-service.yaml +++ b/deployment/cicd/kustomize/base/product-service/cm-product-service.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: ConfigMap metadata: name: cm-product-service + namespace: phonebill-dev data: SERVER_PORT: "8083" DB_KIND: "postgresql" diff --git a/deployment/cicd/kustomize/base/product-service/deployment.yaml b/deployment/cicd/kustomize/base/product-service/deployment.yaml index 0b463a3..581bff2 100644 --- a/deployment/cicd/kustomize/base/product-service/deployment.yaml +++ b/deployment/cicd/kustomize/base/product-service/deployment.yaml @@ -2,6 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: product-service + namespace: phonebill-dev spec: replicas: 1 selector: diff --git a/deployment/cicd/kustomize/base/product-service/kustomization.yaml b/deployment/cicd/kustomize/base/product-service/kustomization.yaml deleted file mode 100644 index ed9aa8d..0000000 --- a/deployment/cicd/kustomize/base/product-service/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- cm-product-service.yaml -- deployment.yaml -- secret-product-service.yaml -- service.yaml \ No newline at end of file diff --git a/deployment/cicd/kustomize/base/product-service/secret-product-service.yaml b/deployment/cicd/kustomize/base/product-service/secret-product-service.yaml index 73c1619..e6a139a 100644 --- a/deployment/cicd/kustomize/base/product-service/secret-product-service.yaml +++ b/deployment/cicd/kustomize/base/product-service/secret-product-service.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Secret metadata: name: secret-product-service + namespace: phonebill-dev type: Opaque stringData: DB_HOST: "product-change-postgres-dev-postgresql" diff --git a/deployment/cicd/kustomize/base/product-service/service.yaml b/deployment/cicd/kustomize/base/product-service/service.yaml index b784a5d..7bb407f 100644 --- a/deployment/cicd/kustomize/base/product-service/service.yaml +++ b/deployment/cicd/kustomize/base/product-service/service.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Service metadata: name: product-service + namespace: phonebill-dev spec: selector: app: product-service diff --git a/deployment/cicd/kustomize/base/user-service/cm-user-service.yaml b/deployment/cicd/kustomize/base/user-service/cm-user-service.yaml index 4031913..1b5d95f 100644 --- a/deployment/cicd/kustomize/base/user-service/cm-user-service.yaml +++ b/deployment/cicd/kustomize/base/user-service/cm-user-service.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: ConfigMap metadata: name: cm-user-service + namespace: phonebill-dev data: SERVER_PORT: "8081" DB_KIND: "postgresql" diff --git a/deployment/cicd/kustomize/base/user-service/deployment.yaml b/deployment/cicd/kustomize/base/user-service/deployment.yaml index 2dbd2d4..77dd54a 100644 --- a/deployment/cicd/kustomize/base/user-service/deployment.yaml +++ b/deployment/cicd/kustomize/base/user-service/deployment.yaml @@ -2,6 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: user-service + namespace: phonebill-dev spec: replicas: 1 selector: diff --git a/deployment/cicd/kustomize/base/user-service/kustomization.yaml b/deployment/cicd/kustomize/base/user-service/kustomization.yaml deleted file mode 100644 index 55397b3..0000000 --- a/deployment/cicd/kustomize/base/user-service/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- cm-user-service.yaml -- deployment.yaml -- secret-user-service.yaml -- service.yaml \ No newline at end of file diff --git a/deployment/cicd/kustomize/base/user-service/secret-user-service.yaml b/deployment/cicd/kustomize/base/user-service/secret-user-service.yaml index a0e6d7a..5dbf7cb 100644 --- a/deployment/cicd/kustomize/base/user-service/secret-user-service.yaml +++ b/deployment/cicd/kustomize/base/user-service/secret-user-service.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Secret metadata: name: secret-user-service + namespace: phonebill-dev type: Opaque stringData: DB_HOST: "auth-postgres-dev-postgresql" diff --git a/deployment/cicd/kustomize/base/user-service/service.yaml b/deployment/cicd/kustomize/base/user-service/service.yaml index c9fb9cf..2a6bc8f 100644 --- a/deployment/cicd/kustomize/base/user-service/service.yaml +++ b/deployment/cicd/kustomize/base/user-service/service.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Service metadata: name: user-service + namespace: phonebill-dev spec: selector: app: user-service diff --git a/deployment/cicd/kustomize/overlays/dev/configmap-common-patch.yaml b/deployment/cicd/kustomize/overlays/dev/configmap-common-patch.yaml index 26f5f19..a707506 100644 --- a/deployment/cicd/kustomize/overlays/dev/configmap-common-patch.yaml +++ b/deployment/cicd/kustomize/overlays/dev/configmap-common-patch.yaml @@ -4,5 +4,8 @@ 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" # 5์‹œ๊ฐ„ + JWT_REFRESH_TOKEN_VALIDITY: "86400000" + REDIS_PORT: "6379" SPRING_PROFILES_ACTIVE: "dev" - DDL_AUTO: "update" \ No newline at end of file + DDL_AUTO: "update" diff --git a/deployment/cicd/kustomize/overlays/dev/deployment-patch.yaml b/deployment/cicd/kustomize/overlays/dev/deployment-patch.yaml new file mode 100644 index 0000000..dd57639 --- /dev/null +++ b/deployment/cicd/kustomize/overlays/dev/deployment-patch.yaml @@ -0,0 +1,89 @@ +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 +--- +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 +--- +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 +--- +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 +--- +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 \ No newline at end of file diff --git a/deployment/cicd/kustomize/overlays/dev/ingress-patch.yaml b/deployment/cicd/kustomize/overlays/dev/ingress-patch.yaml index 3f3cf11..542a5d9 100644 --- a/deployment/cicd/kustomize/overlays/dev/ingress-patch.yaml +++ b/deployment/cicd/kustomize/overlays/dev/ingress-patch.yaml @@ -6,5 +6,43 @@ metadata: 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 \ No newline at end of file + - 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 diff --git a/deployment/cicd/kustomize/overlays/dev/kustomization.yaml b/deployment/cicd/kustomize/overlays/dev/kustomization.yaml index c947971..b8f54ed 100644 --- a/deployment/cicd/kustomize/overlays/dev/kustomization.yaml +++ b/deployment/cicd/kustomize/overlays/dev/kustomization.yaml @@ -4,16 +4,30 @@ kind: Kustomization namespace: phonebill-dev resources: -- ../../base + - ../../base + +patchesStrategicMerge: + - configmap-common-patch.yaml + - deployment-patch.yaml + - ingress-patch.yaml + - secret-common-patch.yaml + - secret-user-service-patch.yaml + - secret-bill-service-patch.yaml + - secret-product-service-patch.yaml + +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 + +namePrefix: dev- commonLabels: - env: dev - -patchesStrategicMerge: -- configmap-common-patch.yaml -- secret-common-patch.yaml -- ingress-patch.yaml -- replica-patch.yaml -- secret-user-service-patch.yaml -- secret-bill-service-patch.yaml -- secret-product-service-patch.yaml \ No newline at end of file + environment: dev \ No newline at end of file diff --git a/deployment/cicd/kustomize/overlays/dev/replica-patch.yaml b/deployment/cicd/kustomize/overlays/dev/replica-patch.yaml deleted file mode 100644 index e740cb1..0000000 --- a/deployment/cicd/kustomize/overlays/dev/replica-patch.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# Replica count patches for dev environment -apiVersion: apps/v1 -kind: Deployment -metadata: - name: api-gateway -spec: - replicas: 1 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: user-service -spec: - replicas: 1 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: bill-service -spec: - replicas: 1 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: product-service -spec: - replicas: 1 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kos-mock -spec: - replicas: 1 \ No newline at end of file diff --git a/deployment/cicd/kustomize/overlays/dev/secret-bill-service-patch.yaml b/deployment/cicd/kustomize/overlays/dev/secret-bill-service-patch.yaml index bd10cde..40b58fe 100644 --- a/deployment/cicd/kustomize/overlays/dev/secret-bill-service-patch.yaml +++ b/deployment/cicd/kustomize/overlays/dev/secret-bill-service-patch.yaml @@ -5,4 +5,6 @@ metadata: type: Opaque stringData: DB_HOST: "bill-inquiry-postgres-dev-postgresql" - DB_PASSWORD: "BillUser2025!" \ No newline at end of file + DB_NAME: "bill_inquiry_db" + DB_USERNAME: "bill_inquiry_user" + DB_PASSWORD: "BillUser2025!" diff --git a/deployment/cicd/kustomize/overlays/dev/secret-common-patch.yaml b/deployment/cicd/kustomize/overlays/dev/secret-common-patch.yaml index 0d79217..f32a832 100644 --- a/deployment/cicd/kustomize/overlays/dev/secret-common-patch.yaml +++ b/deployment/cicd/kustomize/overlays/dev/secret-common-patch.yaml @@ -4,5 +4,6 @@ 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!" \ No newline at end of file + REDIS_PASSWORD: "Redis2025Dev!" diff --git a/deployment/cicd/kustomize/overlays/dev/secret-product-service-patch.yaml b/deployment/cicd/kustomize/overlays/dev/secret-product-service-patch.yaml index bfe2059..e651e74 100644 --- a/deployment/cicd/kustomize/overlays/dev/secret-product-service-patch.yaml +++ b/deployment/cicd/kustomize/overlays/dev/secret-product-service-patch.yaml @@ -5,4 +5,6 @@ metadata: type: Opaque stringData: DB_HOST: "product-change-postgres-dev-postgresql" - DB_PASSWORD: "ProductUser2025!" \ No newline at end of file + DB_NAME: "product_change_db" + DB_USERNAME: "product_change_user" + DB_PASSWORD: "ProductUser2025!" diff --git a/deployment/cicd/kustomize/overlays/dev/secret-user-service-patch.yaml b/deployment/cicd/kustomize/overlays/dev/secret-user-service-patch.yaml index 6ffe745..91a2a16 100644 --- a/deployment/cicd/kustomize/overlays/dev/secret-user-service-patch.yaml +++ b/deployment/cicd/kustomize/overlays/dev/secret-user-service-patch.yaml @@ -5,4 +5,6 @@ metadata: type: Opaque stringData: DB_HOST: "auth-postgres-dev-postgresql" - DB_PASSWORD: "AuthUser2025!" \ No newline at end of file + DB_NAME: "phonebill_auth" + DB_USERNAME: "auth_user" + DB_PASSWORD: "AuthUser2025!" diff --git a/deployment/cicd/kustomize/overlays/prod/configmap-common-patch.yaml b/deployment/cicd/kustomize/overlays/prod/configmap-common-patch.yaml index 20ffe94..8ebe568 100644 --- a/deployment/cicd/kustomize/overlays/prod/configmap-common-patch.yaml +++ b/deployment/cicd/kustomize/overlays/prod/configmap-common-patch.yaml @@ -3,6 +3,9 @@ kind: ConfigMap metadata: name: cm-common data: - CORS_ALLOWED_ORIGINS: "https://phonebill.example.com,https://phonebill-app.example.com" + CORS_ALLOWED_ORIGINS: "https://phonebill.20.214.196.128.nip.io" + JWT_ACCESS_TOKEN_VALIDITY: "3600000" # 1์‹œ๊ฐ„ + JWT_REFRESH_TOKEN_VALIDITY: "86400000" + REDIS_PORT: "6379" SPRING_PROFILES_ACTIVE: "prod" - DDL_AUTO: "validate" \ No newline at end of file + DDL_AUTO: "validate" diff --git a/deployment/cicd/kustomize/overlays/prod/deployment-patch.yaml b/deployment/cicd/kustomize/overlays/prod/deployment-patch.yaml new file mode 100644 index 0000000..eacf315 --- /dev/null +++ b/deployment/cicd/kustomize/overlays/prod/deployment-patch.yaml @@ -0,0 +1,89 @@ +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 +--- +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 +--- +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 +--- +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 +--- +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 \ No newline at end of file diff --git a/deployment/cicd/kustomize/overlays/prod/ingress-patch.yaml b/deployment/cicd/kustomize/overlays/prod/ingress-patch.yaml index fc2b6a0..554fae8 100644 --- a/deployment/cicd/kustomize/overlays/prod/ingress-patch.yaml +++ b/deployment/cicd/kustomize/overlays/prod/ingress-patch.yaml @@ -7,10 +7,50 @@ metadata: nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/force-ssl-redirect: "true" cert-manager.io/cluster-issuer: "letsencrypt-prod" + nginx.ingress.kubernetes.io/ssl-protocols: "TLSv1.2 TLSv1.3" + nginx.ingress.kubernetes.io/ssl-ciphers: "ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-GCM-SHA384" spec: + ingressClassName: nginx tls: - hosts: - - phonebill-api.example.com + - phonebill.20.214.196.128.nip.io secretName: phonebill-prod-tls rules: - - host: phonebill-api.example.com \ No newline at end of file + - host: phonebill.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 diff --git a/deployment/cicd/kustomize/overlays/prod/kustomization.yaml b/deployment/cicd/kustomize/overlays/prod/kustomization.yaml index 783de23..d8f81dc 100644 --- a/deployment/cicd/kustomize/overlays/prod/kustomization.yaml +++ b/deployment/cicd/kustomize/overlays/prod/kustomization.yaml @@ -4,10 +4,30 @@ kind: Kustomization namespace: phonebill-prod resources: -- ../../base + - ../../base + +patchesStrategicMerge: + - configmap-common-patch.yaml + - deployment-patch.yaml + - ingress-patch.yaml + - secret-common-patch.yaml + - secret-user-service-patch.yaml + - secret-bill-service-patch.yaml + - secret-product-service-patch.yaml + +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 + +namePrefix: prod- commonLabels: - env: prod - -patchesStrategicMerge: -- env-patches.yaml \ No newline at end of file + environment: prod \ No newline at end of file diff --git a/deployment/cicd/kustomize/overlays/prod/replica-patch.yaml b/deployment/cicd/kustomize/overlays/prod/replica-patch.yaml deleted file mode 100644 index 602462f..0000000 --- a/deployment/cicd/kustomize/overlays/prod/replica-patch.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# Replica count patches for production environment -apiVersion: apps/v1 -kind: Deployment -metadata: - name: api-gateway -spec: - replicas: 3 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: user-service -spec: - replicas: 3 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: bill-service -spec: - replicas: 3 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: product-service -spec: - replicas: 3 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kos-mock -spec: - replicas: 2 \ No newline at end of file diff --git a/deployment/cicd/kustomize/overlays/prod/secret-bill-service-patch.yaml b/deployment/cicd/kustomize/overlays/prod/secret-bill-service-patch.yaml index 7af33cf..52c87e1 100644 --- a/deployment/cicd/kustomize/overlays/prod/secret-bill-service-patch.yaml +++ b/deployment/cicd/kustomize/overlays/prod/secret-bill-service-patch.yaml @@ -5,4 +5,6 @@ metadata: type: Opaque stringData: DB_HOST: "bill-inquiry-postgres-prod-postgresql" - DB_PASSWORD: "BillUserProd$ecure2025!" \ No newline at end of file + DB_NAME: "bill_inquiry_db" + DB_USERNAME: "bill_inquiry_user" + DB_PASSWORD: "BillUser2025Prod!" diff --git a/deployment/cicd/kustomize/overlays/prod/secret-common-patch.yaml b/deployment/cicd/kustomize/overlays/prod/secret-common-patch.yaml index 2b200af..13f59ad 100644 --- a/deployment/cicd/kustomize/overlays/prod/secret-common-patch.yaml +++ b/deployment/cicd/kustomize/overlays/prod/secret-common-patch.yaml @@ -4,5 +4,6 @@ metadata: name: secret-common type: Opaque stringData: + JWT_SECRET: "prod7Yo9qaJ6FBD/Thl2/j6/SFAfNwUorAY1ZcWO2KI7uA4bmVLOCPxE9hYuUpRCOkgV2UF2DdHXtqHi3+BU/prod" REDIS_HOST: "redis-cache-prod-master" - REDIS_PASSWORD: "Redis2025Prod$ecure!" \ No newline at end of file + REDIS_PASSWORD: "Redis2025Prod!" diff --git a/deployment/cicd/kustomize/overlays/prod/secret-product-service-patch.yaml b/deployment/cicd/kustomize/overlays/prod/secret-product-service-patch.yaml index 0443053..4f3907c 100644 --- a/deployment/cicd/kustomize/overlays/prod/secret-product-service-patch.yaml +++ b/deployment/cicd/kustomize/overlays/prod/secret-product-service-patch.yaml @@ -5,4 +5,6 @@ metadata: type: Opaque stringData: DB_HOST: "product-change-postgres-prod-postgresql" - DB_PASSWORD: "ProductUserProd$ecure2025!" \ No newline at end of file + DB_NAME: "product_change_db" + DB_USERNAME: "product_change_user" + DB_PASSWORD: "ProductUser2025Prod!" diff --git a/deployment/cicd/kustomize/overlays/prod/secret-user-service-patch.yaml b/deployment/cicd/kustomize/overlays/prod/secret-user-service-patch.yaml index 5264c44..71a6aff 100644 --- a/deployment/cicd/kustomize/overlays/prod/secret-user-service-patch.yaml +++ b/deployment/cicd/kustomize/overlays/prod/secret-user-service-patch.yaml @@ -5,4 +5,6 @@ metadata: type: Opaque stringData: DB_HOST: "auth-postgres-prod-postgresql" - DB_PASSWORD: "AuthUserProd$ecure2025!" \ No newline at end of file + DB_NAME: "phonebill_auth" + DB_USERNAME: "auth_user" + DB_PASSWORD: "AuthUser2025Prod!" diff --git a/deployment/cicd/kustomize/overlays/staging/configmap-common-patch.yaml b/deployment/cicd/kustomize/overlays/staging/configmap-common-patch.yaml index aaf2d7b..7098d5c 100644 --- a/deployment/cicd/kustomize/overlays/staging/configmap-common-patch.yaml +++ b/deployment/cicd/kustomize/overlays/staging/configmap-common-patch.yaml @@ -3,6 +3,9 @@ kind: ConfigMap metadata: name: cm-common data: - CORS_ALLOWED_ORIGINS: "https://phonebill-staging.example.com,https://phonebill.staging.example.com" + CORS_ALLOWED_ORIGINS: "https://phonebill-staging.20.214.196.128.nip.io" + JWT_ACCESS_TOKEN_VALIDITY: "18000000" # 5์‹œ๊ฐ„ + JWT_REFRESH_TOKEN_VALIDITY: "86400000" + REDIS_PORT: "6379" SPRING_PROFILES_ACTIVE: "staging" - DDL_AUTO: "validate" \ No newline at end of file + DDL_AUTO: "validate" diff --git a/deployment/cicd/kustomize/overlays/staging/deployment-patch.yaml b/deployment/cicd/kustomize/overlays/staging/deployment-patch.yaml new file mode 100644 index 0000000..0ebeb97 --- /dev/null +++ b/deployment/cicd/kustomize/overlays/staging/deployment-patch.yaml @@ -0,0 +1,89 @@ +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 +--- +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 +--- +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 +--- +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 +--- +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 \ No newline at end of file diff --git a/deployment/cicd/kustomize/overlays/staging/ingress-patch.yaml b/deployment/cicd/kustomize/overlays/staging/ingress-patch.yaml index 5b4d5a8..354aca2 100644 --- a/deployment/cicd/kustomize/overlays/staging/ingress-patch.yaml +++ b/deployment/cicd/kustomize/overlays/staging/ingress-patch.yaml @@ -7,9 +7,47 @@ metadata: nginx.ingress.kubernetes.io/ssl-redirect: "true" cert-manager.io/cluster-issuer: "letsencrypt-prod" spec: + ingressClassName: nginx tls: - hosts: - - phonebill-api-staging.example.com + - phonebill-staging.20.214.196.128.nip.io secretName: phonebill-staging-tls rules: - - host: phonebill-api-staging.example.com \ No newline at end of file + - host: phonebill-staging.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 diff --git a/deployment/cicd/kustomize/overlays/staging/kustomization.yaml b/deployment/cicd/kustomize/overlays/staging/kustomization.yaml index 56b9c51..42168ed 100644 --- a/deployment/cicd/kustomize/overlays/staging/kustomization.yaml +++ b/deployment/cicd/kustomize/overlays/staging/kustomization.yaml @@ -4,16 +4,30 @@ kind: Kustomization namespace: phonebill-staging resources: -- ../../base + - ../../base + +patchesStrategicMerge: + - configmap-common-patch.yaml + - deployment-patch.yaml + - ingress-patch.yaml + - secret-common-patch.yaml + - secret-user-service-patch.yaml + - secret-bill-service-patch.yaml + - secret-product-service-patch.yaml + +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 + +namePrefix: staging- commonLabels: - env: staging - -patchesStrategicMerge: -- configmap-common-patch.yaml -- secret-common-patch.yaml -- ingress-patch.yaml -- replica-patch.yaml -- secret-user-service-patch.yaml -- secret-bill-service-patch.yaml -- secret-product-service-patch.yaml \ No newline at end of file + environment: staging \ No newline at end of file diff --git a/deployment/cicd/kustomize/overlays/staging/replica-patch.yaml b/deployment/cicd/kustomize/overlays/staging/replica-patch.yaml deleted file mode 100644 index 9e8c187..0000000 --- a/deployment/cicd/kustomize/overlays/staging/replica-patch.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# Replica count patches for staging environment -apiVersion: apps/v1 -kind: Deployment -metadata: - name: api-gateway -spec: - replicas: 2 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: user-service -spec: - replicas: 2 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: bill-service -spec: - replicas: 2 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: product-service -spec: - replicas: 2 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kos-mock -spec: - replicas: 1 \ No newline at end of file diff --git a/deployment/cicd/kustomize/overlays/staging/secret-bill-service-patch.yaml b/deployment/cicd/kustomize/overlays/staging/secret-bill-service-patch.yaml index 27c3201..03241fe 100644 --- a/deployment/cicd/kustomize/overlays/staging/secret-bill-service-patch.yaml +++ b/deployment/cicd/kustomize/overlays/staging/secret-bill-service-patch.yaml @@ -5,4 +5,6 @@ metadata: type: Opaque stringData: DB_HOST: "bill-inquiry-postgres-staging-postgresql" - DB_PASSWORD: "BillUserStaging2025!" \ No newline at end of file + DB_NAME: "bill_inquiry_db" + DB_USERNAME: "bill_inquiry_user" + DB_PASSWORD: "BillUser2025Staging!" diff --git a/deployment/cicd/kustomize/overlays/staging/secret-common-patch.yaml b/deployment/cicd/kustomize/overlays/staging/secret-common-patch.yaml index ecf7b9e..d6abb77 100644 --- a/deployment/cicd/kustomize/overlays/staging/secret-common-patch.yaml +++ b/deployment/cicd/kustomize/overlays/staging/secret-common-patch.yaml @@ -4,5 +4,6 @@ metadata: name: secret-common type: Opaque stringData: + JWT_SECRET: "staging5Yo9qaJ6FBD/Thl2/j6/SFAfNwUorAY1ZcWO2KI7uA4bmVLOCPxE9hYuUpRCOkgV2UF2DdHXtqHi3+BU/staging" REDIS_HOST: "redis-cache-staging-master" - REDIS_PASSWORD: "Redis2025Staging!" \ No newline at end of file + REDIS_PASSWORD: "Redis2025Staging!" diff --git a/deployment/cicd/kustomize/overlays/staging/secret-product-service-patch.yaml b/deployment/cicd/kustomize/overlays/staging/secret-product-service-patch.yaml index dbe9be5..249d077 100644 --- a/deployment/cicd/kustomize/overlays/staging/secret-product-service-patch.yaml +++ b/deployment/cicd/kustomize/overlays/staging/secret-product-service-patch.yaml @@ -5,4 +5,6 @@ metadata: type: Opaque stringData: DB_HOST: "product-change-postgres-staging-postgresql" - DB_PASSWORD: "ProductUserStaging2025!" \ No newline at end of file + DB_NAME: "product_change_db" + DB_USERNAME: "product_change_user" + DB_PASSWORD: "ProductUser2025Staging!" diff --git a/deployment/cicd/kustomize/overlays/staging/secret-user-service-patch.yaml b/deployment/cicd/kustomize/overlays/staging/secret-user-service-patch.yaml index 8d1bb8c..b1bd753 100644 --- a/deployment/cicd/kustomize/overlays/staging/secret-user-service-patch.yaml +++ b/deployment/cicd/kustomize/overlays/staging/secret-user-service-patch.yaml @@ -5,4 +5,6 @@ metadata: type: Opaque stringData: DB_HOST: "auth-postgres-staging-postgresql" - DB_PASSWORD: "AuthUserStaging2025!" \ No newline at end of file + DB_NAME: "phonebill_auth" + DB_USERNAME: "auth_user" + DB_PASSWORD: "AuthUser2025Staging!" diff --git a/deployment/cicd/scripts/deploy.sh b/deployment/cicd/scripts/deploy.sh old mode 100644 new mode 100755 index 5ed9fef..c55550d --- a/deployment/cicd/scripts/deploy.sh +++ b/deployment/cicd/scripts/deploy.sh @@ -1,474 +1,82 @@ #!/bin/bash +set -e -# Manual Deployment Script for phonebill Microservices -# Usage: ./deploy.sh [service1,service2,...] [options] -# Example: ./deploy.sh dev all --skip-build -# Example: ./deploy.sh prod user-service,bill-service --force +ENVIRONMENT=${1:-dev} +IMAGE_TAG=${2:-latest} -set -euo pipefail +echo "๐Ÿš€ Starting deployment to ${ENVIRONMENT} environment with image tag: ${IMAGE_TAG}" -# Script configuration -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)" -CICD_DIR="${PROJECT_ROOT}/deployment/cicd" -K8S_DIR="${PROJECT_ROOT}/deployment/k8s" +# ํ™˜๊ฒฝ ๊ฒ€์ฆ +if [[ ! "$ENVIRONMENT" =~ ^(dev|staging|prod)$ ]]; then + echo "โŒ Error: Invalid environment. Use dev, staging, or prod" + exit 1 +fi -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color +# Kustomize ์„ค์น˜ ํ™•์ธ +if ! command -v kustomize &> /dev/null; then + echo "๐Ÿ“ฆ Installing Kustomize..." + curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash + sudo mv kustomize /usr/local/bin/ +fi -# Logging functions -log_info() { - echo -e "${BLUE}[INFO]${NC} $1" -} +# kubectl ์—ฐ๊ฒฐ ํ™•์ธ +if ! kubectl cluster-info &> /dev/null; then + echo "โŒ Error: Unable to connect to Kubernetes cluster" + echo "Please ensure kubectl is configured properly" + exit 1 +fi -log_warn() { - echo -e "${YELLOW}[WARN]${NC} $1" -} +# ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ƒ์„ฑ +echo "๐Ÿ”ง Creating namespace phonebill-${ENVIRONMENT} if not exists..." +kubectl create namespace phonebill-${ENVIRONMENT} --dry-run=client -o yaml | kubectl apply -f - -log_error() { - echo -e "${RED}[ERROR]${NC} $1" -} +# ํ™˜๊ฒฝ๋ณ„ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™ +cd deployment/cicd/kustomize/overlays/${ENVIRONMENT} -log_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" -} +echo "๐Ÿท๏ธ Updating image tags..." -# Usage information -show_usage() { - cat << EOF -Usage: $0 [services] [options] +# ๊ฐ ์„œ๋น„์Šค ์ด๋ฏธ์ง€ ํƒœ๊ทธ ์—…๋ฐ์ดํŠธ +kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/api-gateway:${ENVIRONMENT}-${IMAGE_TAG} +kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/user-service:${ENVIRONMENT}-${IMAGE_TAG} +kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/bill-service:${ENVIRONMENT}-${IMAGE_TAG} +kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/product-service:${ENVIRONMENT}-${IMAGE_TAG} +kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/kos-mock:${ENVIRONMENT}-${IMAGE_TAG} -Arguments: - environment Target environment (dev|staging|prod) - services Services to deploy (default: all) - Options: all, api-gateway, user-service, bill-service, product-service, kos-mock - Multiple services: service1,service2,service3 +echo "๐Ÿ“‹ Applying Kubernetes manifests..." -Options: - --skip-build Skip Gradle build step - --skip-test Skip unit tests during build - --skip-push Skip container image push - --force Force deployment even if no changes - --dry-run Show what would be deployed without actually deploying - --help Show this help message +# ๋ฐฐํฌ ์‹คํ–‰ +kubectl apply -k . -Examples: - $0 dev # Deploy all services to dev - $0 staging user-service # Deploy user-service to staging - $0 prod api-gateway,bill-service # Deploy specific services to prod - $0 dev all --skip-build # Deploy without building - $0 staging all --dry-run # Preview deployment +echo "โณ Waiting for deployments to be ready..." -Environment Files: - dev: ${CICD_DIR}/config/deploy_env_vars_dev - staging: ${CICD_DIR}/config/deploy_env_vars_staging - prod: ${CICD_DIR}/config/deploy_env_vars_prod -EOF -} +# ๋ฐฐํฌ ์ƒํƒœ ํ™•์ธ +kubectl rollout status deployment/${ENVIRONMENT}-api-gateway -n phonebill-${ENVIRONMENT} --timeout=300s +kubectl rollout status deployment/${ENVIRONMENT}-user-service -n phonebill-${ENVIRONMENT} --timeout=300s +kubectl rollout status deployment/${ENVIRONMENT}-bill-service -n phonebill-${ENVIRONMENT} --timeout=300s +kubectl rollout status deployment/${ENVIRONMENT}-product-service -n phonebill-${ENVIRONMENT} --timeout=300s +kubectl rollout status deployment/${ENVIRONMENT}-kos-mock -n phonebill-${ENVIRONMENT} --timeout=300s -# Parse command line arguments -parse_arguments() { - if [[ $# -eq 0 ]] || [[ "$1" == "--help" ]]; then - show_usage - exit 0 - fi +echo "๐Ÿ” Health Check..." - ENVIRONMENT="$1" - shift +# API Gateway Health Check +GATEWAY_POD=$(kubectl get pod -n phonebill-${ENVIRONMENT} -l app=api-gateway -o jsonpath='{.items[0].metadata.name}') +if kubectl -n phonebill-${ENVIRONMENT} exec $GATEWAY_POD -- curl -f http://localhost:8080/actuator/health > /dev/null 2>&1; then + echo "โœ… API Gateway is healthy!" +else + echo "โš ๏ธ API Gateway health check failed, but deployment completed" +fi - # Validate environment - if [[ ! "$ENVIRONMENT" =~ ^(dev|staging|prod)$ ]]; then - log_error "Invalid environment: $ENVIRONMENT" - log_error "Valid environments: dev, staging, prod" - exit 1 - fi - - # Set services (default to 'all') - SERVICES_TO_DEPLOY="all" - if [[ $# -gt 0 ]] && [[ ! "$1" =~ ^-- ]]; then - SERVICES_TO_DEPLOY="$1" - shift - fi - - # Parse options - SKIP_BUILD=false - SKIP_TEST=false - SKIP_PUSH=false - FORCE_DEPLOY=false - DRY_RUN=false - - while [[ $# -gt 0 ]]; do - case $1 in - --skip-build) - SKIP_BUILD=true - shift - ;; - --skip-test) - SKIP_TEST=true - shift - ;; - --skip-push) - SKIP_PUSH=true - shift - ;; - --force) - FORCE_DEPLOY=true - shift - ;; - --dry-run) - DRY_RUN=true - shift - ;; - *) - log_error "Unknown option: $1" - show_usage - exit 1 - ;; - esac - done -} - -# Load environment configuration -load_environment_config() { - local config_file="${CICD_DIR}/config/deploy_env_vars_${ENVIRONMENT}" - - if [[ ! -f "$config_file" ]]; then - log_error "Configuration file not found: $config_file" - exit 1 - fi - - # Source the configuration file - set -a # automatically export all variables - source "$config_file" - set +a - - log_info "Loaded configuration from $config_file" -} - -# Validate prerequisites -validate_prerequisites() { - local missing_tools=() - - # Check required tools - command -v gradle >/dev/null 2>&1 || missing_tools+=("gradle") - command -v docker >/dev/null 2>&1 || missing_tools+=("docker") - command -v kubectl >/dev/null 2>&1 || missing_tools+=("kubectl") - command -v az >/dev/null 2>&1 || missing_tools+=("azure-cli") - - if [[ ${#missing_tools[@]} -ne 0 ]]; then - log_error "Missing required tools: ${missing_tools[*]}" - log_error "Please install the missing tools and try again" - exit 1 - fi - - # Check if we're in the project root - if [[ ! -f "${PROJECT_ROOT}/settings.gradle" ]]; then - log_error "Not in phonebill project root directory" - exit 1 - fi - - # Check Azure login - if ! az account show >/dev/null 2>&1; then - log_error "Not logged into Azure CLI. Please run: az login" - exit 1 - fi - - # Check kubectl context - if ! kubectl config current-context >/dev/null 2>&1; then - log_warn "No kubectl context set. Will attempt to configure AKS credentials" - fi - - log_success "Prerequisites validation passed" -} - -# Resolve services list -resolve_services() { - if [[ "$SERVICES_TO_DEPLOY" == "all" ]]; then - SERVICE_LIST=(${SERVICES//,/ }) - else - IFS=',' read -ra SERVICE_LIST <<< "$SERVICES_TO_DEPLOY" - fi - - log_info "Services to deploy: ${SERVICE_LIST[*]}" - - # Validate service names - local valid_services=(${SERVICES//,/ }) - for service in "${SERVICE_LIST[@]}"; do - if [[ ! " ${valid_services[*]} " =~ " ${service} " ]]; then - log_error "Invalid service name: $service" - log_error "Valid services: ${valid_services[*]}" - exit 1 - fi - done -} - -# Build services -build_services() { - if [[ "$SKIP_BUILD" == true ]]; then - log_info "Skipping build step" - return 0 - fi - - log_info "Building services with Gradle..." - cd "$PROJECT_ROOT" - - for service in "${SERVICE_LIST[@]}"; do - log_info "Building $service..." - - local build_cmd="./gradlew ${service}:clean ${service}:build --no-daemon --parallel" - - if [[ "$SKIP_TEST" == true ]]; then - build_cmd="$build_cmd -x test" - fi - - if [[ "$DRY_RUN" == true ]]; then - log_info "[DRY-RUN] Would execute: $build_cmd" - else - if ! $build_cmd; then - log_error "Build failed for $service" - exit 1 - fi - fi - done - - log_success "Build completed successfully" -} - -# Build and push container images -build_and_push_images() { - if [[ "$SKIP_PUSH" == true ]]; then - log_info "Skipping container image build and push" - return 0 - fi - - log_info "Building and pushing container images..." - - # Generate image tag - local timestamp=$(date +%Y%m%d-%H%M%S) - local build_number="${BUILD_NUMBER:-$(date +%s)}" - IMAGE_TAG="${build_number}-${ENVIRONMENT}-${timestamp}" - - log_info "Using image tag: $IMAGE_TAG" - - # Login to ACR - if [[ "$DRY_RUN" == false ]]; then - log_info "Logging into Azure Container Registry..." - az acr login --name "$ACR_NAME" - fi - - for service in "${SERVICE_LIST[@]}"; do - log_info "Building container image for $service..." - - local image_name="${REGISTRY_URL}/phonebill/${service}" - local service_dir="${PROJECT_ROOT}/${service}" - - if [[ ! -d "$service_dir" ]]; then - log_error "Service directory not found: $service_dir" - exit 1 - fi - - if [[ ! -f "${service_dir}/Dockerfile" ]]; then - log_error "Dockerfile not found: ${service_dir}/Dockerfile" - exit 1 - fi - - if [[ "$DRY_RUN" == true ]]; then - log_info "[DRY-RUN] Would build and push: ${image_name}:${IMAGE_TAG}" - else - # Build image - docker build \ - -t "${image_name}:${IMAGE_TAG}" \ - -t "${image_name}:latest-${ENVIRONMENT}" \ - "$service_dir" - - # Push image - docker push "${image_name}:${IMAGE_TAG}" - docker push "${image_name}:latest-${ENVIRONMENT}" - fi - done - - log_success "Container images built and pushed successfully" -} - -# Configure kubectl -configure_kubectl() { - log_info "Configuring kubectl for AKS cluster..." - - if [[ "$DRY_RUN" == false ]]; then - az aks get-credentials \ - --resource-group "$AZURE_RESOURCE_GROUP" \ - --name "$AKS_CLUSTER_NAME" \ - --overwrite-existing - fi - - log_success "kubectl configured for $AKS_CLUSTER_NAME" -} - -# Deploy to Kubernetes -deploy_to_kubernetes() { - log_info "Deploying services to Kubernetes namespace: $AKS_NAMESPACE" - - # Ensure namespace exists - if [[ "$DRY_RUN" == false ]]; then - kubectl create namespace "$AKS_NAMESPACE" --dry-run=client -o yaml | kubectl apply -f - - fi - - for service in "${SERVICE_LIST[@]}"; do - log_info "Deploying $service..." - - local kustomize_path="${K8S_DIR}/${service}" - local overlay_path="${kustomize_path}/${KUSTOMIZE_OVERLAY}" - - if [[ ! -d "$overlay_path" ]]; then - log_error "Kustomize overlay not found: $overlay_path" - exit 1 - fi - - if [[ "$DRY_RUN" == true ]]; then - log_info "[DRY-RUN] Would deploy $service using: kubectl apply -k $overlay_path -n $AKS_NAMESPACE" - else - # Update image tag in kustomization.yaml if IMAGE_TAG is set - if [[ -n "${IMAGE_TAG:-}" ]]; then - local kustomization_file="${overlay_path}/kustomization.yaml" - if [[ -f "$kustomization_file" ]]; then - # Backup original file - cp "$kustomization_file" "${kustomization_file}.backup" - - # Update image tag - sed -i "s|newTag:.*|newTag: ${IMAGE_TAG}|" "$kustomization_file" - fi - fi - - # Deploy using kubectl + kustomize - kubectl apply -k "$overlay_path" -n "$AKS_NAMESPACE" - - # Wait for rollout to complete - kubectl rollout status deployment/"$service" -n "$AKS_NAMESPACE" --timeout=300s - - # Restore backup if exists - if [[ -f "${kustomization_file}.backup" ]]; then - mv "${kustomization_file}.backup" "$kustomization_file" - fi - fi - done - - log_success "Deployment completed successfully" -} - -# Perform health checks -perform_health_checks() { - if [[ "$DRY_RUN" == true ]]; then - log_info "[DRY-RUN] Would perform health checks for deployed services" - return 0 - fi - - log_info "Performing health checks..." - - for service in "${SERVICE_LIST[@]}"; do - log_info "Health checking $service..." - - local max_retries=${HEALTH_CHECK_RETRY:-10} - local retry_count=0 - local is_healthy=false - - while [[ $retry_count -lt $max_retries ]]; do - if kubectl get deployment "$service" -n "$AKS_NAMESPACE" -o json | \ - jq -e '.status.readyReplicas == .status.replicas and .status.replicas > 0' >/dev/null 2>&1; then - is_healthy=true - break - fi - - retry_count=$((retry_count + 1)) - log_info "Health check attempt $retry_count/$max_retries for $service..." - sleep 30 - done - - if [[ "$is_healthy" == true ]]; then - log_success "$service is healthy" - else - log_error "$service failed health check" - kubectl describe deployment "$service" -n "$AKS_NAMESPACE" - exit 1 - fi - done - - log_success "All services passed health checks" -} - -# Show deployment summary -show_summary() { - log_info "=========================================" - log_info "Deployment Summary" - log_info "=========================================" - log_info "Environment: $ENVIRONMENT" - log_info "Namespace: $AKS_NAMESPACE" - log_info "Services: ${SERVICE_LIST[*]}" - - if [[ -n "${IMAGE_TAG:-}" ]]; then - log_info "Image Tag: $IMAGE_TAG" - fi - - log_info "Options:" - log_info " Skip Build: $SKIP_BUILD" - log_info " Skip Test: $SKIP_TEST" - log_info " Skip Push: $SKIP_PUSH" - log_info " Force Deploy: $FORCE_DEPLOY" - log_info " Dry Run: $DRY_RUN" - log_info "=========================================" -} - -# Cleanup function -cleanup() { - local exit_code=$? - if [[ $exit_code -ne 0 ]]; then - log_error "Deployment failed with exit code: $exit_code" - - # Show recent events for debugging - if [[ "$DRY_RUN" == false ]] && command -v kubectl >/dev/null 2>&1; then - log_info "Recent events in namespace $AKS_NAMESPACE:" - kubectl get events -n "$AKS_NAMESPACE" --sort-by='.lastTimestamp' --field-selector type=Warning | tail -10 - fi - fi -} - -# Main execution function -main() { - # Set up error handling - trap cleanup EXIT - - log_info "๐Ÿš€ Starting phonebill deployment script" - - # Parse arguments and validate - parse_arguments "$@" - show_summary - - # Load configuration and validate prerequisites - load_environment_config - validate_prerequisites - resolve_services - - # Execute deployment steps - build_services - build_and_push_images - configure_kubectl - deploy_to_kubernetes - perform_health_checks - - log_success "๐ŸŽ‰ Deployment completed successfully!" - - if [[ "$DRY_RUN" == false ]]; then - log_info "You can check the deployment status with:" - log_info " kubectl get pods -n $AKS_NAMESPACE" - log_info " kubectl get services -n $AKS_NAMESPACE" - log_info " kubectl get ingress -n $AKS_NAMESPACE" - fi -} - -# Execute main function if script is run directly -if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then - main "$@" -fi \ No newline at end of file +echo "" +echo "โœ… Deployment completed successfully!" +echo "" +echo "๐Ÿ“Š Deployment Status:" +kubectl get pods -n phonebill-${ENVIRONMENT} -l app=phonebill +echo "" +echo "๐ŸŒ Services:" +kubectl get services -n phonebill-${ENVIRONMENT} +echo "" +echo "๐Ÿ”— Ingress:" +kubectl get ingress -n phonebill-${ENVIRONMENT} +echo "" +echo "๐ŸŽฏ Environment: ${ENVIRONMENT}" +echo "๐Ÿท๏ธ Image Tag: ${ENVIRONMENT}-${IMAGE_TAG}" \ No newline at end of file