Replaces direct kubectl usage with SSH-based remote execution for Kubernetes deployment steps. Updates secrets and environment variables to use SSH key and connection info, and modifies manifest transfer and deployment verification to operate over SSH. This improves security and flexibility for remote Kubernetes server management.
351 lines
13 KiB
YAML
351 lines
13 KiB
YAML
# 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 비밀번호
|
|
# - K8S_SSH_KEY: base64로 인코딩된 SSH 비밀키 (쿠버네티스 서버 접속용)
|
|
#
|
|
# 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: harbor.wace.me
|
|
HARBOR_REGISTRY_EXTERNAL: harbor.wace.me
|
|
HARBOR_PROJECT: speefox_vexplor
|
|
K8S_NAMESPACE: vexplor
|
|
|
|
# 쿠버네티스 서버 SSH 접속 정보
|
|
K8S_SSH_HOST: 112.168.212.142
|
|
K8S_SSH_PORT: 22
|
|
K8S_SSH_USER: wace
|
|
|
|
# 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 openssh-client
|
|
|
|
# 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
|
|
ssh -V
|
|
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 푸시 완료"
|
|
|
|
# SSH 키 설정 (쿠버네티스 서버 접속용)
|
|
- name: Setup SSH Key
|
|
env:
|
|
SSH_KEY_CONTENT: ${{ secrets.K8S_SSH_KEY }}
|
|
run: |
|
|
echo "SSH 키 설정..."
|
|
|
|
if [ -z "${SSH_KEY_CONTENT}" ]; then
|
|
echo "K8S_SSH_KEY secret이 설정되지 않았습니다!"
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p ~/.ssh
|
|
echo "${SSH_KEY_CONTENT}" | base64 -d > ~/.ssh/id_rsa
|
|
chmod 600 ~/.ssh/id_rsa
|
|
|
|
# known_hosts에 쿠버네티스 서버 추가
|
|
ssh-keyscan -p ${K8S_SSH_PORT} ${K8S_SSH_HOST} >> ~/.ssh/known_hosts 2>/dev/null
|
|
|
|
# SSH 연결 테스트
|
|
echo "SSH 연결 테스트..."
|
|
ssh -o StrictHostKeyChecking=no -p ${K8S_SSH_PORT} ${K8S_SSH_USER}@${K8S_SSH_HOST} "echo 'SSH 연결 성공'"
|
|
echo "SSH 키 설정 완료"
|
|
|
|
# k8s 매니페스트 파일을 쿠버네티스 서버로 전송
|
|
- name: Transfer k8s manifests
|
|
run: |
|
|
echo "k8s 매니페스트 파일 전송..."
|
|
cd /workspace/source
|
|
|
|
# 쿠버네티스 서버에 디렉토리 생성
|
|
ssh -p ${K8S_SSH_PORT} ${K8S_SSH_USER}@${K8S_SSH_HOST} "mkdir -p ~/vexplor-deploy/k8s"
|
|
|
|
# k8s 파일 전송
|
|
scp -P ${K8S_SSH_PORT} -r k8s/* ${K8S_SSH_USER}@${K8S_SSH_HOST}:~/vexplor-deploy/k8s/
|
|
|
|
echo "매니페스트 파일 전송 완료"
|
|
|
|
# Kubernetes 배포 (SSH를 통해 원격 실행)
|
|
- name: Deploy to Kubernetes
|
|
env:
|
|
HARBOR_USER: ${{ secrets.HARBOR_USERNAME }}
|
|
HARBOR_PASS: ${{ secrets.HARBOR_PASSWORD }}
|
|
run: |
|
|
echo "Kubernetes 배포 시작 (SSH 원격 실행)..."
|
|
|
|
# SSH를 통해 쿠버네티스 서버에서 kubectl 명령 실행
|
|
ssh -p ${K8S_SSH_PORT} ${K8S_SSH_USER}@${K8S_SSH_HOST} << 'DEPLOY_SCRIPT'
|
|
set -e
|
|
cd ~/vexplor-deploy
|
|
|
|
echo "네임스페이스 확인..."
|
|
kubectl apply -f k8s/namespace.yaml
|
|
|
|
echo "ConfigMap 적용..."
|
|
kubectl apply -f k8s/vexplor-config.yaml -n vexplor
|
|
|
|
# Secret 적용 (존재하는 경우에만)
|
|
if [ -f k8s/vexplor-secret.yaml ]; then
|
|
echo "Secret 적용..."
|
|
kubectl apply -f k8s/vexplor-secret.yaml -n vexplor
|
|
fi
|
|
|
|
echo "네임스페이스 및 ConfigMap 적용 완료"
|
|
DEPLOY_SCRIPT
|
|
|
|
# Harbor Registry Secret 생성 (별도로 처리 - 환경변수 사용)
|
|
echo "Harbor Registry Secret 확인..."
|
|
ssh -p ${K8S_SSH_PORT} ${K8S_SSH_USER}@${K8S_SSH_HOST} "kubectl get secret harbor-registry -n vexplor" > /dev/null 2>&1 || \
|
|
ssh -p ${K8S_SSH_PORT} ${K8S_SSH_USER}@${K8S_SSH_HOST} "kubectl create secret docker-registry harbor-registry \
|
|
--docker-server=${HARBOR_REGISTRY_K8S} \
|
|
--docker-username=${HARBOR_USER} \
|
|
--docker-password='${HARBOR_PASS}' \
|
|
-n vexplor"
|
|
echo "Harbor Registry Secret 확인 완료"
|
|
|
|
# Backend 배포
|
|
echo "Backend 배포..."
|
|
ssh -p ${K8S_SSH_PORT} ${K8S_SSH_USER}@${K8S_SSH_HOST} << BACKEND_DEPLOY
|
|
set -e
|
|
cd ~/vexplor-deploy
|
|
kubectl apply -f k8s/vexplor-backend-deployment.yaml -n vexplor
|
|
|
|
echo "Backend 이미지 업데이트..."
|
|
kubectl set image deployment/${BACKEND_DEPLOYMENT_NAME} \
|
|
${BACKEND_CONTAINER_NAME}=${HARBOR_REGISTRY_K8S}/${HARBOR_PROJECT}/${BACKEND_IMAGE_NAME}:latest \
|
|
-n vexplor || true
|
|
kubectl rollout restart deployment/${BACKEND_DEPLOYMENT_NAME} -n vexplor
|
|
|
|
echo "Backend Rolling Update 진행 중..."
|
|
kubectl rollout status deployment/${BACKEND_DEPLOYMENT_NAME} -n vexplor --timeout=5m
|
|
echo "Backend 배포 완료"
|
|
BACKEND_DEPLOY
|
|
|
|
# Frontend 배포
|
|
echo "Frontend 배포..."
|
|
ssh -p ${K8S_SSH_PORT} ${K8S_SSH_USER}@${K8S_SSH_HOST} << FRONTEND_DEPLOY
|
|
set -e
|
|
cd ~/vexplor-deploy
|
|
kubectl apply -f k8s/vexplor-frontend-deployment.yaml -n vexplor
|
|
|
|
echo "Frontend 이미지 업데이트..."
|
|
kubectl set image deployment/${FRONTEND_DEPLOYMENT_NAME} \
|
|
${FRONTEND_CONTAINER_NAME}=${HARBOR_REGISTRY_K8S}/${HARBOR_PROJECT}/${FRONTEND_IMAGE_NAME}:latest \
|
|
-n vexplor || true
|
|
kubectl rollout restart deployment/${FRONTEND_DEPLOYMENT_NAME} -n vexplor
|
|
|
|
echo "Frontend Rolling Update 진행 중..."
|
|
kubectl rollout status deployment/${FRONTEND_DEPLOYMENT_NAME} -n vexplor --timeout=5m
|
|
echo "Frontend 배포 완료"
|
|
FRONTEND_DEPLOY
|
|
|
|
# Ingress 배포
|
|
echo "Ingress 배포..."
|
|
ssh -p ${K8S_SSH_PORT} ${K8S_SSH_USER}@${K8S_SSH_HOST} "cd ~/vexplor-deploy && kubectl apply -f k8s/vexplor-ingress.yaml -n vexplor"
|
|
|
|
echo "전체 배포 완료!"
|
|
|
|
# 배포 검증
|
|
- name: Verify deployment
|
|
run: |
|
|
echo "배포 검증..."
|
|
ssh -p ${K8S_SSH_PORT} ${K8S_SSH_USER}@${K8S_SSH_HOST} << 'VERIFY_SCRIPT'
|
|
echo ""
|
|
echo "Backend 상태:"
|
|
kubectl get deployment vexplor-backend -n vexplor
|
|
kubectl get pods -l app=vexplor-backend -n vexplor
|
|
echo ""
|
|
echo "Frontend 상태:"
|
|
kubectl get deployment vexplor-frontend -n vexplor
|
|
kubectl get pods -l app=vexplor-frontend -n vexplor
|
|
echo ""
|
|
echo "Services:"
|
|
kubectl get svc -n vexplor
|
|
echo ""
|
|
echo "Ingress:"
|
|
kubectl get ingress -n vexplor
|
|
echo ""
|
|
echo "검증 완료"
|
|
VERIFY_SCRIPT
|
|
|
|
# 배포 요약
|
|
- 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 "배포 실패! 이전 버전으로 롤백..."
|
|
ssh -p ${K8S_SSH_PORT} ${K8S_SSH_USER}@${K8S_SSH_HOST} "kubectl rollout undo deployment/vexplor-backend -n vexplor" || true
|
|
ssh -p ${K8S_SSH_PORT} ${K8S_SSH_USER}@${K8S_SSH_HOST} "kubectl rollout undo deployment/vexplor-frontend -n vexplor" || true
|
|
|
|
# Harbor 로그아웃
|
|
- name: Logout from Harbor
|
|
if: always()
|
|
run: |
|
|
export DOCKER_HOST=unix:///var/run/docker.sock
|
|
docker logout ${HARBOR_REGISTRY} || true
|
|
|