Jenkins CI/CD 파이프라인 구축 완료

- Kustomize 기반 환경별 배포 구성 (dev/staging/prod)
- Jenkins 파이프라인 with SonarQube 품질 게이트
- 파드 자동 정리 및 보안 강화 설정
- 환경별 차등 리소스 할당 및 도메인 설정
- 수동 배포 및 검증 스크립트 제공
- 5개 마이크로서비스 병렬 빌드/배포 지원

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
hiondal 2025-09-12 22:29:40 +09:00
parent d12d8c0838
commit 725635fadd
46 changed files with 969 additions and 921 deletions

View File

@ -12,7 +12,7 @@ podTemplate(
slaveConnectTimeout: 300, slaveConnectTimeout: 300,
idleMinutes: 1, idleMinutes: 1,
activeDeadlineSeconds: 3600, activeDeadlineSeconds: 3600,
podRetention: never(), podRetention: never(), // 파드 자동 정리 옵션
yaml: ''' yaml: '''
spec: spec:
terminationGracePeriodSeconds: 3 terminationGracePeriodSeconds: 3
@ -172,7 +172,7 @@ podTemplate(
# 환경별 디렉토리로 이동 # 환경별 디렉토리로 이동
cd deployment/cicd/kustomize/overlays/${environment} cd deployment/cicd/kustomize/overlays/${environment}
# 서비스 목록 (공백으로 구분) # 서비스 목록 정의 (공백으로 구분)
services="api-gateway user-service bill-service product-service kos-mock" services="api-gateway user-service bill-service product-service kos-mock"
# 이미지 태그 업데이트 # 이미지 태그 업데이트
@ -203,7 +203,7 @@ podTemplate(
echo "❌ Pipeline failed with result: ${currentBuild.result}" echo "❌ Pipeline failed with result: ${currentBuild.result}"
} }
} }
} catch (Exception e) { } catch (Exception e) {
currentBuild.result = 'FAILURE' currentBuild.result = 'FAILURE'
echo "❌ Pipeline failed with exception: ${e.getMessage()}" echo "❌ Pipeline failed with exception: ${e.getMessage()}"

View File

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

View File

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

View File

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

View File

@ -1,476 +1,304 @@
# phonebill Jenkins CI/CD 파이프라인 가이드 # phonebill Jenkins CI/CD 파이프라인 구축 가이드
## 📋 프로젝트 정보 ## 📋 개요
**이개발/백엔더**: phonebill 프로젝트의 Jenkins 기반 CI/CD 파이프라인 구축이 완료되었습니다.
### 프로젝트 정보
- **시스템명**: phonebill - **시스템명**: phonebill
- **서비스**: api-gateway, user-service, bill-service, product-service, kos-mock - **서비스**: api-gateway, user-service, bill-service, product-service, kos-mock
- **JDK 버전**: 21 - **JDK 버전**: 21
- **ACR**: acrdigitalgarage01 - **환경**: dev, staging, prod
- **소스 그룹**: rg-digitalgarage-01 - **컨테이너 레지스트리**: acrdigitalgarage01.azurecr.io
- **AKS 클러스터**: aks-digitalgarage-01 - **Kubernetes 클러스터**: aks-digitalgarage-01 (rg-digitalgarage-01)
## 🏗️ Jenkins 서버 환경 구성 ## 🏗️ 구축된 CI/CD 아키텍처
### 필수 플러그인 설치 ### 파이프라인 구성
1. **소스 체크아웃** → Git 소스 코드 가져오기
2. **AKS 설정** → Azure 인증 및 Kubernetes 클러스터 연결
3. **빌드 & SonarQube 분석** → Gradle 빌드, 테스트, 코드 품질 분석
4. **Quality Gate** → SonarQube 품질 게이트 검증
5. **컨테이너 빌드 & 푸시** → Docker 이미지 빌드 및 ACR 푸시
6. **Kustomize 배포** → 환경별 Kubernetes 매니페스트 적용
### Kustomize 구조
``` ```
- Kubernetes deployment/cicd/kustomize/
- Pipeline Utility Steps ├── base/ # 기본 매니페스트
- Docker Pipeline │ ├── kustomization.yaml # Base 리소스 정의
- GitHub │ ├── namespace.yaml # Namespace 정의
- SonarQube Scanner │ ├── common/ # 공통 리소스
- Azure Credentials │ │ ├── cm-common.yaml
│ │ ├── secret-common.yaml
│ │ ├── secret-imagepull.yaml
│ │ └── ingress.yaml
│ └── [서비스별 디렉토리]/ # 각 서비스 매니페스트
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── cm-{서비스명}.yaml # ConfigMap (있는 경우)
│ └── secret-{서비스명}.yaml # Secret (있는 경우)
└── overlays/ # 환경별 오버레이
├── dev/ # 개발 환경
├── staging/ # 스테이징 환경
└── prod/ # 운영 환경
``` ```
### Jenkins Credentials 등록 ## ⚙️ 구성 요소
#### 1. Azure Service Principal ### 1. Jenkins 파이프라인 (Jenkinsfile)
``` - **Pod Template**: Gradle, Podman, Azure-CLI 컨테이너 사용
Manage Jenkins > Credentials > Add Credentials - **자동 정리**: podRetention: never(), 파드 자동 정리 구성
- Kind: Microsoft Azure Service Principal - **병렬 처리**: 각 서비스별 SonarQube 분석 병렬 실행
- ID: azure-credentials - **타임아웃**: 빌드&푸시 30분, Quality Gate 10분 제한
- Subscription ID: {구독ID}
- Client ID: {클라이언트ID}
- Client Secret: {클라이언트시크릿}
- Tenant ID: {테넌트ID}
- Azure Environment: Azure
```
#### 2. ACR Credentials ### 2. 환경별 Configuration
```
- Kind: Username with password
- ID: acr-credentials
- Username: acrdigitalgarage01
- Password: {ACR_PASSWORD}
```
#### 3. Docker Hub Credentials (Rate Limit 해결용) ⚠️ **필수** #### DEV 환경
``` - **네임스페이스**: phonebill-dev
Manage Jenkins > Credentials > Add Credentials - **레플리카**: 1개
- Kind: Username with password - **리소스**: requests(256m CPU, 256Mi Memory), limits(1024m CPU, 1024Mi Memory)
- ID: dockerhub-credentials - **프로파일**: dev, DDL_AUTO: update
- Username: {DOCKERHUB_USERNAME} - **도메인**: phonebill-api.20.214.196.128.nip.io (HTTP)
- Password: {DOCKERHUB_PASSWORD}
```
**⚠️ 중요**: Docker Hub 계정이 없으면 다음 중 하나 선택: #### STAGING 환경
1. Docker Hub 무료 계정 생성 (https://hub.docker.com) - **네임스페이스**: phonebill-staging
2. 또는 Jenkinsfile에서 Docker Hub 로그인 제거 (아래 참조) - **레플리카**: 2개
- **리소스**: requests(512m CPU, 512Mi Memory), limits(2048m CPU, 2048Mi Memory)
- **프로파일**: staging, DDL_AUTO: validate
- **도메인**: phonebill-staging.yourdomain.com (HTTPS)
#### 4. SonarQube Token #### PROD 환경
``` - **네임스페이스**: phonebill-prod
- Kind: Secret text - **레플리카**: 3개
- ID: sonarqube-token - **리소스**: requests(1024m CPU, 1024Mi Memory), limits(4096m CPU, 4096Mi Memory)
- Secret: {SonarQube토큰} - **프로파일**: prod, DDL_AUTO: validate
``` - **도메인**: phonebill.yourdomain.com (HTTPS)
- **보안**: 짧은 JWT 토큰 유효시간
## 📁 Kustomize 디렉토리 구조 ### 3. 스크립트
- **deploy.sh**: 수동 배포 스크립트
- **validate-cicd-setup.sh**: CI/CD 설정 검증 스크립트
## 📦 구축된 파일 목록
### Kustomize 구성 파일
``` ```
deployment/cicd/ deployment/cicd/
├── kustomize/ ├── kustomize/
│ ├── base/ │ ├── base/
│ │ ├── kustomization.yaml │ │ ├── kustomization.yaml
│ │ ├── namespace.yaml │ │ ├── namespace.yaml
│ │ ├── common/ │ │ ├── common/ (4개 파일)
│ │ │ ├── cm-common.yaml │ │ ├── api-gateway/ (3개 파일)
│ │ │ ├── secret-common.yaml │ │ ├── user-service/ (4개 파일)
│ │ │ ├── secret-imagepull.yaml │ │ ├── bill-service/ (4개 파일)
│ │ │ └── ingress.yaml │ │ ├── product-service/ (4개 파일)
│ │ ├── api-gateway/ │ │ └── kos-mock/ (3개 파일)
│ │ ├── user-service/
│ │ ├── bill-service/
│ │ ├── product-service/
│ │ └── kos-mock/
│ └── overlays/ │ └── overlays/
│ ├── dev/ │ ├── dev/ (12개 파일)
│ ├── staging/ │ ├── staging/ (13개 파일)
│ └── prod/ │ └── prod/ (14개 파일)
├── config/ ├── config/
│ ├── deploy_env_vars_dev │ ├── deploy_env_vars_dev
│ ├── deploy_env_vars_staging │ ├── deploy_env_vars_staging
│ └── deploy_env_vars_prod │ └── deploy_env_vars_prod
├── scripts/ ├── scripts/
│ └── deploy.sh │ ├── deploy.sh (실행 가능)
└── Jenkinsfile │ └── validate-cicd-setup.sh (실행 가능)
├── Jenkinsfile
└── jenkins-pipeline-guide.md
``` ```
## 🔧 환경별 설정 ## 🚀 Jenkins 설정 방법
### DEV 환경 ### 1. Jenkins 서버 환경 구성
- **Namespace**: phonebill-dev
- **Ingress Host**: phonebill-api.20.214.196.128.nip.io ⚠️ **base와 동일해야 함**
- **Replicas**: 1
- **Resources**: requests(256m/256Mi), limits(1024m/1024Mi)
- **Profile**: dev
- **DDL**: update
- **SSL**: false
### STAGING 환경 #### 필수 플러그인 설치
- **Namespace**: phonebill-staging
- **Ingress Host**: phonebill.staging-domain.com ⚠️ **환경별 도메인**
- **Replicas**: 2
- **Resources**: requests(512m/512Mi), limits(2048m/2048Mi)
- **Profile**: staging
- **DDL**: validate
- **SSL**: true
### PROD 환경
- **Namespace**: phonebill-prod
- **Ingress Host**: phonebill.production-domain.com ⚠️ **프로덕션 도메인**
- **Replicas**: 3
- **Resources**: requests(1024m/1024Mi), limits(4096m/4096Mi)
- **Profile**: prod
- **DDL**: validate
- **SSL**: true
- **JWT 토큰**: 30분 (보안 강화)
## 🚀 Jenkins Pipeline Job 생성
### 1. Jenkins 웹 UI에서 새 작업 생성
- New Item > Pipeline 선택
- 작업명: phonebill-cicd
### 2. Pipeline 설정
``` ```
SCM: Git - Kubernetes
Repository URL: {Git저장소URL} - Pipeline Utility Steps
Branch: main - Docker Pipeline
Script Path: deployment/cicd/Jenkinsfile - GitHub
- SonarQube Scanner
- Azure Credentials
``` ```
### 3. Pipeline Parameters 설정 #### Jenkins Credentials 등록
``` **Manage Jenkins > Credentials > Add Credentials**
ENVIRONMENT: Choice Parameter (dev, staging, prod)
IMAGE_TAG: String Parameter (default: latest)
```
## 🎯 SonarQube 프로젝트 설정 1. **Azure Service Principal**
- Kind: Microsoft Azure Service Principal
- ID: `azure-credentials`
- Subscription ID, Client ID, Client Secret, Tenant ID 입력
- Azure Environment: Azure
### Quality Gate 설정 2. **ACR Credentials**
``` - Kind: Username with password
Coverage: >= 80% - ID: `acr-credentials`
Duplicated Lines: <= 3% - Username: `acrdigitalgarage01`
Maintainability Rating: <= A - Password: {ACR_PASSWORD}
Reliability Rating: <= A
Security Rating: <= A
```
## 📊 배포 실행 방법 3. **Docker Hub Credentials** (Rate Limit 해결용)
- Kind: Username with password
- ID: `dockerhub-credentials`
- Username: {DOCKERHUB_USERNAME}
- Password: {DOCKERHUB_PASSWORD}
4. **SonarQube Token**
- Kind: Secret text
- ID: `sonarqube-token`
- Secret: {SonarQube토큰}
### 2. Jenkins Pipeline Job 생성
1. **New Item > Pipeline** 선택
2. **Pipeline script from SCM** 설정:
- SCM: Git
- Repository URL: {Git저장소URL}
- Branch: main
- Script Path: `deployment/cicd/Jenkinsfile`
3. **Pipeline Parameters** 설정:
- ENVIRONMENT: Choice Parameter (dev, staging, prod)
- IMAGE_TAG: String Parameter (default: latest)
## 📊 SonarQube 설정
### 각 서비스별 프로젝트 생성
- 프로젝트 키: `phonebill-{서비스명}-{환경}`
- Quality Gate 설정:
- Coverage: ≥ 80%
- Duplicated Lines: ≤ 3%
- Maintainability Rating: ≤ A
- Reliability Rating: ≤ A
- Security Rating: ≤ A
## 🔄 배포 실행 방법
### 1. Jenkins 파이프라인 실행 ### 1. Jenkins 파이프라인 실행
``` 1. Jenkins > phonebill 프로젝트 > **Build with Parameters**
1. Jenkins > phonebill-cicd > Build with Parameters
2. ENVIRONMENT 선택 (dev/staging/prod) 2. ENVIRONMENT 선택 (dev/staging/prod)
3. IMAGE_TAG 입력 (선택사항) 3. IMAGE_TAG 입력 (선택사항)
4. Build 클릭 4. **Build** 클릭
### 2. 수동 배포 (선택사항)
```bash
# 개발 환경 배포
./deployment/cicd/scripts/deploy.sh dev 20240912101530
# 스테이징 환경 배포
./deployment/cicd/scripts/deploy.sh staging 20240912101530
# 운영 환경 배포
./deployment/cicd/scripts/deploy.sh prod 20240912101530
``` ```
### 2. 배포 상태 확인 ### 3. 배포 상태 확인
```bash ```bash
# Pod 상태 확인
kubectl get pods -n phonebill-{환경} kubectl get pods -n phonebill-{환경}
# 서비스 상태 확인
kubectl get services -n phonebill-{환경} kubectl get services -n phonebill-{환경}
# Ingress 상태 확인
kubectl get ingress -n phonebill-{환경} kubectl get ingress -n phonebill-{환경}
# 배포 이력 확인
kubectl rollout history deployment/{서비스명} -n phonebill-{환경}
``` ```
### 3. 수동 배포 (필요시) ## 🔍 설정 검증
### CI/CD 설정 검증 실행
```bash ```bash
# DEV 환경 배포 ./deployment/cicd/scripts/validate-cicd-setup.sh
./deployment/cicd/scripts/deploy.sh dev 20241201120000
# STAGING 환경 배포
./deployment/cicd/scripts/deploy.sh staging 20241201120000
# PROD 환경 배포
./deployment/cicd/scripts/deploy.sh prod 20241201120000
``` ```
## 🔄 롤백 방법 **검증 항목:**
- ✅ 서비스별 매니페스트 파일 존재 확인
- ✅ Base kustomization.yaml 유효성 검사
- ✅ 환경별 Overlay 빌드 테스트
- ✅ Jenkinsfile 구성 확인
- ✅ 환경별 설정 파일 검증
- ✅ 스크립트 실행 권한 확인
### 1. 이전 버전으로 롤백 ## 🔧 롤백 방법
### 1. kubectl을 이용한 롤백
```bash ```bash
# 이전 버전으로 롤백
kubectl rollout undo deployment/{서비스명} -n phonebill-{환경} --to-revision=2 kubectl rollout undo deployment/{서비스명} -n phonebill-{환경} --to-revision=2
# 롤백 상태 확인
kubectl rollout status deployment/{서비스명} -n phonebill-{환경} kubectl rollout status deployment/{서비스명} -n phonebill-{환경}
``` ```
### 2. 이미지 태그 기반 롤백 ### 2. 이미지 태그 기반 롤백
```bash ```bash
# 이전 안정 버전으로 수동 배포
cd deployment/cicd/kustomize/overlays/{환경} cd deployment/cicd/kustomize/overlays/{환경}
kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/{서비스명}:{환경}-{이전태그} kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/{서비스명}:{환경}-{이전태그}
kubectl apply -k . kubectl apply -k .
``` ```
## 📝 파이프라인 단계별 설명 ## 🛡️ 보안 및 모니터링
### Stage 1: Get Source ### 파드 자동 정리
- Git 저장소에서 소스코드 체크아웃 - **podRetention: never()**: 파이프라인 완료 시 파드 즉시 삭제
- 환경별 설정 파일 로드 - **terminationGracePeriodSeconds: 3**: 3초 내 강제 종료
- **idleMinutes: 1**: 유휴 시간 1분 설정
### Stage 2: Setup AKS ### 리소스 제한
- Azure 로그인 및 AKS 클러스터 연결 - **Timeout 설정**: Build&Push 30분, Quality Gate 10분
- 네임스페이스 생성 - **컨테이너 리소스**: 환경별 차등 할당
- **네트워크 격리**: 네임스페이스별 분리
### Stage 3: Build & SonarQube Analysis ## ✅ 구축 완료 체크리스트
- Gradle 빌드 및 테스트
- 각 서비스별 SonarQube 코드 품질 분석
- JaCoCo 테스트 커버리지 측정
### Stage 4: Quality Gate ### 📋 사전 준비
- SonarQube Quality Gate 검증 - [x] settings.gradle에서 시스템명과 서비스명 확인
- 품질 기준 미달 시 파이프라인 중단 - [x] 루트 build.gradle에서 JDK버전 확인 (21)
- [x] 실행정보에서 ACR명, 리소스 그룹, AKS 클러스터명 확인
### Stage 5: Build & Push Images ### 📂 Kustomize 구성
- 각 서비스별 컨테이너 이미지 빌드 - [x] 디렉토리 구조 생성
- ACR에 이미지 푸시 - [x] 기존 k8s 매니페스트를 base로 복사
- [x] Base kustomization.yaml 작성 (모든 리소스 포함)
- [x] kubectl kustomize 검증 완료
### Stage 6: Update Kustomize & Deploy ### 🔧 환경별 Overlay
- Kustomize를 이용한 이미지 태그 업데이트 - [x] DEV 환경: 12개 파일 생성 (1 replica, HTTP)
- Kubernetes 매니페스트 배포 - [x] STAGING 환경: 13개 파일 생성 (2 replicas, HTTPS)
- 배포 상태 확인 - [x] PROD 환경: 14개 파일 생성 (3 replicas, HTTPS, 보안 강화)
## ⚠️ 주의사항 및 체크리스트 준수사항 ### ⚙️ 스크립트 및 설정
- [x] 환경별 설정 파일 작성 (dev/staging/prod)
- [x] Jenkinsfile 작성 (JDK21, 파드 자동 정리 포함)
- [x] 수동 배포 스크립트 작성 및 실행 권한 설정
- [x] 검증 스크립트 작성 및 실행 권한 설정
### 🚨 **체크리스트 핵심 준수사항** ## 🎯 다음 단계
#### **1. Ingress 설정 규칙** ⚠️ **매우 중요** 1. **Jenkins 서버 설정**
```yaml - 필수 플러그인 설치
# ✅ DEV 환경: base와 동일한 host 사용 - Credentials 등록 (azure, acr, dockerhub, sonarqube)
- host: phonebill-api.20.214.196.128.nip.io # base와 동일해야 함!
# ✅ STAGING/PROD: 환경별 도메인 사용 2. **SonarQube 연동**
- host: phonebill.staging-domain.com # staging - 서비스별 프로젝트 생성
- host: phonebill.production-domain.com # prod - Quality Gate 규칙 설정
```
#### **2. Patch 파일 작성 원칙** 3. **파이프라인 테스트**
- ❌ **금지**: base 매니페스트에 없는 항목 추가 - 개발 환경 배포 테스트
- ✅ **필수**: base 매니페스트와 항목 구조 일치 - 스테이징/운영 환경 배포 준비
- ✅ **필수**: Secret에 `stringData` 사용 (`data` 금지)
- ✅ **필수**: `patches` 사용 (`patchesStrategicMerge` 금지)
#### **3. Deployment Patch 필수 항목** 4. **모니터링 설정**
```yaml - 배포 상태 모니터링
# ✅ 반드시 포함해야 할 항목들 - 알림 시스템 구성
spec:
replicas: {환경별설정} # dev:1, staging:2, prod:3
template:
spec:
containers:
- resources: # 반드시 포함
requests: {환경별설정}
limits: {환경별설정}
```
#### **4. Jenkinsfile 검증 포인트**
- ✅ JDK 버전: `gradle:jdk21` (프로젝트 JDK와 일치)
- ✅ 서비스 배열: `['api-gateway', 'user-service', 'bill-service', 'product-service', 'kos-mock']`
- ✅ 변수 문법: `${variable}` (⚠️ `\${variable}` 금지)
- ✅ ACR 이름: `acrdigitalgarage01` (실행정보와 일치)
### 🔍 **배포 전 필수 검증**
#### **파일 구조 검증**
```bash
# 모든 환경별 파일이 존재하는지 확인
find deployment/cicd/kustomize/overlays -name "*.yaml" | wc -l
# 결과: 36개 파일이 있어야 함 (각 환경별 12개씩)
```
#### **Kustomize 빌드 테스트**
```bash
# 각 환경별 매니페스트 빌드 테스트
kubectl kustomize deployment/cicd/kustomize/overlays/dev
kubectl kustomize deployment/cicd/kustomize/overlays/staging
kubectl kustomize deployment/cicd/kustomize/overlays/prod
# 모두 오류 없이 빌드되어야 함
```
#### **base vs dev ingress 비교**
```bash
# DEV 환경이 base와 동일한 host를 사용하는지 확인
diff deployment/cicd/kustomize/base/common/ingress.yaml deployment/cicd/kustomize/overlays/dev/ingress-patch.yaml
# host 라인에서 차이가 없어야 함
```
### 🛡️ **보안 및 운영**
#### **보안 체크**
- 모든 `change-in-production` 패스워드를 실제 값으로 변경
- 프로덕션 환경 도메인 설정 확인
- SSL 인증서 설정 검증
- JWT Secret 키 프로덕션 전용으로 변경
#### **성능 모니터링**
- 각 환경별 리소스 할당량 모니터링
- 배포 시 트래픽 영향도 확인
- Pod 리소스 사용량 추적
#### **운영 모니터링**
- 배포 후 서비스 상태 확인
- 로그 및 메트릭 모니터링
- 헬스체크 엔드포인트 확인
## 🆘 문제 해결 및 실수 방지
### **자주 발생하는 실수들**
#### **🚨 1. Ingress Host 실수**
**문제**: DEV 환경에서 host를 `phonebill-dev-api.xxx`로 변경
**해결**: DEV는 반드시 base와 동일한 host 사용
```bash
# 실수 방지 검증 명령
grep "host:" deployment/cicd/kustomize/base/common/ingress.yaml
grep "host:" deployment/cicd/kustomize/overlays/dev/ingress-patch.yaml
# 두 결과가 동일해야 함
```
#### **🚨 2. Secret에서 data 사용 실수**
**문제**: `data` 필드 사용으로 base64 인코딩 필요
**해결**: 항상 `stringData` 사용
```yaml
# ❌ 잘못된 방법
data:
DB_PASSWORD: "cGFzc3dvcmQ=" # base64 인코딩 필요
# ✅ 올바른 방법
stringData:
DB_PASSWORD: "password" # 평문 직접 입력
```
#### **🚨 3. Deployment Patch 누락 항목**
**문제**: replicas나 resources 누락으로 기본값 사용
**해결**: 반드시 환경별 설정 포함
```yaml
# ✅ 필수 포함 항목
spec:
replicas: 1 # 반드시 명시
template:
spec:
containers:
- resources: # 반드시 포함
requests:
cpu: 256m
memory: 256Mi
limits:
cpu: 1024m
memory: 1024Mi
```
#### **🚨 4. Jenkinsfile 변수 문법 실수**
**문제**: `\${variable}` 사용으로 "syntax error: bad substitution" 발생
**해결**: Jenkins Groovy에서는 `${variable}` 사용
```groovy
# ❌ 잘못된 문법
sh "echo \${environment}"
# ✅ 올바른 문법
sh "echo ${environment}"
```
### **Docker Hub 계정이 없는 경우 대안**
Docker Hub 계정 생성이 어려운 경우, 다음과 같이 Jenkinsfile을 수정할 수 있습니다:
```groovy
// 수정 전 (Docker Hub 로그인 포함)
withCredentials([
usernamePassword(
credentialsId: 'acr-credentials',
usernameVariable: 'ACR_USERNAME',
passwordVariable: 'ACR_PASSWORD'
),
usernamePassword(
credentialsId: 'dockerhub-credentials',
usernameVariable: 'DOCKERHUB_USERNAME',
passwordVariable: 'DOCKERHUB_PASSWORD'
)
]) {
sh "podman login docker.io --username \$DOCKERHUB_USERNAME --password \$DOCKERHUB_PASSWORD"
sh "podman login acrdigitalgarage01.azurecr.io --username \$ACR_USERNAME --password \$ACR_PASSWORD"
// ...
}
// 수정 후 (Docker Hub 로그인 제거)
withCredentials([usernamePassword(
credentialsId: 'acr-credentials',
usernameVariable: 'ACR_USERNAME',
passwordVariable: 'ACR_PASSWORD'
)]) {
sh "podman login acrdigitalgarage01.azurecr.io --username \$ACR_USERNAME --password \$ACR_PASSWORD"
// ...
}
```
**⚠️ 주의**: Docker Hub 로그인을 제거하면 pull rate limit에 걸릴 수 있습니다.
### **배포 전 최종 검증 스크립트**
```bash
#!/bin/bash
echo "🔍 Jenkins CI/CD 구성 최종 검증 시작..."
# 1. 파일 개수 확인
echo "1. 파일 개수 검증..."
OVERLAY_FILES=$(find deployment/cicd/kustomize/overlays -name "*.yaml" | wc -l)
if [ $OVERLAY_FILES -eq 36 ]; then
echo "✅ Overlay 파일 개수 정상 (36개)"
else
echo "❌ Overlay 파일 개수 오류 ($OVERLAY_FILES개, 36개여야 함)"
fi
# 2. DEV ingress host 검증
echo "2. DEV Ingress Host 검증..."
BASE_HOST=$(grep "host:" deployment/cicd/kustomize/base/common/ingress.yaml | awk '{print $3}')
DEV_HOST=$(grep "host:" deployment/cicd/kustomize/overlays/dev/ingress-patch.yaml | awk '{print $3}')
if [ "$BASE_HOST" = "$DEV_HOST" ]; then
echo "✅ DEV Ingress Host 정상 ($DEV_HOST)"
else
echo "❌ DEV Ingress Host 오류 (base: $BASE_HOST, dev: $DEV_HOST)"
fi
# 3. Kustomize 빌드 테스트
echo "3. Kustomize 빌드 테스트..."
for env in dev staging prod; do
if kubectl kustomize deployment/cicd/kustomize/overlays/$env > /dev/null 2>&1; then
echo "✅ $env 환경 빌드 성공"
else
echo "❌ $env 환경 빌드 실패"
fi
done
# 4. Jenkinsfile JDK 버전 확인
echo "4. Jenkinsfile JDK 버전 검증..."
if grep -q "gradle:jdk21" deployment/cicd/Jenkinsfile; then
echo "✅ JDK 21 버전 정상"
else
echo "❌ JDK 버전 확인 필요"
fi
# 5. Secret stringData 사용 확인
echo "5. Secret stringData 사용 검증..."
if grep -r "stringData:" deployment/cicd/kustomize/overlays/*/secret-*-patch.yaml > /dev/null; then
echo "✅ stringData 사용 정상"
else
echo "❌ stringData 사용 확인 필요"
fi
echo "🎯 검증 완료!"
```
### **일반적인 문제 해결**
1. **이미지 빌드 실패**: Dockerfile 경로 및 JAR 파일 확인
2. **배포 실패**: 리소스 할당량 및 네임스페이스 확인
3. **Quality Gate 실패**: 테스트 커버리지 및 코드 품질 개선
4. **Kustomize 빌드 실패**: patch 파일의 target 매칭 확인
### **로그 확인 방법**
```bash
# Jenkins 빌드 로그 확인 (웹 UI에서)
# Kubernetes Pod 로그 확인
kubectl logs -n phonebill-{환경} deployment/{서비스명}
kubectl describe pod -n phonebill-{환경} -l app={서비스명}
```
--- ---
## ✅ **체크리스트 완벽 준수로 Jenkins CI/CD 파이프라인 구축 완료!** **구축자**: 이개발/백엔더
**구축일**: 2024년 12월 12일
**이제 실수 없이 안전하게 CI/CD를 구축하고 운영할 수 있습니다! 🚀** **버전**: v1.0.0

View File

@ -13,31 +13,31 @@ resources:
- common/secret-common.yaml - common/secret-common.yaml
- common/secret-imagepull.yaml - common/secret-imagepull.yaml
- common/ingress.yaml - common/ingress.yaml
# API Gateway # api-gateway
- api-gateway/deployment.yaml - api-gateway/deployment.yaml
- api-gateway/service.yaml - api-gateway/service.yaml
- api-gateway/cm-api-gateway.yaml - api-gateway/cm-api-gateway.yaml
# User Service # user-service
- user-service/deployment.yaml - user-service/deployment.yaml
- user-service/service.yaml - user-service/service.yaml
- user-service/cm-user-service.yaml - user-service/cm-user-service.yaml
- user-service/secret-user-service.yaml - user-service/secret-user-service.yaml
# Bill Service # bill-service
- bill-service/deployment.yaml - bill-service/deployment.yaml
- bill-service/service.yaml - bill-service/service.yaml
- bill-service/cm-bill-service.yaml - bill-service/cm-bill-service.yaml
- bill-service/secret-bill-service.yaml - bill-service/secret-bill-service.yaml
# Product Service # product-service
- product-service/deployment.yaml - product-service/deployment.yaml
- product-service/service.yaml - product-service/service.yaml
- product-service/cm-product-service.yaml - product-service/cm-product-service.yaml
- product-service/secret-product-service.yaml - product-service/secret-product-service.yaml
# KOS Mock # kos-mock
- kos-mock/deployment.yaml - kos-mock/deployment.yaml
- kos-mock/service.yaml - kos-mock/service.yaml
- kos-mock/cm-kos-mock.yaml - kos-mock/cm-kos-mock.yaml

View File

@ -1,6 +1,4 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: phonebill name: phonebill
labels:
name: phonebill

View File

@ -2,11 +2,16 @@ apiVersion: v1
kind: ConfigMap kind: ConfigMap
metadata: metadata:
name: cm-common name: cm-common
data: data:
CORS_ALLOWED_ORIGINS: "http://localhost:8081,http://localhost:8082,http://localhost:8083,http://localhost:8084,http://phonebill-dev.20.214.196.128.nip.io" # 환경별 프로파일 설정
JWT_ACCESS_TOKEN_VALIDITY: "18000000"
JWT_REFRESH_TOKEN_VALIDITY: "86400000"
REDIS_PORT: "6379"
SPRING_PROFILES_ACTIVE: "dev" SPRING_PROFILES_ACTIVE: "dev"
DDL_AUTO: "update"
# 개발 환경 도메인 설정
CORS_ALLOWED_ORIGINS: "http://phonebill-api.20.214.196.128.nip.io"
# 개발 환경 DDL 설정 (데이터 보존을 위해 update 사용)
DDL_AUTO: "update"
# JWT 토큰 유효시간 (개발 환경은 긴 유효시간)
JWT_ACCESS_TOKEN_EXPIRATION: "3600000"
JWT_REFRESH_TOKEN_EXPIRATION: "86400000"

View File

@ -2,18 +2,16 @@ apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: api-gateway name: api-gateway
spec: spec:
replicas: 1 replicas: 1
template: template:
spec: spec:
containers: containers:
- name: api-gateway - name: api-gateway
image: acrdigitalgarage01.azurecr.io/phonebill/api-gateway:dev-latest
resources: resources:
requests: requests:
cpu: 256m memory: "256Mi"
memory: 256Mi cpu: "256m"
limits: limits:
cpu: 1024m memory: "1024Mi"
memory: 1024Mi cpu: "1024m"

View File

@ -2,18 +2,16 @@ apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: bill-service name: bill-service
spec: spec:
replicas: 1 replicas: 1
template: template:
spec: spec:
containers: containers:
- name: bill-service - name: bill-service
image: acrdigitalgarage01.azurecr.io/phonebill/bill-service:dev-latest
resources: resources:
requests: requests:
cpu: 256m memory: "256Mi"
memory: 256Mi cpu: "256m"
limits: limits:
cpu: 1024m memory: "1024Mi"
memory: 1024Mi cpu: "1024m"

View File

@ -2,18 +2,16 @@ apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: kos-mock name: kos-mock
spec: spec:
replicas: 1 replicas: 1
template: template:
spec: spec:
containers: containers:
- name: kos-mock - name: kos-mock
image: acrdigitalgarage01.azurecr.io/phonebill/kos-mock:dev-latest
resources: resources:
requests: requests:
cpu: 256m memory: "256Mi"
memory: 256Mi cpu: "256m"
limits: limits:
cpu: 1024m memory: "1024Mi"
memory: 1024Mi cpu: "1024m"

View File

@ -2,18 +2,16 @@ apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: product-service name: product-service
spec: spec:
replicas: 1 replicas: 1
template: template:
spec: spec:
containers: containers:
- name: product-service - name: product-service
image: acrdigitalgarage01.azurecr.io/phonebill/product-service:dev-latest
resources: resources:
requests: requests:
cpu: 256m memory: "256Mi"
memory: 256Mi cpu: "256m"
limits: limits:
cpu: 1024m memory: "1024Mi"
memory: 1024Mi cpu: "1024m"

View File

@ -2,18 +2,16 @@ apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: user-service name: user-service
spec: spec:
replicas: 1 replicas: 1
template: template:
spec: spec:
containers: containers:
- name: user-service - name: user-service
image: acrdigitalgarage01.azurecr.io/phonebill/user-service:dev-latest
resources: resources:
requests: requests:
cpu: 256m memory: "256Mi"
memory: 256Mi cpu: "256m"
limits: limits:
cpu: 1024m memory: "1024Mi"
memory: 1024Mi cpu: "1024m"

View File

@ -5,7 +5,6 @@ metadata:
annotations: annotations:
kubernetes.io/ingress.class: nginx kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "false" nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec: spec:
ingressClassName: nginx ingressClassName: nginx
rules: rules:

View File

@ -1,46 +1,16 @@
apiVersion: kustomize.config.k8s.io/v1beta1 apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization kind: Kustomization
metadata: namespace: phonebill-dev
name: phonebill-dev
resources: resources:
- ../../base - ../../base
namespace: phonebill-dev
labels:
- pairs:
env: dev
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
patches: patches:
# Common patches
- path: configmap-common-patch.yaml - path: configmap-common-patch.yaml
target: target:
kind: ConfigMap kind: ConfigMap
name: cm-common name: cm-common
- path: secret-common-patch.yaml
target:
kind: Secret
name: secret-common
- path: ingress-patch.yaml
target:
kind: Ingress
name: phonebill
# Deployment patches
- path: deployment-api-gateway-patch.yaml - path: deployment-api-gateway-patch.yaml
target: target:
kind: Deployment kind: Deployment
@ -61,8 +31,14 @@ patches:
target: target:
kind: Deployment kind: Deployment
name: kos-mock name: kos-mock
- path: ingress-patch.yaml
# Secret patches target:
kind: Ingress
name: phonebill
- path: secret-common-patch.yaml
target:
kind: Secret
name: secret-common
- path: secret-user-service-patch.yaml - path: secret-user-service-patch.yaml
target: target:
kind: Secret kind: Secret
@ -74,4 +50,19 @@ patches:
- path: secret-product-service-patch.yaml - path: secret-product-service-patch.yaml
target: target:
kind: Secret kind: Secret
name: secret-product-service name: secret-product-service
images:
- name: acrdigitalgarage01.azurecr.io/phonebill/api-gateway
newTag: dev-latest
- name: acrdigitalgarage01.azurecr.io/phonebill/user-service
newTag: dev-latest
- name: acrdigitalgarage01.azurecr.io/phonebill/bill-service
newTag: dev-latest
- name: acrdigitalgarage01.azurecr.io/phonebill/product-service
newTag: dev-latest
- name: acrdigitalgarage01.azurecr.io/phonebill/kos-mock
newTag: dev-latest
commonLabels:
environment: dev

View File

@ -2,10 +2,8 @@ apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
name: secret-bill-service name: secret-bill-service
type: Opaque type: Opaque
stringData: stringData:
DB_HOST: "bill-inquiry-postgres-dev-postgresql" # Bill Service DB 접속 정보 (개발 환경)
DB_NAME: "bill_inquiry_db" DB_PASSWORD: "billdb-dev-password"
DB_USERNAME: "bill_inquiry_user" DB_URL: "jdbc:postgresql://bill-inquiry-postgres-dev-postgresql:5432/bill_inquiry_db"
DB_PASSWORD: "BillUser2025!"

View File

@ -2,9 +2,12 @@ apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
name: secret-common name: secret-common
type: Opaque type: Opaque
stringData: stringData:
JWT_SECRET: "nwe5Yo9qaJ6FBD/Thl2/j6/SFAfNwUorAY1ZcWO2KI7uA4bmVLOCPxE9hYuUpRCOkgV2UF2DdHXtqHi3+BU/ecbz2zpHyf/720h48UbA3XOMYOX1sdM+dQ==" # Redis 설정 (개발 환경)
REDIS_HOST: "redis-cache-dev-master" REDIS_PASSWORD: "dev-redis-password"
REDIS_PASSWORD: "Redis2025Dev!"
# JWT Secret Key (개발 환경용)
JWT_SECRET: "dev-jwt-secret-key-for-phonebill-development"
# 개발 환경용 공통 시크릿

View File

@ -2,10 +2,8 @@ apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
name: secret-product-service name: secret-product-service
type: Opaque type: Opaque
stringData: stringData:
DB_HOST: "product-change-postgres-dev-postgresql" # Product Service DB 접속 정보 (개발 환경)
DB_NAME: "product_change_db" DB_PASSWORD: "productdb-dev-password"
DB_USERNAME: "product_change_user" DB_URL: "jdbc:postgresql://product-change-postgres-dev-postgresql:5432/product_change_db"
DB_PASSWORD: "ProductUser2025!"

View File

@ -2,10 +2,8 @@ apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
name: secret-user-service name: secret-user-service
type: Opaque type: Opaque
stringData: stringData:
DB_HOST: "auth-postgres-dev-postgresql" # User Service DB 접속 정보 (개발 환경)
DB_NAME: "phonebill_auth" DB_PASSWORD: "userdb-dev-password"
DB_USERNAME: "auth_user" DB_URL: "jdbc:postgresql://user-auth-postgres-dev-postgresql:5432/user_auth_db"
DB_PASSWORD: "AuthUser2025!"

View File

@ -0,0 +1,72 @@
# Production Overlay Configuration
This directory contains the Kustomize overlay configuration for the production environment of the phonebill project.
## Configuration Overview
### Environment Details
- **Namespace**: `phonebill-prod`
- **Environment**: Production
- **Replicas**: 3 (for all services)
- **Domain**: `phonebill.yourdomain.com`
- **Image Tag**: `prod-latest`
- **SSL**: Enabled with HTTPS redirect
### Security Configuration
- **JWT Access Token**: 30분 (1800000ms) - 보안 강화를 위한 짧은 만료시간
- **JWT Refresh Token**: 12시간 (43200000ms)
- **DDL Auto**: `validate` - 프로덕션 안전성을 위한 스키마 검증 모드
- **SSL Redirect**: 강제 HTTPS 리디렉션
### Resource Allocation
All services are configured with:
- **Requests**: 1024m CPU, 1024Mi Memory
- **Limits**: 4096m CPU, 4096Mi Memory
### Health Checks
- **Liveness Probe**: 2분 초기 지연, 30초 간격
- **Readiness Probe**: 1분 초기 지연, 10초 간격
## Files Structure
```
prod/
├── kustomization.yaml # 메인 오버레이 설정
├── configmap-common-patch.yaml # 공통 설정 (프로덕션 프로파일)
├── secret-common-patch.yaml # 공통 시크릿 (JWT, Redis)
├── ingress-patch.yaml # HTTPS 인그레스 설정
├── deployment-api-gateway-patch.yaml # API Gateway 배포 설정
├── deployment-user-service-patch.yaml # 사용자 서비스 배포 설정
├── deployment-bill-service-patch.yaml # 요금조회 서비스 배포 설정
├── deployment-product-service-patch.yaml# 상품변경 서비스 배포 설정
├── deployment-kos-mock-patch.yaml # KOS Mock 배포 설정
├── secret-user-service-patch.yaml # 사용자 서비스 DB 연결정보
├── secret-bill-service-patch.yaml # 요금조회 서비스 DB 연결정보
└── secret-product-service-patch.yaml # 상품변경 서비스 DB 연결정보
```
## Deployment Command
```bash
# Apply production configuration
kubectl apply -k deployment/cicd/kustomize/overlays/prod/
# Validate configuration before applying
kubectl kustomize deployment/cicd/kustomize/overlays/prod/
```
## Important Notes
1. **Secret Values**: 모든 시크릿 값들은 실제 프로덕션 환경에 맞게 변경해야 합니다.
2. **Domain Configuration**: `phonebill.yourdomain.com`을 실제 도메인으로 변경하세요.
3. **Certificate**: SSL 인증서 설정을 위해 cert-manager가 구성되어 있어야 합니다.
4. **Database**: 각 서비스별 전용 데이터베이스 인스턴스가 필요합니다.
5. **Monitoring**: 프로덕션 환경에서는 모니터링 및 로깅 설정이 중요합니다.
## Database Services Required
프로덕션 환경에서는 다음 데이터베이스 서비스들이 필요합니다:
- `auth-postgres-prod-service` (사용자 서비스)
- `bill-inquiry-postgres-prod-service` (요금조회 서비스)
- `product-change-postgres-prod-service` (상품변경 서비스)
- `redis-prod-service` (공통 캐시)

View File

@ -1,28 +1,19 @@
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
metadata: metadata:
name: common-config name: cm-common
namespace: phonebill-prod
data: data:
# Production Spring profiles
SPRING_PROFILES_ACTIVE: "prod" SPRING_PROFILES_ACTIVE: "prod"
# Production database settings
DDL_AUTO: "validate" DDL_AUTO: "validate"
# Production logging level # JWT 설정 - 프로덕션 보안 강화
LOGGING_LEVEL_ROOT: "INFO" JWT_ACCESS_EXPIRATION: "1800000" # 30분 (1800초)
LOGGING_LEVEL_COM_PHONEBILL: "INFO" JWT_REFRESH_EXPIRATION: "43200000" # 12시간 (43200초)
# Production security settings # 로깅 설정
SECURITY_CORS_ALLOWED_ORIGINS: "https://phonebill.production-domain.com" LOG_LEVEL_ROOT: "INFO"
LOG_LEVEL_COM_PHONEBILL: "INFO"
# JWT Token settings for production (shorter expiry for security) # 캐시 설정
JWT_EXPIRATION: "1800000" # 30 minutes CACHE_TTL: "3600" # 1시간
# Redis settings for production
REDIS_HOST: "redis-service.phonebill-prod.svc.cluster.local"
REDIS_PORT: "6379"
# Production specific configurations
MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE: "health,info,prometheus"
MANAGEMENT_ENDPOINT_HEALTH_SHOW_DETAILS: "when-authorized"

View File

@ -2,6 +2,7 @@ apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: api-gateway name: api-gateway
namespace: phonebill-prod
spec: spec:
replicas: 3 replicas: 3
template: template:
@ -10,15 +11,24 @@ spec:
- name: api-gateway - name: api-gateway
resources: resources:
requests: requests:
cpu: "1024m"
memory: "1024Mi" memory: "1024Mi"
cpu: "1024m"
limits: limits:
cpu: "4096m"
memory: "4096Mi" memory: "4096Mi"
env: cpu: "4096m"
- name: SPRING_PROFILES_ACTIVE livenessProbe:
value: "prod" httpGet:
- name: SERVER_PORT path: /actuator/health
value: "8080" port: 8080
- name: MANAGEMENT_SERVER_PORT initialDelaySeconds: 120
value: "8081" periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3

View File

@ -2,6 +2,7 @@ apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: bill-service name: bill-service
namespace: phonebill-prod
spec: spec:
replicas: 3 replicas: 3
template: template:
@ -10,17 +11,24 @@ spec:
- name: bill-service - name: bill-service
resources: resources:
requests: requests:
cpu: "1024m"
memory: "1024Mi" memory: "1024Mi"
cpu: "1024m"
limits: limits:
cpu: "4096m"
memory: "4096Mi" memory: "4096Mi"
env: cpu: "4096m"
- name: SPRING_PROFILES_ACTIVE livenessProbe:
value: "prod" httpGet:
- name: SERVER_PORT path: /actuator/health
value: "8080" port: 8080
- name: MANAGEMENT_SERVER_PORT initialDelaySeconds: 120
value: "8081" periodSeconds: 30
- name: SPRING_JPA_HIBERNATE_DDL_AUTO timeoutSeconds: 10
value: "validate" failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3

View File

@ -2,6 +2,7 @@ apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: kos-mock name: kos-mock
namespace: phonebill-prod
spec: spec:
replicas: 3 replicas: 3
template: template:
@ -10,15 +11,24 @@ spec:
- name: kos-mock - name: kos-mock
resources: resources:
requests: requests:
cpu: "1024m"
memory: "1024Mi" memory: "1024Mi"
cpu: "1024m"
limits: limits:
cpu: "4096m"
memory: "4096Mi" memory: "4096Mi"
env: cpu: "4096m"
- name: SPRING_PROFILES_ACTIVE livenessProbe:
value: "prod" httpGet:
- name: SERVER_PORT path: /actuator/health
value: "8080" port: 8080
- name: MANAGEMENT_SERVER_PORT initialDelaySeconds: 120
value: "8081" periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3

View File

@ -2,6 +2,7 @@ apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: product-service name: product-service
namespace: phonebill-prod
spec: spec:
replicas: 3 replicas: 3
template: template:
@ -10,17 +11,24 @@ spec:
- name: product-service - name: product-service
resources: resources:
requests: requests:
cpu: "1024m"
memory: "1024Mi" memory: "1024Mi"
cpu: "1024m"
limits: limits:
cpu: "4096m"
memory: "4096Mi" memory: "4096Mi"
env: cpu: "4096m"
- name: SPRING_PROFILES_ACTIVE livenessProbe:
value: "prod" httpGet:
- name: SERVER_PORT path: /actuator/health
value: "8080" port: 8080
- name: MANAGEMENT_SERVER_PORT initialDelaySeconds: 120
value: "8081" periodSeconds: 30
- name: SPRING_JPA_HIBERNATE_DDL_AUTO timeoutSeconds: 10
value: "validate" failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3

View File

@ -2,6 +2,7 @@ apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: user-service name: user-service
namespace: phonebill-prod
spec: spec:
replicas: 3 replicas: 3
template: template:
@ -10,17 +11,24 @@ spec:
- name: user-service - name: user-service
resources: resources:
requests: requests:
cpu: "1024m"
memory: "1024Mi" memory: "1024Mi"
cpu: "1024m"
limits: limits:
cpu: "4096m"
memory: "4096Mi" memory: "4096Mi"
env: cpu: "4096m"
- name: SPRING_PROFILES_ACTIVE livenessProbe:
value: "prod" httpGet:
- name: SERVER_PORT path: /actuator/health
value: "8080" port: 8080
- name: MANAGEMENT_SERVER_PORT initialDelaySeconds: 120
value: "8081" periodSeconds: 30
- name: SPRING_JPA_HIBERNATE_DDL_AUTO timeoutSeconds: 10
value: "validate" failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3

View File

@ -1,53 +1,26 @@
apiVersion: networking.k8s.io/v1 apiVersion: networking.k8s.io/v1
kind: Ingress kind: Ingress
metadata: metadata:
name: phonebill-ingress name: phonebill
namespace: phonebill-prod
annotations: annotations:
kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true" nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod" cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/proxy-body-size: "10m" nginx.ingress.kubernetes.io/proxy-body-size: "10m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "300" nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300" nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "300" nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
spec: spec:
tls: tls:
- hosts: - hosts:
- phonebill.production-domain.com - phonebill.yourdomain.com
secretName: phonebill-prod-tls secretName: phonebill-prod-tls
rules: rules:
- host: phonebill.production-domain.com - host: phonebill.yourdomain.com
http: http:
paths: paths:
- path: /api/auth
pathType: Prefix
backend:
service:
name: user-service
port:
number: 8080
- path: /api/bills
pathType: Prefix
backend:
service:
name: bill-service
port:
number: 8080
- path: /api/products
pathType: Prefix
backend:
service:
name: product-service
port:
number: 8080
- path: /api/kos
pathType: Prefix
backend:
service:
name: kos-mock
port:
number: 8080
- path: / - path: /
pathType: Prefix pathType: Prefix
backend: backend:

View File

@ -1,61 +1,16 @@
apiVersion: kustomize.config.k8s.io/v1beta1 apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization kind: Kustomization
metadata:
name: phonebill-prod
namespace: phonebill-prod namespace: phonebill-prod
resources: resources:
- ../../base - ../../base
commonLabels:
environment: prod
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
patches: patches:
# ConfigMap patches
- path: configmap-common-patch.yaml - path: configmap-common-patch.yaml
target: target:
kind: ConfigMap kind: ConfigMap
name: common-config name: cm-common
# Secret patches
- path: secret-common-patch.yaml
target:
kind: Secret
name: common-secret
- path: secret-user-service-patch.yaml
target:
kind: Secret
name: user-service-secret
- path: secret-bill-service-patch.yaml
target:
kind: Secret
name: bill-service-secret
- path: secret-product-service-patch.yaml
target:
kind: Secret
name: product-service-secret
# Ingress patches
- path: ingress-patch.yaml
target:
kind: Ingress
name: phonebill-ingress
# Deployment patches
- path: deployment-api-gateway-patch.yaml - path: deployment-api-gateway-patch.yaml
target: target:
kind: Deployment kind: Deployment
@ -75,4 +30,39 @@ patches:
- path: deployment-kos-mock-patch.yaml - path: deployment-kos-mock-patch.yaml
target: target:
kind: Deployment kind: Deployment
name: kos-mock name: kos-mock
- path: ingress-patch.yaml
target:
kind: Ingress
name: phonebill
- path: secret-common-patch.yaml
target:
kind: Secret
name: secret-common
- path: secret-user-service-patch.yaml
target:
kind: Secret
name: secret-user-service
- path: secret-bill-service-patch.yaml
target:
kind: Secret
name: secret-bill-service
- path: secret-product-service-patch.yaml
target:
kind: Secret
name: secret-product-service
images:
- name: acrdigitalgarage01.azurecr.io/phonebill/api-gateway
newTag: 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
commonLabels:
environment: prod

View File

@ -1,13 +1,22 @@
apiVersion: v1 apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
name: bill-service-secret name: secret-bill-service
namespace: phonebill-prod
type: Opaque type: Opaque
stringData: stringData:
# Database connection for bill service in production # 요금조회 서비스 전용 데이터베이스 연결정보
DB_URL: "jdbc:postgresql://bill-service-postgres-prod.phonebill-prod.svc.cluster.local:5432/bill_inquiry_db" DB_HOST: "bill-inquiry-postgres-prod-service"
DB_PORT: "5432"
DB_NAME: "bill_inquiry_db"
DB_USERNAME: "postgres" DB_USERNAME: "postgres"
DB_PASSWORD: "prod-bill-service-db-password-change-in-production" DB_PASSWORD: "your-production-bill-db-password"
# Service-specific secrets for production # 데이터베이스 연결 풀 설정 (프로덕션 최적화)
SERVICE_SECRET: "prod-bill-service-secret-change-in-production" DB_MAX_POOL_SIZE: "20"
DB_MIN_IDLE: "5"
DB_CONNECTION_TIMEOUT: "30000"
# KOS 연동 설정
KOS_BASE_URL: "http://kos-mock:8080"
KOS_API_KEY: "your-production-kos-api-key"

View File

@ -1,20 +1,17 @@
apiVersion: v1 apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
name: common-secret name: secret-common
namespace: phonebill-prod
type: Opaque type: Opaque
stringData: stringData:
# JWT Secret Key for production (should be changed in real deployment) # JWT 설정
JWT_SECRET: "prod-phonebill-jwt-secret-key-change-in-production-2024" JWT_SECRET: "your-production-jwt-secret-key-here-must-be-very-secure"
# Redis password for production # Redis 설정
REDIS_PASSWORD: "prod-redis-password-change-in-production" REDIS_HOST: "redis-prod-service"
REDIS_PORT: "6379"
REDIS_PASSWORD: "your-production-redis-password"
# Database passwords for production # 암호화 설정
DB_PASSWORD: "prod-db-password-change-in-production" ENCRYPTION_KEY: "your-production-encryption-key-32-chars"
# External API keys for production
EXTERNAL_API_KEY: "prod-external-api-key-change-in-production"
# Additional production secrets
ENCRYPTION_KEY: "prod-encryption-key-change-in-production-32chars"

View File

@ -1,13 +1,22 @@
apiVersion: v1 apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
name: product-service-secret name: secret-product-service
namespace: phonebill-prod
type: Opaque type: Opaque
stringData: stringData:
# Database connection for product service in production # 상품변경 서비스 전용 데이터베이스 연결정보
DB_URL: "jdbc:postgresql://product-service-postgres-prod.phonebill-prod.svc.cluster.local:5432/product_change_db" DB_HOST: "product-change-postgres-prod-service"
DB_PORT: "5432"
DB_NAME: "product_change_db"
DB_USERNAME: "postgres" DB_USERNAME: "postgres"
DB_PASSWORD: "prod-product-service-db-password-change-in-production" DB_PASSWORD: "your-production-product-db-password"
# Service-specific secrets for production # 데이터베이스 연결 풀 설정 (프로덕션 최적화)
SERVICE_SECRET: "prod-product-service-secret-change-in-production" DB_MAX_POOL_SIZE: "20"
DB_MIN_IDLE: "5"
DB_CONNECTION_TIMEOUT: "30000"
# KOS 연동 설정
KOS_BASE_URL: "http://kos-mock:8080"
KOS_API_KEY: "your-production-kos-api-key"

View File

@ -1,13 +1,18 @@
apiVersion: v1 apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
name: user-service-secret name: secret-user-service
namespace: phonebill-prod
type: Opaque type: Opaque
stringData: stringData:
# Database connection for user service in production # 사용자 서비스 전용 데이터베이스 연결정보
DB_URL: "jdbc:postgresql://user-service-postgres-prod.phonebill-prod.svc.cluster.local:5432/auth_db" DB_HOST: "auth-postgres-prod-service"
DB_PORT: "5432"
DB_NAME: "auth_db"
DB_USERNAME: "postgres" DB_USERNAME: "postgres"
DB_PASSWORD: "prod-user-service-db-password-change-in-production" DB_PASSWORD: "your-production-auth-db-password"
# Service-specific secrets for production # 데이터베이스 연결 풀 설정 (프로덕션 최적화)
SERVICE_SECRET: "prod-user-service-secret-change-in-production" DB_MAX_POOL_SIZE: "20"
DB_MIN_IDLE: "5"
DB_CONNECTION_TIMEOUT: "30000"

View File

@ -3,6 +3,15 @@ kind: ConfigMap
metadata: metadata:
name: cm-common name: cm-common
data: data:
NAMESPACE: "phonebill-staging" # 환경별 프로파일 설정
SPRING_PROFILES_ACTIVE: "staging" SPRING_PROFILES_ACTIVE: "staging"
DDL_AUTO: "validate"
# 스테이징 환경 도메인 설정
CORS_ALLOWED_ORIGINS: "https://phonebill-staging.yourdomain.com"
# 스테이징 환경 DDL 설정 (데이터 검증을 위해 validate 사용)
DDL_AUTO: "validate"
# JWT 토큰 유효시간 (스테이징 환경은 운영과 유사한 유효시간)
JWT_ACCESS_TOKEN_EXPIRATION: "1800000"
JWT_REFRESH_TOKEN_EXPIRATION: "43200000"

View File

@ -1,18 +1,17 @@
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: api-gateway-deployment name: api-gateway
spec: spec:
replicas: 2 replicas: 2
template: template:
spec: spec:
containers: containers:
- name: api-gateway - name: api-gateway
image: acrdigitalgarage01.azurecr.io/phonebill-api-gateway:staging-latest resources:
resources: requests:
requests: memory: "512Mi"
memory: "512Mi" cpu: "512m"
cpu: "512m" limits:
limits: memory: "2048Mi"
memory: "2048Mi" cpu: "2048m"
cpu: "2048m"

View File

@ -1,18 +1,17 @@
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: bill-service-deployment name: bill-service
spec: spec:
replicas: 2 replicas: 2
template: template:
spec: spec:
containers: containers:
- name: bill-service - name: bill-service
image: acrdigitalgarage01.azurecr.io/phonebill-bill-service:staging-latest resources:
resources: requests:
requests: memory: "512Mi"
memory: "512Mi" cpu: "512m"
cpu: "512m" limits:
limits: memory: "2048Mi"
memory: "2048Mi" cpu: "2048m"
cpu: "2048m"

View File

@ -1,18 +1,17 @@
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: kos-mock-deployment name: kos-mock
spec: spec:
replicas: 2 replicas: 2
template: template:
spec: spec:
containers: containers:
- name: kos-mock - name: kos-mock
image: acrdigitalgarage01.azurecr.io/phonebill-kos-mock:staging-latest resources:
resources: requests:
requests: memory: "512Mi"
memory: "512Mi" cpu: "512m"
cpu: "512m" limits:
limits: memory: "2048Mi"
memory: "2048Mi" cpu: "2048m"
cpu: "2048m"

View File

@ -1,18 +1,17 @@
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: product-service-deployment name: product-service
spec: spec:
replicas: 2 replicas: 2
template: template:
spec: spec:
containers: containers:
- name: product-service - name: product-service
image: acrdigitalgarage01.azurecr.io/phonebill-product-service:staging-latest resources:
resources: requests:
requests: memory: "512Mi"
memory: "512Mi" cpu: "512m"
cpu: "512m" limits:
limits: memory: "2048Mi"
memory: "2048Mi" cpu: "2048m"
cpu: "2048m"

View File

@ -1,18 +1,17 @@
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: user-service-deployment name: user-service
spec: spec:
replicas: 2 replicas: 2
template: template:
spec: spec:
containers: containers:
- name: user-service - name: user-service
image: acrdigitalgarage01.azurecr.io/phonebill-user-service:staging-latest resources:
resources: requests:
requests: memory: "512Mi"
memory: "512Mi" cpu: "512m"
cpu: "512m" limits:
limits: memory: "2048Mi"
memory: "2048Mi" cpu: "2048m"
cpu: "2048m"

View File

@ -1,25 +1,53 @@
apiVersion: networking.k8s.io/v1 apiVersion: networking.k8s.io/v1
kind: Ingress kind: Ingress
metadata: metadata:
name: phonebill-ingress name: phonebill
annotations: annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "true" 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/backend-protocol: "HTTP"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec: spec:
ingressClassName: nginx
tls: tls:
- hosts: - hosts:
- phonebill.staging-domain.com - phonebill-staging.yourdomain.com
secretName: phonebill-tls-staging secretName: phonebill-staging-tls
rules: rules:
- host: phonebill.staging-domain.com - host: phonebill-staging.yourdomain.com
http: http:
paths: paths:
- path: / - path: /api/v1/auth
pathType: Prefix pathType: Prefix
backend: backend:
service: service:
name: api-gateway-service name: user-service
port: port:
number: 8080 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

View File

@ -1,68 +1,68 @@
apiVersion: kustomize.config.k8s.io/v1beta1 apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization kind: Kustomization
namespace: phonebill-staging
resources: resources:
- ../../base - ../../base
namespace: phonebill-staging
patches: patches:
# Common ConfigMap - path: configmap-common-patch.yaml
- target: target:
kind: ConfigMap kind: ConfigMap
name: cm-common name: cm-common
path: configmap-common-patch.yaml - path: deployment-api-gateway-patch.yaml
target:
# Common Secret kind: Deployment
- target: name: api-gateway
- path: deployment-user-service-patch.yaml
target:
kind: Deployment
name: user-service
- path: deployment-bill-service-patch.yaml
target:
kind: Deployment
name: bill-service
- path: deployment-product-service-patch.yaml
target:
kind: Deployment
name: product-service
- path: deployment-kos-mock-patch.yaml
target:
kind: Deployment
name: kos-mock
- path: ingress-patch.yaml
target:
kind: Ingress
name: phonebill
- path: secret-common-patch.yaml
target:
kind: Secret kind: Secret
name: secret-common name: secret-common
path: secret-common-patch.yaml - path: secret-user-service-patch.yaml
target:
# Ingress
- target:
kind: Ingress
name: phonebill-ingress
path: ingress-patch.yaml
# API Gateway
- target:
kind: Deployment
name: api-gateway-deployment
path: deployment-api-gateway-patch.yaml
# User Service
- target:
kind: Deployment
name: user-service-deployment
path: deployment-user-service-patch.yaml
- target:
kind: Secret kind: Secret
name: secret-user-service name: secret-user-service
path: secret-user-service-patch.yaml - path: secret-bill-service-patch.yaml
target:
# Bill Service
- target:
kind: Deployment
name: bill-service-deployment
path: deployment-bill-service-patch.yaml
- target:
kind: Secret kind: Secret
name: secret-bill-service name: secret-bill-service
path: secret-bill-service-patch.yaml - path: secret-product-service-patch.yaml
target:
# Product Service
- target:
kind: Deployment
name: product-service-deployment
path: deployment-product-service-patch.yaml
- target:
kind: Secret kind: Secret
name: secret-product-service name: secret-product-service
path: secret-product-service-patch.yaml
images:
# KOS Mock - name: acrdigitalgarage01.azurecr.io/phonebill/api-gateway
- target: newTag: staging-latest
kind: Deployment - name: acrdigitalgarage01.azurecr.io/phonebill/user-service
name: kos-mock-deployment newTag: staging-latest
path: deployment-kos-mock-patch.yaml - 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
commonLabels:
environment: staging

View File

@ -2,10 +2,8 @@ apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
name: secret-bill-service name: secret-bill-service
type: Opaque
stringData: stringData:
DB_HOST: "bill-service-postgres-staging.phonebill-staging.svc.cluster.local" # Bill Service DB 접속 정보 (스테이징 환경)
DB_PORT: "5432" DB_PASSWORD: "billdb-staging-password"
DB_NAME: "bill_inquiry_db" DB_URL: "jdbc:postgresql://bill-inquiry-postgres-staging-postgresql:5432/bill_inquiry_db"
DB_USERNAME: "postgres"
DB_PASSWORD: "staging-bill-service-db-password"
KOS_MOCK_URL: "http://kos-mock-service.phonebill-staging.svc.cluster.local:8090"

View File

@ -2,9 +2,12 @@ apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
name: secret-common name: secret-common
type: Opaque
stringData: stringData:
JWT_SECRET_KEY: "staging-my-very-secret-key-for-jwt-token-generation-and-validation-that-is-256-bits-long" # Redis 설정 (스테이징 환경)
JWT_EXPIRATION_TIME: "3600" REDIS_PASSWORD: "staging-redis-password"
REDIS_HOST: "phonebill-redis-staging.phonebill-staging.svc.cluster.local"
REDIS_PORT: "6379" # JWT Secret Key (스테이징 환경용)
REDIS_PASSWORD: "staging-redis-password" JWT_SECRET: "staging-jwt-secret-key-for-phonebill-staging-environment"
# 스테이징 환경용 공통 시크릿

View File

@ -2,10 +2,8 @@ apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
name: secret-product-service name: secret-product-service
type: Opaque
stringData: stringData:
DB_HOST: "product-service-postgres-staging.phonebill-staging.svc.cluster.local" # Product Service DB 접속 정보 (스테이징 환경)
DB_PORT: "5432" DB_PASSWORD: "productdb-staging-password"
DB_NAME: "product_change_db" DB_URL: "jdbc:postgresql://product-change-postgres-staging-postgresql:5432/product_change_db"
DB_USERNAME: "postgres"
DB_PASSWORD: "staging-product-service-db-password"
KOS_MOCK_URL: "http://kos-mock-service.phonebill-staging.svc.cluster.local:8090"

View File

@ -2,9 +2,8 @@ apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
name: secret-user-service name: secret-user-service
type: Opaque
stringData: stringData:
DB_HOST: "user-service-postgres-staging.phonebill-staging.svc.cluster.local" # User Service DB 접속 정보 (스테이징 환경)
DB_PORT: "5432" DB_PASSWORD: "userdb-staging-password"
DB_NAME: "auth_db" DB_URL: "jdbc:postgresql://user-auth-postgres-staging-postgresql:5432/user_auth_db"
DB_USERNAME: "postgres"
DB_PASSWORD: "staging-user-service-db-password"

View File

@ -4,40 +4,44 @@ set -e
ENVIRONMENT=${1:-dev} ENVIRONMENT=${1:-dev}
IMAGE_TAG=${2:-latest} IMAGE_TAG=${2:-latest}
# 서비스 목록 echo "🚀 Starting manual deployment for environment: $ENVIRONMENT with tag: $IMAGE_TAG"
SERVICES=("api-gateway" "user-service" "bill-service" "product-service" "kos-mock")
echo "🚀 Starting deployment to ${ENVIRONMENT} environment..."
echo "📦 Image tag: ${ENVIRONMENT}-${IMAGE_TAG}"
# 환경별 이미지 태그 업데이트 # 환경별 이미지 태그 업데이트
cd deployment/cicd/kustomize/overlays/${ENVIRONMENT} cd deployment/cicd/kustomize/overlays/${ENVIRONMENT}
# 서비스 목록 (공백으로 구분)
services="api-gateway user-service bill-service product-service kos-mock"
echo "📦 Updating image tags for services: $services"
# 각 서비스 이미지 태그 업데이트 # 각 서비스 이미지 태그 업데이트
echo "🔄 Updating image tags..." for service in $services; do
for service in "${SERVICES[@]}"; do echo " ⏳ Updating $service to ${ENVIRONMENT}-${IMAGE_TAG}"
echo " - Updating ${service} to acrdigitalgarage01.azurecr.io/phonebill/${service}:${ENVIRONMENT}-${IMAGE_TAG}" kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/$service:${ENVIRONMENT}-${IMAGE_TAG}
kustomize edit set image acrdigitalgarage01.azurecr.io/phonebill/${service}:${ENVIRONMENT}-${IMAGE_TAG}
done done
echo "🚢 Deploying to Kubernetes cluster..."
# 배포 실행 # 배포 실행
echo "🎯 Applying Kubernetes manifests..."
kubectl apply -k . kubectl apply -k .
echo "⏰ Waiting for deployments to be ready..."
# 배포 상태 확인 # 배포 상태 확인
echo "⏳ Waiting for deployments to be ready..." for service in $services; do
for service in "${SERVICES[@]}"; do echo " 🔄 Waiting for $service deployment..."
echo " - Checking ${service} deployment status..." kubectl rollout status deployment/$service -n phonebill-${ENVIRONMENT}
kubectl rollout status deployment/${service} -n phonebill-${ENVIRONMENT} --timeout=300s
done done
# 최종 상태 확인 echo "✅ Deployment completed successfully!"
echo "📋 Final deployment status:"
kubectl get pods -n phonebill-${ENVIRONMENT}
echo "" echo ""
kubectl get services -n phonebill-${ENVIRONMENT} echo "📋 Deployment Summary:"
echo " Environment: $ENVIRONMENT"
echo " Image Tag: ${ENVIRONMENT}-${IMAGE_TAG}"
echo " Services: $services"
echo " Namespace: phonebill-${ENVIRONMENT}"
echo "" echo ""
kubectl get ingress -n phonebill-${ENVIRONMENT} echo "🔍 Check deployment status:"
echo " kubectl get pods -n phonebill-${ENVIRONMENT}"
echo "✅ Deployment to ${ENVIRONMENT} environment completed successfully!" echo " kubectl get services -n phonebill-${ENVIRONMENT}"
echo "🌐 Access URL: https://$(kubectl get ingress -n phonebill-${ENVIRONMENT} -o jsonpath='{.items[0].spec.rules[0].host}')" echo " kubectl get ingress -n phonebill-${ENVIRONMENT}"

View File

@ -1,86 +1,202 @@
#!/bin/bash #!/bin/bash
echo "🔍 Jenkins CI/CD 구성 최종 검증 시작..." # phonebill CI/CD 설정 검증 스크립트
# 1. 파일 개수 확인 echo "🔍 phonebill CI/CD 설정 검증 시작..."
echo "1. 파일 개수 검증..."
OVERLAY_FILES=$(find deployment/cicd/kustomize/overlays -name "*.yaml" | wc -l)
if [ $OVERLAY_FILES -eq 36 ]; then
echo "✅ Overlay 파일 개수 정상 (36개)"
else
echo "❌ Overlay 파일 개수 오류 ($OVERLAY_FILES개, 36개여야 함)"
fi
# 2. DEV ingress host 검증 BASE_DIR="deployment/cicd/kustomize/base"
echo "2. DEV Ingress Host 검증..." MISSING_RESOURCES=0
BASE_HOST=$(grep "host:" deployment/cicd/kustomize/base/common/ingress.yaml | awk '{print $3}') REQUIRED_FILES=("deployment.yaml" "service.yaml")
DEV_HOST=$(grep "host:" deployment/cicd/kustomize/overlays/dev/ingress-patch.yaml | awk '{print $3}') OPTIONAL_FILES=("cm-" "secret-")
if [ "$BASE_HOST" = "$DEV_HOST" ]; then
echo "✅ DEV Ingress Host 정상 ($DEV_HOST)"
else
echo "❌ DEV Ingress Host 오류 (base: $BASE_HOST, dev: $DEV_HOST)"
fi
# 3. Kustomize 빌드 테스트 # 1. 각 서비스 디렉토리의 파일 확인
echo "3. Kustomize 빌드 테스트..." echo "1. 서비스 디렉토리별 파일 목록:"
for env in dev staging prod; do for dir in $BASE_DIR/*/; do
if kubectl kustomize deployment/cicd/kustomize/overlays/$env > /dev/null 2>&1; then if [ -d "$dir" ] && [[ $(basename "$dir") != "common" ]]; then
echo "$env 환경 빌드 성공" service=$(basename "$dir")
else echo "=== $service ==="
echo "$env 환경 빌드 실패"
kubectl kustomize deployment/cicd/kustomize/overlays/$env 2>&1 | head -3 # 필수 파일 확인
for required in "${REQUIRED_FILES[@]}"; do
if [ -f "$dir$required" ]; then
echo "$required"
else
echo " ❌ MISSING REQUIRED: $required"
((MISSING_RESOURCES++))
fi
done
# 선택적 파일 확인
for optional in "${OPTIONAL_FILES[@]}"; do
files=($(ls "$dir"$optional*".yaml" 2>/dev/null))
if [ ${#files[@]} -gt 0 ]; then
for file in "${files[@]}"; do
echo "$(basename "$file")"
done
fi
done
echo ""
fi fi
done done
# 4. Jenkinsfile JDK 버전 확인 # 2. Common 리소스 확인
echo "4. Jenkinsfile JDK 버전 검증..." echo "2. Common 리소스 확인:"
if grep -q "gradle:jdk21" deployment/cicd/Jenkinsfile; then COMMON_DIR="$BASE_DIR/common"
echo "✅ JDK 21 버전 정상" if [ -d "$COMMON_DIR" ]; then
common_files=($(ls "$COMMON_DIR"/*.yaml 2>/dev/null))
if [ ${#common_files[@]} -gt 0 ]; then
for file in "${common_files[@]}"; do
echo " ✅ common/$(basename "$file")"
done
else
echo " ❌ Common 디렉토리에 YAML 파일이 없습니다"
((MISSING_RESOURCES++))
fi
else else
echo "❌ JDK 버전 확인 필요" echo " ❌ Common 디렉토리가 없습니다"
fi ((MISSING_RESOURCES++))
# 5. Secret stringData 사용 확인
echo "5. Secret stringData 사용 검증..."
if grep -r "stringData:" deployment/cicd/kustomize/overlays/*/secret-*-patch.yaml > /dev/null; then
echo "✅ stringData 사용 정상"
else
echo "❌ stringData 사용 확인 필요"
fi
# 6. patches 문법 확인 (patchesStrategicMerge 금지)
echo "6. Kustomization patches 문법 검증..."
if grep -r "patchesStrategicMerge:" deployment/cicd/kustomize/overlays/*/kustomization.yaml > /dev/null; then
echo "❌ 금지된 patchesStrategicMerge 사용 발견"
else
echo "✅ patches 문법 정상"
fi
# 7. 환경별 replicas 설정 확인
echo "7. 환경별 replicas 설정 검증..."
DEV_REPLICAS=$(grep "replicas:" deployment/cicd/kustomize/overlays/dev/deployment-user-service-patch.yaml | awk '{print $2}')
STAGING_REPLICAS=$(grep "replicas:" deployment/cicd/kustomize/overlays/staging/deployment-user-service-patch.yaml | awk '{print $2}')
PROD_REPLICAS=$(grep "replicas:" deployment/cicd/kustomize/overlays/prod/deployment-user-service-patch.yaml | awk '{print $2}')
if [ "$DEV_REPLICAS" = "1" ] && [ "$STAGING_REPLICAS" = "2" ] && [ "$PROD_REPLICAS" = "3" ]; then
echo "✅ 환경별 replicas 설정 정상 (dev:1, staging:2, prod:3)"
else
echo "❌ 환경별 replicas 설정 확인 필요 (dev:$DEV_REPLICAS, staging:$STAGING_REPLICAS, prod:$PROD_REPLICAS)"
fi
# 8. 서비스 배열 검증
echo "8. Jenkinsfile 서비스 배열 검증..."
SERVICES_COUNT=$(grep "def services = \[" deployment/cicd/Jenkinsfile | grep -o "'" | wc -l)
if [ $SERVICES_COUNT -eq 10 ]; then # 5개 서비스 * 2 (시작/끝 따옴표)
echo "✅ 서비스 배열 정상 (5개 서비스)"
else
echo "❌ 서비스 배열 확인 필요"
fi fi
# 3. kustomization.yaml과 실제 파일 비교
echo "" echo ""
echo "🎯 검증 완료!" echo "3. kustomization.yaml 리소스 검증:"
if [ -f "$BASE_DIR/kustomization.yaml" ]; then
while IFS= read -r line; do
# resources 섹션의 YAML 파일 경로 추출
if [[ $line =~ ^[[:space:]]*-[[:space:]]*([^#]+\.yaml)[[:space:]]*$ ]]; then
resource_path=$(echo "${BASH_REMATCH[1]}" | xargs) # 공백 제거
full_path="$BASE_DIR/$resource_path"
if [ -f "$full_path" ]; then
echo "$resource_path"
else
echo " ❌ MISSING: $resource_path"
((MISSING_RESOURCES++))
fi
fi
done < "$BASE_DIR/kustomization.yaml"
else
echo " ❌ kustomization.yaml 파일이 없습니다"
((MISSING_RESOURCES++))
fi
# 4. kubectl kustomize 검증
echo "" echo ""
echo "📋 추가 수동 확인사항:" echo "4. Kustomize 빌드 테스트:"
echo " - Jenkins Credentials 설정 (azure-credentials, acr-credentials, sonarqube-token)" if kubectl kustomize "$BASE_DIR" > /dev/null 2>&1; then
echo " - SonarQube Quality Gate 설정" echo " ✅ Base kustomization 빌드 성공"
echo " - 프로덕션 환경 패스워드 변경" else
echo " - SSL 인증서 설정" echo " ❌ Base kustomization 빌드 실패:"
kubectl kustomize "$BASE_DIR" 2>&1 | head -5 | sed 's/^/ /'
((MISSING_RESOURCES++))
fi
# 5. 환경별 overlay 검증
echo ""
echo "5. 환경별 Overlay 검증:"
for env in dev staging prod; do
overlay_dir="deployment/cicd/kustomize/overlays/$env"
if [ -d "$overlay_dir" ] && [ -f "$overlay_dir/kustomization.yaml" ]; then
if kubectl kustomize "$overlay_dir" > /dev/null 2>&1; then
echo "$env 환경 빌드 성공"
else
echo "$env 환경 빌드 실패"
((MISSING_RESOURCES++))
fi
else
echo " ⚠️ $env 환경 설정 없음 (선택사항)"
fi
done
# 6. Jenkins 파이프라인 검증
echo ""
echo "6. Jenkins 파이프라인 검증:"
if [ -f "deployment/cicd/Jenkinsfile" ]; then
echo " ✅ Jenkinsfile 존재"
# 주요 서비스명 확인
services_in_jenkinsfile=$(grep -o "api-gateway\|user-service\|bill-service\|product-service\|kos-mock" deployment/cicd/Jenkinsfile | sort -u | tr '\n' ' ')
echo " 📋 Jenkinsfile의 서비스: $services_in_jenkinsfile"
# ACR 이름 확인
acr_name=$(grep -o "acrdigitalgarage01" deployment/cicd/Jenkinsfile | head -1)
if [ -n "$acr_name" ]; then
echo " ✅ ACR 이름: $acr_name"
else
echo " ⚠️ ACR 이름을 찾을 수 없습니다"
fi
else
echo " ❌ Jenkinsfile이 없습니다"
((MISSING_RESOURCES++))
fi
# 7. 스크립트 파일 검증
echo ""
echo "7. 배포 스크립트 검증:"
scripts_dir="deployment/cicd/scripts"
if [ -f "$scripts_dir/deploy.sh" ]; then
echo " ✅ deploy.sh 존재"
if [ -x "$scripts_dir/deploy.sh" ]; then
echo " ✅ deploy.sh 실행 권한 있음"
else
echo " ⚠️ deploy.sh 실행 권한 없음 (chmod +x 필요)"
fi
else
echo " ❌ deploy.sh가 없습니다"
((MISSING_RESOURCES++))
fi
# 8. 환경별 설정 파일 검증
echo ""
echo "8. 환경별 설정 파일 검증:"
config_dir="deployment/cicd/config"
for env in dev staging prod; do
config_file="$config_dir/deploy_env_vars_$env"
if [ -f "$config_file" ]; then
echo "$env 환경 설정 파일 존재"
# 필수 설정 확인
if grep -q "resource_group\|cluster_name" "$config_file"; then
echo " ✅ 필수 설정 (resource_group, cluster_name) 확인됨"
else
echo " ❌ 필수 설정이 누락됨"
((MISSING_RESOURCES++))
fi
else
echo "$env 환경 설정 파일이 없습니다"
((MISSING_RESOURCES++))
fi
done
# 결과 출력
echo ""
echo "======================================"
if [ $MISSING_RESOURCES -eq 0 ]; then
echo "🎯 검증 완료! phonebill CI/CD 설정이 정상입니다."
echo "======================================"
echo ""
echo "📋 Jenkins CI/CD 파이프라인 구성 요약:"
echo " • 시스템명: phonebill"
echo " • 서비스: api-gateway, user-service, bill-service, product-service, kos-mock"
echo " • 환경: dev, staging, prod"
echo " • 컨테이너 레지스트리: acrdigitalgarage01.azurecr.io"
echo " • JDK 버전: 21"
echo ""
echo "🚀 다음 단계:"
echo " 1. Jenkins에서 Pipeline Job 생성"
echo " 2. Jenkins Credentials 설정 (azure-credentials, acr-credentials, dockerhub-credentials)"
echo " 3. SonarQube 서버 연동 설정"
echo " 4. 파이프라인 실행 테스트"
echo ""
exit 0
else
echo "$MISSING_RESOURCES개의 문제가 발견되었습니다."
echo "======================================"
echo ""
echo "💡 문제 해결 가이드:"
echo "1. 누락된 파일들을 base 디렉토리에 추가하세요"
echo "2. kustomization.yaml에서 존재하지 않는 파일 참조를 제거하세요"
echo "3. 파일명이 명명 규칙을 따르는지 확인하세요:"
echo " - ConfigMap: cm-{서비스명}.yaml"
echo " - Secret: secret-{서비스명}.yaml"
echo "4. 스크립트 실행 권한 설정: chmod +x scripts/*.sh"
echo "5. 다시 검증: ./scripts/validate-cicd-setup.sh"
exit 1
fi