phonebill/.github/workflows/backend-cicd.yaml
ondal 3d8d72ac2b Kustomize 설정 및 GitHub Actions 워크플로우 정리
- ArgoCD 워크플로우 파일 삭제 (backend-cicd_ArgoCD.yaml)
- Kustomize base/overlays 설정 업데이트
- GitHub Actions 백엔드 CI/CD 파이프라인 개선
- 각 서비스 deployment 및 secret 설정 수정
- Docker 이미지 풀 시크릿을 플레이스홀더로 변경

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 16:09:21 +09:00

263 lines
10 KiB
YAML

name: Backend Services CI/CD (Generic K8s)
on:
push:
branches: [ main, develop ]
paths:
- 'api-gateway/**'
- 'user-service/**'
- 'bill-service/**'
- 'product-service/**'
- 'kos-mock/**'
- 'common/**'
- '.github/**'
pull_request:
branches: [ main ]
env:
# ============================================
# 변경: Azure ACR → Docker Hub
# ============================================
REGISTRY: docker.io
IMAGE_ORG: ${{ secrets.DOCKERHUB_USERNAME }}
NAMESPACE: phonebill
# SSH 터널링용
MINIKUBE_IP: "192.168.49.2"
jobs:
build:
name: Build and Test
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.set_outputs.outputs.image_tag }}
environment: ${{ steps.set_outputs.outputs.environment }}
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
java-version: '21'
distribution: 'temurin'
cache: 'gradle'
- name: Determine environment
id: determine_env
run: |
# workflow_dispatch 입력값 우선, 없으면 vars 사용
ENVIRONMENT="${{ vars.ENVIRONMENT || 'dev' }}"
echo "environment=$ENVIRONMENT" >> $GITHUB_OUTPUT
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: |
./gradlew build -x test
- name: SonarQube Analysis & Quality Gate
if: ${{ vars.SKIP_SONARQUBE != 'true' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
run: |
# Define services array
services=(api-gateway user-service bill-service product-service kos-mock)
# Run tests, coverage reports, and SonarQube analysis for each service
for service in "${services[@]}"; do
./gradlew :$service:test :$service:jacocoTestReport :$service:sonar \
-Dsonar.projectKey=phonebill-$service-${{ steps.determine_env.outputs.environment }} \
-Dsonar.projectName=phonebill-$service-${{ steps.determine_env.outputs.environment }} \
-Dsonar.host.url=$SONAR_HOST_URL \
-Dsonar.token=$SONAR_TOKEN \
-Dsonar.java.binaries=build/classes/java/main \
-Dsonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco/test/jacocoTestReport.xml \
-Dsonar.exclusions=**/config/**,**/entity/**,**/dto/**,**/*Application.class,**/exception/**
done
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: app-builds
path: |
api-gateway/build/libs/*.jar
user-service/build/libs/*.jar
bill-service/build/libs/*.jar
product-service/build/libs/*.jar
kos-mock/build/libs/*.jar
- name: Set outputs
id: set_outputs
run: |
IMAGE_TAG=$(date +%Y%m%d%H%M%S)
echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT
echo "environment=${{ steps.determine_env.outputs.environment }}" >> $GITHUB_OUTPUT
release:
name: Build and Push Docker Images
needs: build
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: app-builds
- name: Set environment variables from build job
run: |
echo "ENVIRONMENT=${{ needs.build.outputs.environment }}" >> $GITHUB_ENV
echo "IMAGE_TAG=${{ needs.build.outputs.image_tag }}" >> $GITHUB_ENV
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# ============================================
# 변경: Docker Hub 로그인만 사용
# ============================================
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Build and push Docker images for all services
run: |
# Define services array
services=(api-gateway user-service bill-service product-service kos-mock)
# Build and push each service image
for service in "${services[@]}"; do
echo "Building and pushing $service..."
docker build \
--build-arg BUILD_LIB_DIR="$service/build/libs" \
--build-arg ARTIFACTORY_FILE="$service.jar" \
-f deployment/container/Dockerfile-backend \
-t ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_USERNAME }}/$service:${{ needs.build.outputs.environment }}-${{ needs.build.outputs.image_tag }} \
-t ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_USERNAME }}/$service:${{ needs.build.outputs.environment }}-latest .
docker push ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_USERNAME }}/$service:${{ needs.build.outputs.environment }}-${{ needs.build.outputs.image_tag }}
docker push ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_USERNAME }}/$service:${{ needs.build.outputs.environment }}-latest
done
deploy:
name: Deploy to Kubernetes
needs: [build, release]
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set environment variables
run: |
echo "IMAGE_TAG=${{ needs.build.outputs.image_tag }}" >> $GITHUB_ENV
echo "ENVIRONMENT=${{ needs.build.outputs.environment }}" >> $GITHUB_ENV
# ============================================
# 변경: Azure CLI/Login 제거 → SSH 터널링
# ============================================
- name: Setup SSH key
run: |
mkdir -p ~/.ssh
echo "${{ secrets.VM_SSH_KEY }}" > ~/.ssh/vm_key
chmod 600 ~/.ssh/vm_key
ssh-keyscan -H ${{ secrets.VM_IP }} >> ~/.ssh/known_hosts 2>/dev/null || true
- name: Create SSH tunnel to Minikube
run: |
ssh -i ~/.ssh/vm_key \
-o StrictHostKeyChecking=no \
-o ServerAliveInterval=60 \
-L 8443:${{ env.MINIKUBE_IP }}:8443 \
${{ secrets.VM_USER }}@${{ secrets.VM_IP }} -N &
sleep 5
echo "✅ SSH tunnel established"
# ============================================
# 변경: az aks get-credentials → KUBECONFIG Secret
# ============================================
- name: Setup kubectl
uses: azure/setup-kubectl@v3
- name: Configure kubectl via KUBECONFIG
run: |
mkdir -p $HOME/.kube
echo "${{ secrets.KUBECONFIG }}" > $HOME/.kube/config
chmod 600 $HOME/.kube/config
# server 주소를 localhost:8443으로 변경 (SSH 터널 통해 접근)
sed -i 's|server:.*|server: https://127.0.0.1:8443|g' $HOME/.kube/config
- name: Verify cluster connection
run: |
kubectl cluster-info
kubectl get nodes
- name: Create namespace
run: |
kubectl create namespace ${{ env.NAMESPACE }} --dry-run=client -o yaml | kubectl apply -f -
# ============================================
# 추가: Docker Hub pull secret 생성
# ============================================
- name: Create image pull secret
run: |
kubectl create secret docker-registry dockerhub-secret \
--docker-server=docker.io \
--docker-username=${{ secrets.DOCKERHUB_USERNAME }} \
--docker-password=${{ secrets.DOCKERHUB_PASSWORD }} \
--namespace=${{ env.NAMESPACE }} \
--dry-run=client -o yaml | kubectl apply -f -
- name: Install Kustomize
run: |
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
sudo mv kustomize /usr/local/bin/
- name: Update Kustomize images and deploy
run: |
cd .github/kustomize/overlays/${{ env.ENVIRONMENT }}
# ============================================
# 변경: 이미지 경로를 Docker Hub로
# ============================================
kustomize edit set image ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_USERNAME }}/api-gateway:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
kustomize edit set image ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_USERNAME }}/user-service:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
kustomize edit set image ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_USERNAME }}/bill-service:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
kustomize edit set image ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_USERNAME }}/product-service:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
kustomize edit set image ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_USERNAME }}/kos-mock:${{ env.ENVIRONMENT }}-${{ env.IMAGE_TAG }}
kubectl apply -k .
- name: Wait for deployments to be ready
run: |
echo "Waiting for deployments to be ready..."
kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/api-gateway --timeout=300s
kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/user-service --timeout=300s
kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/bill-service --timeout=300s
kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/product-service --timeout=300s
kubectl -n ${{ env.NAMESPACE }} wait --for=condition=available deployment/kos-mock --timeout=300s
- name: Show deployment status
run: |
kubectl -n ${{ env.NAMESPACE }} get pods -o wide
kubectl -n ${{ env.NAMESPACE }} get svc
# ============================================
# 추가: SSH 터널 정리
# ============================================
- name: Cleanup SSH tunnel
if: always()
run: |
pkill -f "ssh.*8443" || true