# Gitea Actions Workflow - vexplor 자동 배포 # # 환경 변수: # - GITEA_DOMAIN: g.wace.me # - HARBOR_REGISTRY: harbor.wace.me # - K8S_NAMESPACE: vexplor # # 필수 Secrets (Repository Settings > Secrets): # - HARBOR_USERNAME: Harbor 사용자명 # - HARBOR_PASSWORD: Harbor 비밀번호 # - KUBECONFIG: base64로 인코딩된 Kubernetes config # # Application Secrets: # - k8s/vexplor-secret.yaml 파일에서 관리 name: Deploy vexplor on: push: branches: - main - master paths: - "backend-node/**" - "frontend/**" - "docker/**" - "k8s/**" - ".gitea/workflows/deploy.yml" workflow_dispatch: env: GITEA_DOMAIN: g.wace.me HARBOR_REGISTRY: localhost:5001 HARBOR_REGISTRY_K8S: 192.168.1.100:5001 HARBOR_REGISTRY_EXTERNAL: harbor.wace.me HARBOR_PROJECT: speefox_vexplor K8S_NAMESPACE: vexplor # Frontend 빌드 환경 변수 NEXT_PUBLIC_API_URL: "https://api.vexplor.com/api" NEXT_PUBLIC_ENV: "production" INTERNAL_API_URL: "http://vexplor-backend-service:3001" # Frontend 설정 FRONTEND_IMAGE_NAME: vexplor-frontend FRONTEND_DEPLOYMENT_NAME: vexplor-frontend FRONTEND_CONTAINER_NAME: vexplor-frontend FRONTEND_BUILD_CONTEXT: frontend FRONTEND_DOCKERFILE_PATH: docker/deploy/frontend.Dockerfile # Backend 설정 BACKEND_IMAGE_NAME: vexplor-backend BACKEND_DEPLOYMENT_NAME: vexplor-backend BACKEND_CONTAINER_NAME: vexplor-backend BACKEND_BUILD_CONTEXT: backend-node BACKEND_DOCKERFILE_PATH: docker/deploy/backend.Dockerfile jobs: build-and-deploy: runs-on: ubuntu-24.04 steps: # 작업 디렉토리 정리 - name: Clean workspace run: | echo "작업 디렉토리 정리..." cd /workspace rm -rf source mkdir -p source echo "정리 완료" # 필수 도구 설치 - name: Install required tools run: | echo "필수 도구 설치 중..." apt-get update -qq apt-get install -y git curl ca-certificates gnupg # kubectl 설치 curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" chmod +x kubectl mv kubectl /usr/local/bin/ # Docker 클라이언트 설치 install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc chmod a+r /etc/apt/keyrings/docker.asc echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null apt-get update -qq apt-get install -y docker-ce-cli echo "설치 완료:" git --version kubectl version --client docker --version export DOCKER_HOST=unix:///var/run/docker.sock docker version || echo "소켓 연결 대기 중..." # 저장소 체크아웃 - name: Checkout code run: | echo "저장소 체크아웃..." cd /workspace/source git clone --depth 1 --branch ${GITHUB_REF_NAME} \ https://oauth2:${{ github.token }}@${GITEA_DOMAIN}/${GITHUB_REPOSITORY}.git . echo "체크아웃 완료" git log -1 --oneline # 빌드 환경 설정 - name: Set up build environment run: | IMAGE_TAG="v$(date +%Y%m%d-%H%M%S)-${GITHUB_SHA::7}" echo "IMAGE_TAG=${IMAGE_TAG}" >> $GITHUB_ENV # Frontend 이미지 echo "FRONTEND_FULL_IMAGE=${HARBOR_REGISTRY}/${HARBOR_PROJECT}/${FRONTEND_IMAGE_NAME}" >> $GITHUB_ENV echo "FRONTEND_FULL_IMAGE_K8S=${HARBOR_REGISTRY_K8S}/${HARBOR_PROJECT}/${FRONTEND_IMAGE_NAME}" >> $GITHUB_ENV # Backend 이미지 echo "BACKEND_FULL_IMAGE=${HARBOR_REGISTRY}/${HARBOR_PROJECT}/${BACKEND_IMAGE_NAME}" >> $GITHUB_ENV echo "BACKEND_FULL_IMAGE_K8S=${HARBOR_REGISTRY_K8S}/${HARBOR_PROJECT}/${BACKEND_IMAGE_NAME}" >> $GITHUB_ENV echo "빌드 태그: ${IMAGE_TAG}" # Harbor 로그인 - name: Login to Harbor env: HARBOR_USER: ${{ secrets.HARBOR_USERNAME }} HARBOR_PASS: ${{ secrets.HARBOR_PASSWORD }} run: | echo "Harbor 로그인..." export DOCKER_HOST=unix:///var/run/docker.sock echo "${HARBOR_PASS}" | docker login ${HARBOR_REGISTRY} \ --username ${HARBOR_USER} \ --password-stdin echo "Harbor 로그인 완료" # Backend 빌드 및 푸시 - name: Build and Push Backend image run: | echo "Backend 이미지 빌드 및 푸시..." export DOCKER_HOST=unix:///var/run/docker.sock cd /workspace/source docker build \ -t ${BACKEND_FULL_IMAGE}:${IMAGE_TAG} \ -t ${BACKEND_FULL_IMAGE}:latest \ -f ${BACKEND_DOCKERFILE_PATH} \ ${BACKEND_BUILD_CONTEXT} docker push ${BACKEND_FULL_IMAGE}:${IMAGE_TAG} docker push ${BACKEND_FULL_IMAGE}:latest echo "Backend 푸시 완료" # Frontend 빌드 및 푸시 - name: Build and Push Frontend image run: | echo "Frontend 이미지 빌드 및 푸시..." export DOCKER_HOST=unix:///var/run/docker.sock cd /workspace/source echo "빌드 환경 변수:" echo " NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}" echo " NEXT_PUBLIC_ENV=${NEXT_PUBLIC_ENV}" docker build \ -t ${FRONTEND_FULL_IMAGE}:${IMAGE_TAG} \ -t ${FRONTEND_FULL_IMAGE}:latest \ -f ${FRONTEND_DOCKERFILE_PATH} \ --build-arg NEXT_PUBLIC_API_URL="${NEXT_PUBLIC_API_URL}" \ ${FRONTEND_BUILD_CONTEXT} docker push ${FRONTEND_FULL_IMAGE}:${IMAGE_TAG} docker push ${FRONTEND_FULL_IMAGE}:latest echo "Frontend 푸시 완료" # Kubernetes 설정 - name: Setup Kubernetes config env: KUBECONFIG_CONTENT: ${{ secrets.KUBECONFIG }} run: | echo "Kubernetes 설정..." if [ -z "${KUBECONFIG_CONTENT}" ]; then echo "KUBECONFIG secret이 설정되지 않았습니다!" exit 1 fi mkdir -p ~/.kube echo "${KUBECONFIG_CONTENT}" | base64 -d > ~/.kube/config chmod 600 ~/.kube/config if [ ! -s ~/.kube/config ]; then echo "kubeconfig 파일이 비어있습니다" exit 1 fi echo "kubeconfig 파일 생성 완료" kubectl cluster-info > /dev/null 2>&1 && echo "Kubernetes 클러스터 연결 성공" # Kubernetes 배포 - name: Deploy to Kubernetes run: | echo "Kubernetes 배포 시작..." cd /workspace/source # 네임스페이스 생성 (없을 때만) echo "네임스페이스 확인..." kubectl apply -f k8s/namespace.yaml # ConfigMap 적용 echo "ConfigMap 적용..." kubectl apply -f k8s/vexplor-config.yaml -n ${K8S_NAMESPACE} # Secret 적용 (존재하는 경우에만) if [ -f k8s/vexplor-secret.yaml ]; then echo "Secret 적용..." kubectl apply -f k8s/vexplor-secret.yaml -n ${K8S_NAMESPACE} fi # Harbor Registry Secret 생성 (없을 때만) echo "Harbor Registry Secret 확인..." if ! kubectl get secret harbor-registry -n ${K8S_NAMESPACE} > /dev/null 2>&1; then echo "Harbor Registry Secret 생성 중..." kubectl create secret docker-registry harbor-registry \ --docker-server=${HARBOR_REGISTRY_K8S} \ --docker-username=${{ secrets.HARBOR_USERNAME }} \ --docker-password=${{ secrets.HARBOR_PASSWORD }} \ -n ${K8S_NAMESPACE} echo "Harbor Registry Secret 생성 완료" else echo "Harbor Registry Secret 이미 존재" fi # Backend 배포 echo "Backend 배포..." kubectl apply -f k8s/vexplor-backend-deployment.yaml -n ${K8S_NAMESPACE} if kubectl get deployment ${BACKEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE} > /dev/null 2>&1; then echo "Backend 이미지 업데이트..." kubectl set image deployment/${BACKEND_DEPLOYMENT_NAME} \ ${BACKEND_CONTAINER_NAME}=${BACKEND_FULL_IMAGE_K8S}:latest \ -n ${K8S_NAMESPACE} kubectl rollout restart deployment/${BACKEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE} fi echo "Backend Rolling Update 진행 중..." kubectl rollout status deployment/${BACKEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE} --timeout=5m echo "Backend 배포 완료" # Frontend 배포 echo "Frontend 배포..." kubectl apply -f k8s/vexplor-frontend-deployment.yaml -n ${K8S_NAMESPACE} if kubectl get deployment ${FRONTEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE} > /dev/null 2>&1; then echo "Frontend 이미지 업데이트..." kubectl set image deployment/${FRONTEND_DEPLOYMENT_NAME} \ ${FRONTEND_CONTAINER_NAME}=${FRONTEND_FULL_IMAGE_K8S}:latest \ -n ${K8S_NAMESPACE} kubectl rollout restart deployment/${FRONTEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE} fi echo "Frontend Rolling Update 진행 중..." kubectl rollout status deployment/${FRONTEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE} --timeout=5m echo "Frontend 배포 완료" # Ingress 배포 echo "Ingress 배포..." kubectl apply -f k8s/vexplor-ingress.yaml -n ${K8S_NAMESPACE} echo "전체 배포 완료!" # 배포 검증 - name: Verify deployment run: | echo "배포 검증..." echo "" echo "Backend 상태:" kubectl get deployment ${BACKEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE} kubectl get pods -l app=${BACKEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE} echo "" echo "Frontend 상태:" kubectl get deployment ${FRONTEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE} kubectl get pods -l app=${FRONTEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE} echo "" echo "Services:" kubectl get svc -n ${K8S_NAMESPACE} echo "" echo "Ingress:" kubectl get ingress -n ${K8S_NAMESPACE} echo "" echo "검증 완료" # 배포 요약 - name: Deployment summary if: success() run: | echo "==========================================" echo "배포가 성공적으로 완료되었습니다!" echo "==========================================" echo "빌드 버전: ${IMAGE_TAG}" echo "Frontend: https://v1.vexplor.com" echo "Backend API: https://api.vexplor.com" echo "==========================================" # 실패 시 롤백 - name: Rollback on failure if: failure() run: | echo "배포 실패! 이전 버전으로 롤백..." kubectl rollout undo deployment/${BACKEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE} || true kubectl rollout undo deployment/${FRONTEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE} || true # Harbor 로그아웃 - name: Logout from Harbor if: always() run: | export DOCKER_HOST=unix:///var/run/docker.sock docker logout ${HARBOR_REGISTRY} || true