Refactor deploy workflow to use SSH for k8s operations

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.
This commit is contained in:
Johngreen
2025-12-22 17:39:26 +09:00
parent 47ac3dcaf1
commit 15265ebfc9

View File

@@ -8,7 +8,7 @@
# 필수 Secrets (Repository Settings > Secrets):
# - HARBOR_USERNAME: Harbor 사용자명
# - HARBOR_PASSWORD: Harbor 비밀번호
# - KUBECONFIG: base64로 인코딩된 Kubernetes config
# - K8S_SSH_KEY: base64로 인코딩된 SSH 비밀키 (쿠버네티스 서버 접속용)
#
# Application Secrets:
# - k8s/vexplor-secret.yaml 파일에서 관리
@@ -31,10 +31,15 @@ on:
env:
GITEA_DOMAIN: g.wace.me
HARBOR_REGISTRY: localhost:5001
HARBOR_REGISTRY_K8S: 192.168.1.100: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"
@@ -74,12 +79,7 @@ jobs:
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/
apt-get install -y git curl ca-certificates gnupg openssh-client
# Docker 클라이언트 설치
install -m 0755 -d /etc/apt/keyrings
@@ -94,7 +94,7 @@ jobs:
echo "설치 완료:"
git --version
kubectl version --client
ssh -V
docker --version
export DOCKER_HOST=unix:///var/run/docker.sock
@@ -180,100 +180,121 @@ jobs:
docker push ${FRONTEND_FULL_IMAGE}:latest
echo "Frontend 푸시 완료"
# Kubernetes 설정
- name: Setup Kubernetes config
# SSH 키 설정 (쿠버네티스 서버 접속용)
- name: Setup SSH Key
env:
KUBECONFIG_CONTENT: ${{ secrets.KUBECONFIG }}
SSH_KEY_CONTENT: ${{ secrets.K8S_SSH_KEY }}
run: |
echo "Kubernetes 설정..."
echo "SSH 키 설정..."
if [ -z "${KUBECONFIG_CONTENT}" ]; then
echo "KUBECONFIG secret이 설정되지 않았습니다!"
if [ -z "${SSH_KEY_CONTENT}" ]; then
echo "K8S_SSH_KEY secret이 설정되지 않았습니다!"
exit 1
fi
mkdir -p ~/.kube
echo "${KUBECONFIG_CONTENT}" | base64 -d > ~/.kube/config
chmod 600 ~/.kube/config
mkdir -p ~/.ssh
echo "${SSH_KEY_CONTENT}" | base64 -d > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
if [ ! -s ~/.kube/config ]; then
echo "kubeconfig 파일이 비어있습니다"
exit 1
fi
# known_hosts에 쿠버네티스 서버 추가
ssh-keyscan -p ${K8S_SSH_PORT} ${K8S_SSH_HOST} >> ~/.ssh/known_hosts 2>/dev/null
echo "kubeconfig 파일 생성 완료"
kubectl cluster-info > /dev/null 2>&1 && echo "Kubernetes 클러스터 연결 성공"
# SSH 연결 테스트
echo "SSH 연결 테스트..."
ssh -o StrictHostKeyChecking=no -p ${K8S_SSH_PORT} ${K8S_SSH_USER}@${K8S_SSH_HOST} "echo 'SSH 연결 성공'"
echo "SSH 키 설정 완료"
# Kubernetes 배포
- name: Deploy to Kubernetes
# k8s 매니페스트 파일을 쿠버네티스 서버로 전송
- name: Transfer k8s manifests
run: |
echo "Kubernetes 배포 시작..."
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
# ConfigMap 적용
echo "ConfigMap 적용..."
kubectl apply -f k8s/vexplor-config.yaml -n ${K8S_NAMESPACE}
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 ${K8S_NAMESPACE}
kubectl apply -f k8s/vexplor-secret.yaml -n vexplor
fi
# Harbor Registry Secret 생성 (없을 때만)
echo "네임스페이스 및 ConfigMap 적용 완료"
DEPLOY_SCRIPT
# 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
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 배포..."
kubectl apply -f k8s/vexplor-backend-deployment.yaml -n ${K8S_NAMESPACE}
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
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 이미지 업데이트..."
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 ${K8S_NAMESPACE} --timeout=5m
kubectl rollout status deployment/${BACKEND_DEPLOYMENT_NAME} -n vexplor --timeout=5m
echo "Backend 배포 완료"
BACKEND_DEPLOY
# Frontend 배포
echo "Frontend 배포..."
kubectl apply -f k8s/vexplor-frontend-deployment.yaml -n ${K8S_NAMESPACE}
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
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 이미지 업데이트..."
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 ${K8S_NAMESPACE} --timeout=5m
kubectl rollout status deployment/${FRONTEND_DEPLOYMENT_NAME} -n vexplor --timeout=5m
echo "Frontend 배포 완료"
FRONTEND_DEPLOY
# Ingress 배포
echo "Ingress 배포..."
kubectl apply -f k8s/vexplor-ingress.yaml -n ${K8S_NAMESPACE}
ssh -p ${K8S_SSH_PORT} ${K8S_SSH_USER}@${K8S_SSH_HOST} "cd ~/vexplor-deploy && kubectl apply -f k8s/vexplor-ingress.yaml -n vexplor"
echo "전체 배포 완료!"
@@ -281,22 +302,24 @@ jobs:
- name: Verify deployment
run: |
echo "배포 검증..."
ssh -p ${K8S_SSH_PORT} ${K8S_SSH_USER}@${K8S_SSH_HOST} << 'VERIFY_SCRIPT'
echo ""
echo "Backend 상태:"
kubectl get deployment ${BACKEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE}
kubectl get pods -l app=${BACKEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE}
kubectl get deployment vexplor-backend -n vexplor
kubectl get pods -l app=vexplor-backend -n vexplor
echo ""
echo "Frontend 상태:"
kubectl get deployment ${FRONTEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE}
kubectl get pods -l app=${FRONTEND_DEPLOYMENT_NAME} -n ${K8S_NAMESPACE}
kubectl get deployment vexplor-frontend -n vexplor
kubectl get pods -l app=vexplor-frontend -n vexplor
echo ""
echo "Services:"
kubectl get svc -n ${K8S_NAMESPACE}
kubectl get svc -n vexplor
echo ""
echo "Ingress:"
kubectl get ingress -n ${K8S_NAMESPACE}
kubectl get ingress -n vexplor
echo ""
echo "검증 완료"
VERIFY_SCRIPT
# 배포 요약
- name: Deployment summary
@@ -315,8 +338,8 @@ jobs:
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
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