Skip to content

Merge remote-tracking branch 'origin/main' into deploy #3

Merge remote-tracking branch 'origin/main' into deploy

Merge remote-tracking branch 'origin/main' into deploy #3

# ===================================================================
# Python FastAPI 전용 CI/CD 배포 워크플로우
# ===================================================================
name: PROJECT-PYTHON-CICD
# ===================================================================
# 📋 필수 GitHub Secrets 설정 가이드
# ===================================================================
#
# ⚠️ 사용하기 전에 반드시 다음 GitHub Secrets를 설정하세요!
# (저장소 Settings > Secrets and variables > Actions에서 설정)
#
# 🔧 필수 Secrets:
# ┌─────────────────────────────┬────────────────────────────────────┐
# │ Secret 이름 │ 설명 │
# ├─────────────────────────────┼────────────────────────────────────┤
# │ DOCKERHUB_USERNAME │ DockerHub 사용자명 │
# │ DOCKERHUB_TOKEN │ DockerHub 액세스 토큰 │
# │ SERVER_HOST │ 배포 대상 서버 IP/도메인 │
# │ SERVER_USER │ 서버 SSH 접속 사용자명 │
# │ SERVER_PASSWORD │ 서버 SSH 접속 비밀번호 │
# │ ENV │ .env 파일 전체 내용 │
# └─────────────────────────────┴────────────────────────────────────┘
#
# 🧪 선택적 Secrets (test 브랜치 사용시에만):
# ┌─────────────────────────────┬────────────────────────────────────┐
# │ PYTHON_TEST_PORT │ test 브랜치 배포 포트 (기본: 8001) │
# └─────────────────────────────┴────────────────────────────────────┘
#
# ===================================================================
# ===================================================================
# 트리거 설정
# ===================================================================
on:
push:
branches:
- deploy # 프로덕션 배포 (필수)
- test # 테스트 환경 배포 (선택사항)
workflow_dispatch: # 수동 실행 허용
# ===================================================================
# 환경 변수 설정
# ===================================================================
env:
# 🔧 프로젝트 설정
PROJECT_NAME: "mapsee-ai"
PROJECT_MAIN_PORT: "8092"
# 🐍 Python 설정
PYTHON_VERSION: "3.13"
jobs:
# ===================================================================
# 빌드 작업
# ===================================================================
build:
name: Python FastAPI 애플리케이션 빌드
runs-on: ubuntu-latest
steps:
# 1. 소스코드 체크아웃
- name: 코드 체크아웃
uses: actions/checkout@v4
# 2. 디스크 공간 확보
- name: 디스크 공간 확보
run: |
echo "📊 빌드 전 디스크 사용량:"
df -h
echo "🧹 불필요한 파일 정리 중..."
sudo rm -rf /usr/share/dotnet || true
sudo rm -rf /opt/ghc || true
sudo rm -rf /usr/local/share/boost || true
sudo rm -rf "$AGENT_TOOLSDIRECTORY" || true
echo "🐳 Docker 시스템 정리 중..."
docker system prune -af --volumes || true
echo "📊 정리 후 디스크 사용량:"
df -h
# 3. .env 파일 생성
- name: .env 파일 생성
run: |
cat > .env << 'EOF'
${{ secrets.ENV }}
EOF
echo "✅ .env 파일이 생성되었습니다"
# 4. Docker 빌드 환경 설정
- name: Docker 빌드환경 설정
uses: docker/setup-buildx-action@v3
# 5. DockerHub 로그인
- name: DockerHub 로그인
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# 6. Docker 이미지 빌드 및 푸시
- name: Docker 이미지 빌드 및 푸시
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.PROJECT_NAME }}:${{ github.ref_name }}
# GitHub Actions 캐시 사용 (로컬 디스크 공간 절약)
cache-from: type=gha
cache-to: type=gha,mode=max
# 7. 빌드 후 정리
- name: 빌드 후 정리
if: always()
run: |
echo "🧹 빌드 후 정리 중..."
docker system prune -f || true
echo "📊 최종 디스크 사용량:"
df -h
# ===================================================================
# 배포 작업
# ===================================================================
deploy:
name: 원격 서버 배포
needs: build
runs-on: ubuntu-latest
steps:
# SSH를 통한 원격 서버 배포 실행
- name: Deploy
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
password: ${{ secrets.SERVER_PASSWORD }}
port: 2022
command_timeout: 600s # 명령 실행 타임아웃 10분
timeout: 60s # SSH 연결 타임아웃 60초
script: |
set -e
# ============================================================
# 배포 환경 변수 설정
# ============================================================
echo "🔧 환경변수 설정.."
export PATH=$PATH:/usr/local/bin
export PW=${{ secrets.SERVER_PASSWORD }}
# GitHub에서 전달받은 브랜치명
BRANCH=${{ github.ref_name }}
# 프로젝트 설정
PROJECT_NAME="${{ env.PROJECT_NAME }}"
# ============================================================
# 브랜치별 포트 및 컨테이너명 설정
# ============================================================
# 기본값 설정
PORT=8000
CONTAINER_NAME="${PROJECT_NAME}"
# 브랜치에 따른 환경별 설정
if [ "$BRANCH" == "main" ] || [ "$BRANCH" == "deploy" ]; then
# 🏭 프로덕션 환경 (main/deploy 브랜치)
PORT=${{ env.PROJECT_MAIN_PORT }}
CONTAINER_NAME="${PROJECT_NAME}"
echo "🏭 프로덕션 환경으로 배포합니다"
elif [ "$BRANCH" == "test" ]; then
# 🧪 테스트 환경 (test 브랜치)
PORT=${{ secrets.PYTHON_TEST_PORT}}
CONTAINER_NAME="${PROJECT_NAME}-test"
echo "🧪 테스트 환경으로 배포합니다"
else
# ⚠️ 기타 브랜치
echo "⚠️ 지원하지 않는 브랜치입니다: $BRANCH"
exit 1
fi
# 설정 정보 출력
echo "📋 배포 설정 정보:"
echo " - 브랜치: $BRANCH"
echo " - 프로젝트: $PROJECT_NAME"
echo " - 컨테이너 이름: $CONTAINER_NAME"
echo " - 포트: $PORT"
echo " - Docker 이미지: ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}"
# ============================================================
# Docker 이미지 풀 (Pull)
# ============================================================
echo "⬇️ Docker 이미지 풀: ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}"
echo $PW | sudo -S docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}
# ============================================================
# 기존 컨테이너 정리
# ============================================================
echo "🧹 컨테이너 $CONTAINER_NAME 존재 여부 확인 중..."
# 동일한 이름의 컨테이너가 존재하는지 확인
if echo $PW | sudo -S docker ps -a --format '{{.Names}}' | grep -Eq "^${CONTAINER_NAME}\$"; then
echo "⚠️ 컨테이너 $CONTAINER_NAME 이(가) 존재합니다. 중지 및 삭제 중..."
echo $PW | sudo -S docker rm -f $CONTAINER_NAME
echo "✅ 컨테이너 $CONTAINER_NAME 이(가) 삭제되었습니다."
else
echo "ℹ️ 존재하는 컨테이너 $CONTAINER_NAME 이(가) 없습니다."
fi
# ============================================================
# 새 컨테이너 실행
# ============================================================
echo "🚀 새로운 컨테이너 $CONTAINER_NAME 실행 중..."
# Docker 컨테이너 실행
# - 포트 매핑: ${PORT}:8000 (외부포트:내부포트)
# - 시간대: Asia/Seoul
# - 볼륨 마운트: 로컬 시간 동기화 및 프로젝트 데이터
# ⚠️ .env 파일은 이미 Docker 이미지에 포함되어 있습니다
echo $PW | sudo -S docker run -d \
-p ${PORT}:8000 \
--name $CONTAINER_NAME \
-e TZ=Asia/Seoul \
-v /etc/localtime:/etc/localtime:ro \
-v /volume1/projects/mapsee/ai:/mnt/mapsee \
${{ secrets.DOCKERHUB_USERNAME }}/${PROJECT_NAME}:${BRANCH}
# ============================================================
# 컨테이너 헬스체크
# ============================================================
echo "⏳ 컨테이너 초기화 대기 중... (10초)"
sleep 10
echo "🏥 컨테이너 헬스체크 중..."
if echo $PW | sudo -S docker ps --format '{{.Names}}' | grep -Eq "^${CONTAINER_NAME}\$"; then
echo "✅ 컨테이너 $CONTAINER_NAME 이(가) 정상적으로 실행 중입니다"
else
echo "❌ 컨테이너 $CONTAINER_NAME 실행 실패"
echo "📋 컨테이너 로그:"
echo $PW | sudo -S docker logs $CONTAINER_NAME || true
exit 1
fi
# ============================================================
# 배포 완료 확인
# ============================================================
echo "✅ 배포가 성공적으로 완료되었습니다!"
echo ""
echo "📋 배포 결과 요약:"
echo " 🎯 프로젝트: $PROJECT_NAME"
echo " 🌿 브랜치: $BRANCH"
echo " 🐳 컨테이너: $CONTAINER_NAME"
echo " 🌐 포트: $PORT"
echo " ⏰ 배포 시간: $(date '+%Y-%m-%d %H:%M:%S')"
echo ""
echo "🔗 접속 URL: http://${{ secrets.SERVER_HOST }}:${PORT}/docs"