Jenkins CI/CD 파이프라인 업데이트

- Jenkinsfile 개선: SonarQube 분석, Quality Gate 추가
- 환경별 설정 파일 업데이트 (dev/staging/prod)
- Kustomize base 및 overlay 파일 정리
- prod 환경 overlay 파일 추가
- 배포 스크립트 및 검증 스크립트 업데이트
- 파이프라인 가이드 문서 업데이트

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
ondal 2025-12-01 12:57:35 +09:00
parent b467b84426
commit 0f054109bb
48 changed files with 372 additions and 387 deletions

View File

@ -59,6 +59,7 @@ podTemplate(
],
volumes: [
emptyDirVolume(mountPath: '/home/gradle/.gradle', memory: false),
emptyDirVolume(mountPath: '/root/.azure', memory: false),
emptyDirVolume(mountPath: '/run/podman', memory: false)
]
) {
@ -78,6 +79,7 @@ podTemplate(
stage("Setup Kubernetes") {
container('kubectl') {
sh """
kubectl config use-context ${props.context}
kubectl create namespace ${props.namespace} --dry-run=client -o yaml | kubectl apply -f -
"""
}
@ -92,25 +94,73 @@ podTemplate(
}
}
stage('SonarQube Analysis & Quality Gate') {
if (skipSonarQube) {
echo "⏭️ Skipping SonarQube Analysis (SKIP_SONARQUBE=${params.SKIP_SONARQUBE})"
} else {
container('gradle') {
// 각 서비스별로 개별적으로 SonarQube 분석 및 Quality Gate 확인
services.each { service ->
withSonarQubeEnv('SonarQube') {
echo "🔍 Starting SonarQube analysis for ${service}..."
// 서비스별 테스트 및 SonarQube 분석
sh """
./gradlew :${service}:test :${service}:jacocoTestReport :${service}:sonar \
-Dsonar.projectKey=phonebill-${service}-${environment} \
-Dsonar.projectName=phonebill-${service}-${environment} \
-Dsonar.java.binaries=build/classes/java/main \
-Dsonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml \
-Dsonar.exclusions=**/config/**,**/entity/**,**/dto/**,**/*Application.class,**/exception/**
"""
echo "✅ SonarQube analysis completed for ${service}"
}
// 각 서비스별 Quality Gate 확인
timeout(time: 5, unit: 'MINUTES') {
echo "⏳ Waiting for Quality Gate result for ${service}..."
def qg = waitForQualityGate()
if (qg.status != 'OK') {
error "❌ Quality Gate failed for ${service}: ${qg.status}"
} else {
echo "✅ Quality Gate passed for ${service}"
}
}
}
echo "🎉 All services passed SonarQube Quality Gates!"
}
}
}
stage('Build & Push Images') {
timeout(time: 30, unit: 'MINUTES') {
container('podman') {
withCredentials([
usernamePassword(
credentialsId: 'imagereg-credentials',
usernameVariable: 'IMG_USERNAME',
passwordVariable: 'IMG_PASSWORD'
),
usernamePassword(
credentialsId: 'dockerhub-credentials',
usernameVariable: 'DOCKERHUB_USERNAME',
passwordVariable: 'DOCKERHUB_PASSWORD'
)
]) {
// Docker Hub 로그인 (rate limit 해결)
sh "podman login docker.io --username \$DOCKERHUB_USERNAME --password \$DOCKERHUB_PASSWORD"
// Image Registry 로그인
sh "podman login docker.io --username \$IMG_USERNAME --password \$IMG_PASSWORD"
services.each { service ->
sh """
podman build \\
--build-arg BUILD_LIB_DIR="${service}/build/libs" \\
--build-arg ARTIFACTORY_FILE="${service}.jar" \\
-f deployment/container/Dockerfile-backend \\
podman build \
--build-arg BUILD_LIB_DIR="${service}/build/libs" \
--build-arg ARTIFACTORY_FILE="${service}.jar" \
-f deployment/container/Dockerfile-backend \
-t docker.io/hiondal/${service}:${environment}-${imageTag} .
podman push docker.io/hiondal/${service}:${environment}-${imageTag}
@ -124,7 +174,7 @@ podTemplate(
stage('Update Kustomize & Deploy') {
container('kubectl') {
sh """
# Kustomize 설치
# Kustomize 설치 (sudo 없이 사용자 디렉토리에 설치)
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
mkdir -p \$HOME/bin
mv kustomize \$HOME/bin/
@ -133,12 +183,12 @@ podTemplate(
# 환경별 디렉토리로 이동
cd deployment/cicd/kustomize/overlays/${environment}
# 서비스 목록 정의
# 서비스 목록 정의 (공백으로 구분)
services="api-gateway user-service bill-service product-service kos-mock"
# 이미지 태그 업데이트
for service in \$services; do
\$HOME/bin/kustomize edit set image docker.io/hiondal/\$service:${environment}-${imageTag}
\$HOME/bin/kustomize edit set image docker.io/hiondal/\$service=docker.io/hiondal/\$service:${environment}-${imageTag}
done
# 매니페스트 적용
@ -147,15 +197,17 @@ podTemplate(
# 배포 상태 확인
echo "Waiting for deployments to be ready..."
for service in \$services; do
kubectl -n ${props.namespace} wait --for=condition=available deployment/\$service --timeout=300s || echo "Timeout waiting for \$service"
kubectl -n ${props.namespace} wait --for=condition=available deployment/\$service --timeout=300s
done
"""
}
}
// 파이프라인 완료 로그 (Scripted Pipeline 방식)
stage('Pipeline Complete') {
echo "🧹 Pipeline completed. Pod cleanup handled by Jenkins Kubernetes Plugin."
// 성공/실패 여부 로깅
if (currentBuild.result == null || currentBuild.result == 'SUCCESS') {
echo "✅ Pipeline completed successfully!"
} else {

View File

@ -1,4 +1,3 @@
# Dev Environment Configuration
# Minikube Remote 환경 설정
k8s_context=minikube-remote
# dev Environment Configuration
context=minikube
namespace=phonebill

View File

@ -1,4 +1,3 @@
# Production Environment Configuration
# Minikube Remote 환경 설정
k8s_context=minikube-remote
namespace=phonebill-prod
# prod Environment Configuration
context=minikube-prod
namespace=phonebill

View File

@ -1,4 +1,3 @@
# Staging Environment Configuration
# Minikube Remote 환경 설정
k8s_context=minikube-remote
namespace=phonebill-staging
# staging Environment Configuration
context=minikube-staging
namespace=phonebill

View File

@ -1,175 +1,184 @@
# Jenkins CI/CD 파이프라인 가이드
# 백엔드 Jenkins CI/CD 파이프라인 가이드
## 개요
이 문서는 Phonebill 프로젝트의 Jenkins 기반 CI/CD 파이프라인 구축 및 운영 가이드입니다.
## 📋 개요
## 프로젝트 정보
이 가이드는 phonebill 프로젝트의 Jenkins + Kustomize 기반 CI/CD 파이프라인 구축 및 운영 방법을 설명합니다.
## 🔧 사전 준비사항
### 프로젝트 정보
| 항목 | 값 |
|------|-----|
| 시스템명 | phonebill |
| 서비스 목록 | api-gateway, user-service, bill-service, product-service, kos-mock |
| JDK 버전 | 21 |
| Image Registry | docker.io |
| Image Organization | hiondal |
| K8s Context | minikube-remote |
| Jenkins K8s Cloud Name | k8s |
| K8s Context Prefix | minikube |
| Namespace | phonebill |
### 서비스 목록
- api-gateway (포트: 8080)
- user-service (포트: 8081)
- bill-service (포트: 8082)
- product-service (포트: 8083)
- kos-mock (포트: 8084)
### Jenkins 서버 환경 구성
---
## 1. 사전 준비사항
### 1.1 Jenkins 필수 플러그인
#### 1. 필수 플러그인 설치
```
- Kubernetes
- Pipeline Utility Steps
- Docker Pipeline
- GitHub
- SonarQube Scanner
- Azure Credentials
```
### 1.2 Jenkins Credentials 등록
#### 2. Jenkins Credentials 등록
Jenkins 관리 > Credentials > Add Credentials에서 등록:
#### Docker Hub Credentials
**Docker Hub Credentials (Rate Limit 해결용)**
```
- Kind: Username with password
- ID: dockerhub-credentials
- Username: {DOCKERHUB_USERNAME}
- Password: {DOCKERHUB_PASSWORD}
- 참고: Docker Hub 무료 계정 생성 (https://hub.docker.com)
```
#### SonarQube Token (선택사항)
**Image Registry Credentials**
```
- Kind: Username with password
- ID: imagereg-credentials
- Username: {REGISTRY_USERNAME}
- Password: {REGISTRY_PASSWORD}
```
**SonarQube Token (선택사항)**
```
- Kind: Secret text
- ID: sonarqube-token
- Secret: {SonarQube 토큰}
- Secret: {SonarQube토큰}
```
### 1.3 SonarQube 설정 (선택사항)
Jenkins 관리 > Configure System > SonarQube servers:
```
- Name: SonarQube
- Server URL: http://{SONARQUBE_URL}
- Server authentication token: sonarqube-token (위에서 등록한 credential)
```
## 📁 디렉토리 구조
---
## 2. Kustomize 구조
### 2.1 디렉토리 구조
```
deployment/cicd/
├── Jenkinsfile
├── Jenkinsfile # Jenkins 파이프라인 정의
├── jenkins-pipeline-guide.md # 이 가이드 문서
├── config/
│ ├── deploy_env_vars_dev
│ ├── deploy_env_vars_staging
│ └── deploy_env_vars_prod
│ ├── deploy_env_vars_dev # dev 환경 설정
│ ├── deploy_env_vars_staging # staging 환경 설정
│ └── deploy_env_vars_prod # prod 환경 설정
├── scripts/
│ ├── deploy.sh
│ └── validate-resources.sh
│ ├── deploy.sh # 수동 배포 스크립트
│ └── validate-resources.sh # 리소스 검증 스크립트
└── kustomize/
├── base/
├── base/ # 기본 Kubernetes 매니페스트
│ ├── kustomization.yaml
│ ├── common/
│ │ ├── cm-common.yaml
│ │ ├── secret-common.yaml
│ │ └── ingress.yaml
│ ├── api-gateway/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── cm-api-gateway.yaml
│ ├── user-service/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ ├── cm-user-service.yaml
│ │ └── secret-user-service.yaml
│ ├── bill-service/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ ├── cm-bill-service.yaml
│ │ └── secret-bill-service.yaml
│ ├── product-service/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ ├── cm-product-service.yaml
│ │ └── secret-product-service.yaml
│ └── kos-mock/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── cm-kos-mock.yaml
└── overlays/
├── dev/
├── staging/
└── prod/
├── dev/ # 개발 환경 오버레이
├── staging/ # 스테이징 환경 오버레이
└── prod/ # 운영 환경 오버레이
```
### 2.2 환경별 설정 차이
## 🚀 Jenkins Pipeline Job 생성
| 항목 | dev | staging | prod |
|------|-----|---------|------|
| Namespace | phonebill | phonebill-staging | phonebill-prod |
| Replicas | 1 | 2 | 3 |
| CPU Requests | 256m | 512m | 1024m |
| Memory Requests | 256Mi | 512Mi | 1024Mi |
| CPU Limits | 1024m | 2048m | 4096m |
| Memory Limits | 1024Mi | 2048Mi | 4096Mi |
| DDL_AUTO | update | validate | validate |
| SHOW_SQL | true | false | false |
| SSL Redirect | false | true | true |
### 1. Pipeline Job 생성
1. Jenkins 웹 UI에서 **New Item** > **Pipeline** 선택
2. Pipeline script from SCM 설정:
```
SCM: Git
Repository URL: {Git저장소URL}
Branch: main (또는 develop)
Script Path: deployment/cicd/Jenkinsfile
```
---
### 2. Pipeline Parameters 설정
| 파라미터 | 타입 | 값 | 설명 |
|---------|------|-----|------|
| ENVIRONMENT | Choice | dev, staging, prod | 배포 대상 환경 |
| IMAGE_TAG | String | latest | 이미지 태그 (선택) |
| SKIP_SONARQUBE | String | true | SonarQube 분석 건너뛰기 |
## 3. Jenkins Pipeline Job 생성
## ⚙️ 환경별 설정
### 3.1 New Item > Pipeline 선택
### 3.2 Pipeline 설정
```
SCM: Git
Repository URL: {Git 저장소 URL}
Branch: main (또는 develop)
Script Path: deployment/cicd/Jenkinsfile
### DEV 환경
```yaml
# Replicas: 1
# Resources:
# requests: 256m CPU, 256Mi Memory
# limits: 1024m CPU, 1024Mi Memory
# DDL_AUTO: update
# HTTPS: 비활성화
```
### 3.3 Pipeline Parameters 설정
| 파라미터 | 타입 | 기본값 | 설명 |
|----------|------|--------|------|
| ENVIRONMENT | Choice | dev | 배포 환경 (dev/staging/prod) |
| SKIP_SONARQUBE | String | true | SonarQube 분석 건너뛰기 (true/false) |
### STAGING 환경
```yaml
# Replicas: 2
# Resources:
# requests: 512m CPU, 512Mi Memory
# limits: 2048m CPU, 2048Mi Memory
# DDL_AUTO: validate
# HTTPS: 활성화 (SSL 인증서 필요)
```
---
### PROD 환경
```yaml
# Replicas: 3
# Resources:
# requests: 1024m CPU, 1024Mi Memory
# limits: 4096m CPU, 4096Mi Memory
# DDL_AUTO: validate
# HTTPS: 활성화 (SSL 인증서 필요)
```
## 4. 파이프라인 스테이지
## 📊 SonarQube 설정
### 4.1 Get Source
- Git 저장소에서 소스 코드 체크아웃
- 환경별 설정 파일 로드
### Quality Gate 설정
```
Coverage: >= 80%
Duplicated Lines: <= 3%
Maintainability Rating: <= A
Reliability Rating: <= A
Security Rating: <= A
```
### 4.2 Setup Kubernetes
- Kubernetes 컨텍스트 설정
- 네임스페이스 생성
### 분석 제외 대상
```
**/config/**
**/entity/**
**/dto/**
**/*Application.class
**/exception/**
```
### 4.3 Build
- Gradle을 사용한 빌드 (테스트 제외)
- `./gradlew build -x test`
## 🔨 수동 배포
### 4.4 SonarQube Analysis & Quality Gate (선택사항)
- SKIP_SONARQUBE=false일 때만 실행
- 각 서비스별 테스트 및 코드 품질 분석
- Quality Gate 통과 확인
### 4.5 Build & Push Images
- Podman을 사용한 컨테이너 이미지 빌드
- Docker Hub로 이미지 푸시
- 이미지 태그: `{환경}-{타임스탬프}`
### 4.6 Update Kustomize & Deploy
- Kustomize를 사용한 이미지 태그 업데이트
- Kubernetes 매니페스트 적용
- 배포 상태 확인
---
## 5. 배포 실행
### 5.1 Jenkins 파이프라인 실행
1. Jenkins > phonebill > Build with Parameters
2. ENVIRONMENT 선택 (dev/staging/prod)
3. SKIP_SONARQUBE 입력 (true 또는 false)
4. Build 클릭
### 5.2 수동 배포 (스크립트 사용)
### 배포 스크립트 사용
```bash
# dev 환경 배포
./deployment/cicd/scripts/deploy.sh dev latest
@ -181,131 +190,100 @@ Script Path: deployment/cicd/Jenkinsfile
./deployment/cicd/scripts/deploy.sh prod v1.0.0
```
### 5.3 배포 상태 확인
### 리소스 검증
```bash
# Pod 상태 확인
# Kustomize 리소스 검증
./deployment/cicd/scripts/validate-resources.sh
```
## 🔄 배포 상태 확인
```bash
# 파드 상태 확인
kubectl get pods -n phonebill
# 서비스 상태 확인
kubectl get services -n phonebill
# Ingress 상태 확인
# 인그레스 확인
kubectl get ingress -n phonebill
# 특정 Pod 로그 확인
kubectl logs -f deployment/api-gateway -n phonebill
# 배포 상태 상세 확인
kubectl describe deployment api-gateway -n phonebill
```
---
## ⏪ 롤백 방법
## 6. 롤백
### 6.1 이전 버전으로 롤백
### 이전 버전으로 롤백
```bash
# 특정 리비전으로 롤백
kubectl rollout undo deployment/{서비스명} -n phonebill --to-revision=2
# 롤백 상태 확인
kubectl rollout status deployment/{서비스명} -n phonebill
# 롤백 히스토리 확인
kubectl rollout history deployment/{서비스명} -n phonebill
```
### 6.2 이미지 태그 기반 롤백
### 이미지 태그 기반 롤백
```bash
cd deployment/cicd/kustomize/overlays/{환경}
# 이전 안정 버전 이미지 태그로 업데이트
kustomize edit set image docker.io/hiondal/{서비스명}:{환경}-{이전태그}
# 배포
cd deployment/cicd/kustomize/overlays/{환경}
kustomize edit set image docker.io/hiondal/{서비스명}=docker.io/hiondal/{서비스명}:{환경}-{이전태그}
kubectl apply -k .
```
---
## 🔍 문제 해결
## 7. 리소스 검증
### 일반적인 문제
### 7.1 검증 스크립트 실행
#### 1. 이미지 풀 실패
```bash
# ImagePullBackOff 상태 확인
kubectl describe pod {pod-name} -n phonebill
# Docker Hub 인증 확인
kubectl get secret -n phonebill
```
#### 2. 파드 시작 실패
```bash
# 로그 확인
kubectl logs {pod-name} -n phonebill
# 이벤트 확인
kubectl get events -n phonebill --sort-by='.lastTimestamp'
```
#### 3. Kustomize 빌드 실패
```bash
# 검증 스크립트 실행
./deployment/cicd/scripts/validate-resources.sh
# 직접 빌드 테스트
kubectl kustomize deployment/cicd/kustomize/overlays/dev
```
### 7.2 Kustomize 빌드 테스트
```bash
# Base 빌드 테스트
kubectl kustomize deployment/cicd/kustomize/base/
### Jenkins 파이프라인 문제
# 환경별 빌드 테스트
kubectl kustomize deployment/cicd/kustomize/overlays/dev/
kubectl kustomize deployment/cicd/kustomize/overlays/staging/
kubectl kustomize deployment/cicd/kustomize/overlays/prod/
```
#### 1. Pod 정리가 안 되는 경우
- `podRetention: never()` 설정 확인
- `terminationGracePeriodSeconds: 3` 설정 확인
- Jenkins Kubernetes Plugin 버전 확인
---
#### 2. 변수 치환 오류
- `${variable}` 사용 (Groovy 문자열 보간)
- `\${variable}` 사용 금지 (bash 이스케이프)
## 8. SonarQube 설정 (선택사항)
## 📝 체크리스트
### 8.1 Quality Gate 권장 설정
```
Coverage: >= 80%
Duplicated Lines: <= 3%
Maintainability Rating: <= A
Reliability Rating: <= A
Security Rating: <= A
```
### 8.2 SonarQube 프로젝트 생성
각 서비스별로 다음 형식의 프로젝트 키로 생성:
- `phonebill-user-service-dev`
- `phonebill-user-service-staging`
- `phonebill-user-service-prod`
---
## 9. 트러블슈팅
### 9.1 이미지 푸시 실패
- Docker Hub 인증 정보 확인
- Rate Limit 확인 (무료 계정 제한)
### 9.2 배포 실패
```bash
# Pod 이벤트 확인
kubectl describe pod {POD_NAME} -n phonebill
# Pod 로그 확인
kubectl logs {POD_NAME} -n phonebill
```
### 9.3 Kustomize 빌드 실패
- 리소스 파일 존재 여부 확인
- YAML 문법 검증
- `kubectl kustomize` 명령으로 디버깅
### 9.4 SonarQube 연결 실패
- SonarQube 서버 URL 확인
- 인증 토큰 유효성 확인
- 네트워크 연결 확인
---
## 10. 체크리스트
### 사전 준비
- [ ] Jenkins 필수 플러그인 설치 완료
- [ ] Docker Hub Credentials 등록 완료
- [ ] SonarQube Token 등록 완료 (선택)
### 배포 전 확인
- [ ] 환경 변수 파일 설정 완료
- [ ] Kubernetes 컨텍스트 설정 완료
- [ ] 이미지 레지스트리 인증 설정
- [ ] 네임스페이스 생성 완료
- [ ] 백킹 서비스(DB, Redis) 준비 완료
### 배포 전
- [ ] 리소스 검증 스크립트 실행 완료
- [ ] 환경별 설정 파일 확인 완료
- [ ] Kustomize 빌드 테스트 완료
### 배포 후
- [ ] Pod 상태 확인 (Running)
- [ ] 서비스 엔드포인트 확인
- [ ] Ingress 접근 테스트
- [ ] 로그 이상 여부 확인
### 배포 후 확인
- [ ] 모든 파드 Running 상태 확인
- [ ] 서비스 엔드포인트 정상 응답
- [ ] 로그에 에러 없음
- [ ] 헬스체크 정상 통과

View File

@ -1,8 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: api-gateway-config
name: cm-api-gateway
labels:
app: api-gateway
app.kubernetes.io/part-of: phonebill

View File

@ -2,7 +2,6 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
labels:
app: api-gateway
app.kubernetes.io/part-of: phonebill
@ -25,11 +24,11 @@ spec:
name: http
envFrom:
- configMapRef:
name: phonebill-common-config
name: cm-common
- configMapRef:
name: api-gateway-config
name: cm-api-gateway
- secretRef:
name: phonebill-common-secret
name: secret-common
resources:
requests:
cpu: "256m"

View File

@ -2,7 +2,6 @@ apiVersion: v1
kind: Service
metadata:
name: api-gateway
labels:
app: api-gateway
app.kubernetes.io/part-of: phonebill

View File

@ -1,8 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: bill-service-config
name: cm-bill-service
labels:
app: bill-service
app.kubernetes.io/part-of: phonebill

View File

@ -2,7 +2,6 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: bill-service
labels:
app: bill-service
app.kubernetes.io/part-of: phonebill
@ -25,13 +24,13 @@ spec:
name: http
envFrom:
- configMapRef:
name: phonebill-common-config
name: cm-common
- configMapRef:
name: bill-service-config
name: cm-bill-service
- secretRef:
name: phonebill-common-secret
name: secret-common
- secretRef:
name: bill-service-db-secret
name: secret-bill-service
resources:
requests:
cpu: "256m"

View File

@ -1,8 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
name: bill-service-db-secret
name: secret-bill-service
labels:
app: bill-service
app.kubernetes.io/part-of: phonebill

View File

@ -2,7 +2,6 @@ apiVersion: v1
kind: Service
metadata:
name: bill-service
labels:
app: bill-service
app.kubernetes.io/part-of: phonebill

View File

@ -1,8 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: phonebill-common-config
name: cm-common
labels:
app.kubernetes.io/part-of: phonebill
data:

View File

@ -2,7 +2,6 @@ apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: phonebill-ingress
labels:
app.kubernetes.io/part-of: phonebill
annotations:
@ -10,6 +9,7 @@ metadata:
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
ingressClassName: nginx
rules:

View File

@ -1,13 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: phonebill-common-secret
name: secret-common
labels:
app.kubernetes.io/part-of: phonebill
type: Opaque
stringData:
# JWT Secret (최소 256비트 이상, HS256 알고리즘용)
JWT_SECRET: "EK1ZV7vROOXREXbYe/BCISdQq0Yklk9JtoA2v88ux1DBDc0bDGiRRxHeDSb7GHkDP9IUYHMVsBi4/1rS4OhfRg=="
# Redis 비밀번호 (비밀번호 없는 경우 빈 값)
REDIS_PASSWORD: "P@ssw0rd$"

View File

@ -1,8 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: kos-mock-config
name: cm-kos-mock
labels:
app: kos-mock
app.kubernetes.io/part-of: phonebill

View File

@ -2,7 +2,6 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: kos-mock
labels:
app: kos-mock
app.kubernetes.io/part-of: phonebill
@ -25,11 +24,11 @@ spec:
name: http
envFrom:
- configMapRef:
name: phonebill-common-config
name: cm-common
- configMapRef:
name: kos-mock-config
name: cm-kos-mock
- secretRef:
name: phonebill-common-secret
name: secret-common
resources:
requests:
cpu: "256m"

View File

@ -2,7 +2,6 @@ apiVersion: v1
kind: Service
metadata:
name: kos-mock
labels:
app: kos-mock
app.kubernetes.io/part-of: phonebill

View File

@ -1,8 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: product-service-config
name: cm-product-service
labels:
app: product-service
app.kubernetes.io/part-of: phonebill

View File

@ -2,7 +2,6 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: product-service
labels:
app: product-service
app.kubernetes.io/part-of: phonebill
@ -25,13 +24,13 @@ spec:
name: http
envFrom:
- configMapRef:
name: phonebill-common-config
name: cm-common
- configMapRef:
name: product-service-config
name: cm-product-service
- secretRef:
name: phonebill-common-secret
name: secret-common
- secretRef:
name: product-service-db-secret
name: secret-product-service
resources:
requests:
cpu: "256m"

View File

@ -1,8 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
name: product-service-db-secret
name: secret-product-service
labels:
app: product-service
app.kubernetes.io/part-of: phonebill

View File

@ -2,7 +2,6 @@ apiVersion: v1
kind: Service
metadata:
name: product-service
labels:
app: product-service
app.kubernetes.io/part-of: phonebill

View File

@ -1,8 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: user-service-config
name: cm-user-service
labels:
app: user-service
app.kubernetes.io/part-of: phonebill

View File

@ -2,7 +2,6 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
labels:
app: user-service
app.kubernetes.io/part-of: phonebill
@ -25,13 +24,13 @@ spec:
name: http
envFrom:
- configMapRef:
name: phonebill-common-config
name: cm-common
- configMapRef:
name: user-service-config
name: cm-user-service
- secretRef:
name: phonebill-common-secret
name: secret-common
- secretRef:
name: user-service-db-secret
name: secret-user-service
resources:
requests:
cpu: "256m"

View File

@ -1,8 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
name: user-service-db-secret
name: secret-user-service
labels:
app: user-service
app.kubernetes.io/part-of: phonebill

View File

@ -2,7 +2,6 @@ apiVersion: v1
kind: Service
metadata:
name: user-service
labels:
app: user-service
app.kubernetes.io/part-of: phonebill

View File

@ -1,7 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: phonebill-common-config
name: cm-common
labels:
app.kubernetes.io/part-of: phonebill
data:

View File

@ -7,21 +7,18 @@ resources:
- ../../base
patches:
# Common patches
- path: cm-common-patch.yaml
target:
kind: ConfigMap
name: phonebill-common-config
name: cm-common
- path: secret-common-patch.yaml
target:
kind: Secret
name: phonebill-common-secret
name: secret-common
- path: ingress-patch.yaml
target:
kind: Ingress
name: phonebill-ingress
# Deployment patches
- path: deployment-api-gateway-patch.yaml
target:
kind: Deployment
@ -42,29 +39,27 @@ patches:
target:
kind: Deployment
name: kos-mock
# Service Secret patches
- path: secret-user-service-patch.yaml
target:
kind: Secret
name: user-service-db-secret
name: secret-user-service
- path: secret-bill-service-patch.yaml
target:
kind: Secret
name: bill-service-db-secret
name: secret-bill-service
- path: secret-product-service-patch.yaml
target:
kind: Secret
name: product-service-db-secret
name: secret-product-service
images:
- name: docker.io/hiondal/api-gateway
newTag: latest
newTag: dev-latest
- name: docker.io/hiondal/user-service
newTag: latest
newTag: dev-latest
- name: docker.io/hiondal/bill-service
newTag: latest
newTag: dev-latest
- name: docker.io/hiondal/product-service
newTag: latest
newTag: dev-latest
- name: docker.io/hiondal/kos-mock
newTag: latest
newTag: dev-latest

View File

@ -1,7 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
name: bill-service-db-secret
name: secret-bill-service
labels:
app: bill-service
app.kubernetes.io/part-of: phonebill

View File

@ -1,7 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
name: phonebill-common-secret
name: secret-common
labels:
app.kubernetes.io/part-of: phonebill
type: Opaque

View File

@ -1,7 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
name: product-service-db-secret
name: secret-product-service
labels:
app: product-service
app.kubernetes.io/part-of: phonebill

View File

@ -1,7 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
name: user-service-db-secret
name: secret-user-service
labels:
app: user-service
app.kubernetes.io/part-of: phonebill

View File

@ -1,7 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: phonebill-common-config
name: cm-common
labels:
app.kubernetes.io/part-of: phonebill
data:

View File

@ -16,7 +16,7 @@ spec:
tls:
- hosts:
- phonebill.example.com
secretName: phonebill-prod-tls
secretName: phonebill-tls
rules:
- host: phonebill.example.com
http:

View File

@ -1,27 +1,24 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: phonebill-prod
namespace: phonebill
resources:
- ../../base
patches:
# Common patches
- path: cm-common-patch.yaml
target:
kind: ConfigMap
name: phonebill-common-config
name: cm-common
- path: secret-common-patch.yaml
target:
kind: Secret
name: phonebill-common-secret
name: secret-common
- path: ingress-patch.yaml
target:
kind: Ingress
name: phonebill-ingress
# Deployment patches
- path: deployment-api-gateway-patch.yaml
target:
kind: Deployment
@ -42,29 +39,27 @@ patches:
target:
kind: Deployment
name: kos-mock
# Service Secret patches
- path: secret-user-service-patch.yaml
target:
kind: Secret
name: user-service-db-secret
name: secret-user-service
- path: secret-bill-service-patch.yaml
target:
kind: Secret
name: bill-service-db-secret
name: secret-bill-service
- path: secret-product-service-patch.yaml
target:
kind: Secret
name: product-service-db-secret
name: secret-product-service
images:
- name: docker.io/hiondal/api-gateway
newTag: latest
newTag: prod-latest
- name: docker.io/hiondal/user-service
newTag: latest
newTag: prod-latest
- name: docker.io/hiondal/bill-service
newTag: latest
newTag: prod-latest
- name: docker.io/hiondal/product-service
newTag: latest
newTag: prod-latest
- name: docker.io/hiondal/kos-mock
newTag: latest
newTag: prod-latest

View File

@ -1,11 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: bill-service-db-secret
name: secret-bill-service
labels:
app: bill-service
app.kubernetes.io/part-of: phonebill
type: Opaque
stringData:
DB_USERNAME: "unicorn"
DB_PASSWORD: "PROD_DB_PASSWORD"
DB_PASSWORD: "P@ssw0rd$"

View File

@ -1,10 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: phonebill-common-secret
name: secret-common
labels:
app.kubernetes.io/part-of: phonebill
type: Opaque
stringData:
JWT_SECRET: "PROD_JWT_SECRET_REPLACE_WITH_SECURE_VALUE"
REDIS_PASSWORD: "PROD_REDIS_PASSWORD"
JWT_SECRET: "EK1ZV7vROOXREXbYe/BCISdQq0Yklk9JtoA2v88ux1DBDc0bDGiRRxHeDSb7GHkDP9IUYHMVsBi4/1rS4OhfRg=="
REDIS_PASSWORD: "P@ssw0rd$"

View File

@ -1,11 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: product-service-db-secret
name: secret-product-service
labels:
app: product-service
app.kubernetes.io/part-of: phonebill
type: Opaque
stringData:
DB_USERNAME: "unicorn"
DB_PASSWORD: "PROD_DB_PASSWORD"
DB_PASSWORD: "P@ssw0rd$"

View File

@ -1,11 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: user-service-db-secret
name: secret-user-service
labels:
app: user-service
app.kubernetes.io/part-of: phonebill
type: Opaque
stringData:
DB_USERNAME: "unicorn"
DB_PASSWORD: "PROD_DB_PASSWORD"
DB_PASSWORD: "P@ssw0rd$"

View File

@ -1,7 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: phonebill-common-config
name: cm-common
labels:
app.kubernetes.io/part-of: phonebill
data:

View File

@ -10,7 +10,7 @@ metadata:
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-staging"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:

View File

@ -7,21 +7,18 @@ resources:
- ../../base
patches:
# Common patches
- path: cm-common-patch.yaml
target:
kind: ConfigMap
name: phonebill-common-config
name: cm-common
- path: secret-common-patch.yaml
target:
kind: Secret
name: phonebill-common-secret
name: secret-common
- path: ingress-patch.yaml
target:
kind: Ingress
name: phonebill-ingress
# Deployment patches
- path: deployment-api-gateway-patch.yaml
target:
kind: Deployment
@ -42,29 +39,27 @@ patches:
target:
kind: Deployment
name: kos-mock
# Service Secret patches
- path: secret-user-service-patch.yaml
target:
kind: Secret
name: user-service-db-secret
name: secret-user-service
- path: secret-bill-service-patch.yaml
target:
kind: Secret
name: bill-service-db-secret
name: secret-bill-service
- path: secret-product-service-patch.yaml
target:
kind: Secret
name: product-service-db-secret
name: secret-product-service
images:
- name: docker.io/hiondal/api-gateway
newTag: latest
newTag: staging-latest
- name: docker.io/hiondal/user-service
newTag: latest
newTag: staging-latest
- name: docker.io/hiondal/bill-service
newTag: latest
newTag: staging-latest
- name: docker.io/hiondal/product-service
newTag: latest
newTag: staging-latest
- name: docker.io/hiondal/kos-mock
newTag: latest
newTag: staging-latest

View File

@ -1,11 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: bill-service-db-secret
name: secret-bill-service
labels:
app: bill-service
app.kubernetes.io/part-of: phonebill
type: Opaque
stringData:
DB_USERNAME: "unicorn"
DB_PASSWORD: "STAGING_DB_PASSWORD"
DB_PASSWORD: "P@ssw0rd$"

View File

@ -1,10 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: phonebill-common-secret
name: secret-common
labels:
app.kubernetes.io/part-of: phonebill
type: Opaque
stringData:
JWT_SECRET: "STAGING_JWT_SECRET_REPLACE_WITH_SECURE_VALUE"
REDIS_PASSWORD: "STAGING_REDIS_PASSWORD"
JWT_SECRET: "EK1ZV7vROOXREXbYe/BCISdQq0Yklk9JtoA2v88ux1DBDc0bDGiRRxHeDSb7GHkDP9IUYHMVsBi4/1rS4OhfRg=="
REDIS_PASSWORD: "P@ssw0rd$"

View File

@ -1,11 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: product-service-db-secret
name: secret-product-service
labels:
app: product-service
app.kubernetes.io/part-of: phonebill
type: Opaque
stringData:
DB_USERNAME: "unicorn"
DB_PASSWORD: "STAGING_DB_PASSWORD"
DB_PASSWORD: "P@ssw0rd$"

View File

@ -1,11 +1,11 @@
apiVersion: v1
kind: Secret
metadata:
name: user-service-db-secret
name: secret-user-service
labels:
app: user-service
app.kubernetes.io/part-of: phonebill
type: Opaque
stringData:
DB_USERNAME: "unicorn"
DB_PASSWORD: "STAGING_DB_PASSWORD"
DB_PASSWORD: "P@ssw0rd$"

View File

@ -4,35 +4,32 @@ set -e
ENVIRONMENT=${1:-dev}
IMAGE_TAG=${2:-latest}
echo "🚀 Deploying to ${ENVIRONMENT} environment with tag ${IMAGE_TAG}..."
# 환경별 설정 파일 로드
source "$(dirname "$0")/../config/deploy_env_vars_${ENVIRONMENT}"
echo "🚀 Starting deployment to ${ENVIRONMENT} environment..."
# 환경별 이미지 태그 업데이트
cd "$(dirname "$0")/../kustomize/overlays/${ENVIRONMENT}"
cd deployment/cicd/kustomize/overlays/${ENVIRONMENT}
# 서비스 목록
# 서비스 목록 (공백으로 구분)
services="api-gateway user-service bill-service product-service kos-mock"
# 각 서비스 이미지 태그 업데이트
for service in $services; do
echo "📦 Updating image tag for ${service}..."
kustomize edit set image docker.io/hiondal/$service:${ENVIRONMENT}-${IMAGE_TAG}
kustomize edit set image docker.io/hiondal/$service=docker.io/hiondal/$service:${ENVIRONMENT}-${IMAGE_TAG}
done
# 배포 실행
echo "📋 Applying Kustomize manifests..."
echo "📤 Applying Kubernetes manifests..."
kubectl apply -k .
# 배포 상태 확인
echo "⏳ Waiting for deployments to be ready..."
for service in $services; do
echo " Checking ${service}..."
kubectl rollout status deployment/$service -n ${namespace} --timeout=300s || echo " ⚠️ Timeout waiting for ${service}"
kubectl rollout status deployment/$service -n phonebill --timeout=300s
done
echo "✅ Deployment completed successfully!"
echo ""
echo "📊 Current status:"
kubectl get pods -n ${namespace}
echo "📊 Current deployment status:"
kubectl get pods -n phonebill

View File

@ -1,10 +1,12 @@
#!/bin/bash
# Base 리소스 누락 검증 스크립트
# Base 리소스 누락 검증 스크립트 (phonebill)
echo "🔍 Phonebill Base 리소스 누락 검증 시작..."
echo "🔍 phonebill Base 리소스 누락 검증 시작..."
BASE_DIR="deployment/cicd/kustomize/base"
MISSING_RESOURCES=0
REQUIRED_FILES=("deployment.yaml" "service.yaml")
OPTIONAL_FILES=("cm-" "secret-")
# 1. 각 서비스 디렉토리의 파일 확인
echo ""
@ -15,33 +17,24 @@ for dir in $BASE_DIR/*/; do
echo "=== $service ==="
# 필수 파일 확인
if [ -f "$dir/deployment.yaml" ]; then
echo " ✅ deployment.yaml"
else
echo " ❌ MISSING REQUIRED: deployment.yaml"
((MISSING_RESOURCES++))
fi
for required in "${REQUIRED_FILES[@]}"; do
if [ -f "$dir$required" ]; then
echo "$required"
else
echo " ❌ MISSING REQUIRED: $required"
((MISSING_RESOURCES++))
fi
done
if [ -f "$dir/service.yaml" ]; then
echo " ✅ service.yaml"
else
echo " ❌ MISSING REQUIRED: service.yaml"
((MISSING_RESOURCES++))
fi
# ConfigMap 확인
if ls "$dir"cm-*.yaml 1> /dev/null 2>&1; then
for file in "$dir"cm-*.yaml; do
echo "$(basename "$file")"
done
fi
# Secret 확인
if ls "$dir"secret-*.yaml 1> /dev/null 2>&1; then
for file in "$dir"secret-*.yaml; do
echo "$(basename "$file")"
done
fi
# 선택적 파일 확인
for optional in "${OPTIONAL_FILES[@]}"; do
files=($(ls "$dir"$optional*".yaml" 2>/dev/null))
if [ ${#files[@]} -gt 0 ]; then
for file in "${files[@]}"; do
echo "$(basename "$file")"
done
fi
done
echo ""
fi
done
@ -50,11 +43,15 @@ done
echo "2. Common 리소스 확인:"
COMMON_DIR="$BASE_DIR/common"
if [ -d "$COMMON_DIR" ]; then
for file in "$COMMON_DIR"/*.yaml; do
if [ -f "$file" ]; 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")"
fi
done
done
else
echo " ❌ Common 디렉토리에 YAML 파일이 없습니다"
((MISSING_RESOURCES++))
fi
else
echo " ❌ Common 디렉토리가 없습니다"
((MISSING_RESOURCES++))
@ -65,8 +62,9 @@ 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)
resource_path=$(echo "${BASH_REMATCH[1]}" | xargs) # 공백 제거
full_path="$BASE_DIR/$resource_path"
if [ -f "$full_path" ]; then
echo "$resource_path"