Docker Build & Deploy #15
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Docker Build & Deploy | |
| on: | |
| workflow_run: | |
| workflows: ["CI Test (Pre-deployment)"] | |
| types: [completed] | |
| branches: [main] | |
| # 중복 배포 방지 (한 번에 하나만 실행) | |
| concurrency: | |
| group: deploy-production | |
| cancel-in-progress: true | |
| jobs: | |
| build-and-deploy: | |
| name: Docker 빌드 & EC2 배포 | |
| # CI Test 성공 시에만 배포 | |
| if: ${{ github.event.workflow_run.conclusion == 'success' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v3 | |
| - name: GitHub Container Registry 로그인 | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GHCR_PAT }} | |
| - name: Docker 이미지 빌드 & 푸시 | |
| working-directory: ai_server | |
| run: | | |
| IMAGE_NAME=ghcr.io/${{ github.repository_owner }}/onsikgu-ai-server | |
| IMAGE_TAG=${{ github.sha }} | |
| # 빌드 | |
| docker build -t $IMAGE_NAME:$IMAGE_TAG . | |
| docker tag $IMAGE_NAME:$IMAGE_TAG $IMAGE_NAME:latest | |
| # GHCR에 푸시 | |
| docker push $IMAGE_NAME:$IMAGE_TAG | |
| docker push $IMAGE_NAME:latest | |
| - name: EC2 디렉토리 준비 & docker-compose.yml 생성 | |
| uses: appleboy/ssh-action@master | |
| with: | |
| host: ${{ secrets.EC2_HOST }} | |
| username: ubuntu | |
| key: ${{ secrets.EC2_SSH_KEY }} | |
| port: 22 | |
| script: | | |
| # 디렉토리 생성 | |
| mkdir -p ~/onsikgu_ai | |
| mkdir -p ~/onsikgu_data/chroma | |
| # docker-compose.yml 생성 | |
| cat > ~/onsikgu_ai/docker-compose.yml << 'EOF' | |
| version: '3.8' | |
| services: | |
| ai-server: | |
| container_name: onsikgu-ai-server | |
| image: ghcr.io/${{ github.repository_owner }}/onsikgu-ai-server:latest | |
| ports: | |
| - "8000:8000" | |
| volumes: | |
| - ~/onsikgu_data/chroma:/data/chroma | |
| env_file: | |
| - .env | |
| environment: | |
| - CHROMA_PERSIST_DIRECTORY=/data/chroma | |
| restart: unless-stopped | |
| healthcheck: | |
| test: ["CMD", "curl", "-f", "http://localhost:8000/health"] | |
| interval: 30s | |
| timeout: 10s | |
| retries: 3 | |
| start_period: 40s | |
| deploy: | |
| resources: | |
| limits: | |
| memory: 2G | |
| reservations: | |
| memory: 512M | |
| EOF | |
| - name: EC2에서 컨테이너 배포 | |
| uses: appleboy/ssh-action@master | |
| env: | |
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | |
| LANGCHAIN_API_KEY: ${{ secrets.LANGCHAIN_API_KEY }} | |
| LANGCHAIN_PROJECT: ${{ secrets.LANGCHAIN_PROJECT }} | |
| with: | |
| host: ${{ secrets.EC2_HOST }} | |
| username: ubuntu | |
| key: ${{ secrets.EC2_SSH_KEY }} | |
| port: 22 | |
| timeout: 10m | |
| envs: OPENAI_API_KEY,LANGCHAIN_API_KEY,LANGCHAIN_PROJECT | |
| script: | | |
| #!/bin/bash | |
| set -e | |
| echo "==========================================" | |
| echo "🐳 Docker 배포 시작" | |
| echo "시간: $(date)" | |
| echo "==========================================" | |
| # 1. Docker 정리 (디스크 공간 확보) | |
| echo "🧹 Docker 정리 중..." | |
| sudo docker system prune -af --volumes || true | |
| echo " ✅ 정리 완료" | |
| # 2. 작업 디렉토리 | |
| cd ~/onsikgu_ai | |
| # 3. GHCR 로그인 | |
| echo "🔐 GitHub Container Registry 로그인..." | |
| echo "${{ secrets.GHCR_PAT }}" | sudo docker login ghcr.io -u ${{ github.actor }} --password-stdin | |
| # 4. 최신 이미지 Pull | |
| echo "📥 최신 이미지 다운로드 중..." | |
| sudo docker pull ghcr.io/${{ github.repository_owner }}/onsikgu-ai-server:latest | |
| echo " ✅ 이미지 다운로드 완료" | |
| # 5. .env 파일 생성 | |
| echo "📝 환경변수 설정 중..." | |
| cat > .env << EOF | |
| # OpenAI API | |
| OPENAI_API_KEY=${OPENAI_API_KEY} | |
| # Langsmith | |
| LANGCHAIN_TRACING_V2=true | |
| LANGCHAIN_API_KEY=${LANGCHAIN_API_KEY} | |
| LANGCHAIN_PROJECT=${LANGCHAIN_PROJECT} | |
| # ChromaDB | |
| CHROMA_PERSIST_DIRECTORY=/data/chroma | |
| CHROMA_COLLECTION_NAME=qa_history | |
| CHROMA_DATA_PATH=${HOME}/onsikgu_data/chroma | |
| # Server | |
| ENVIRONMENT=production | |
| EOF | |
| echo " ✅ .env 파일 생성 완료" | |
| # 6. Docker 설치 확인 | |
| if ! command -v docker &> /dev/null; then | |
| echo "🐳 Docker 설치 중..." | |
| curl -fsSL https://get.docker.com | sh | |
| sudo usermod -aG docker ubuntu | |
| newgrp docker | |
| fi | |
| # 7. Docker Compose 설치 확인 | |
| if ! command -v docker-compose &> /dev/null; then | |
| echo "🐳 Docker Compose 설치 중..." | |
| sudo curl -L "https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose | |
| sudo chmod +x /usr/local/bin/docker-compose | |
| fi | |
| # 8. 이전 컨테이너 중지 및 정리 | |
| echo "🛑 이전 컨테이너 중지 중..." | |
| sudo docker-compose down || true | |
| # 9. 컨테이너 시작 (빌드 없이 이미지 사용) | |
| echo "🚀 컨테이너 시작 중..." | |
| sudo docker-compose up -d | |
| # 10. Health Check | |
| echo "🏥 Health Check 중..." | |
| sleep 10 | |
| for i in {1..10}; do | |
| if curl -f http://localhost:8000/health > /dev/null 2>&1; then | |
| echo "✅ Health Check 성공!" | |
| break | |
| fi | |
| echo " 시도 $i/10 실패, 5초 후 재시도..." | |
| sleep 5 | |
| done | |
| # 11. 상태 확인 | |
| echo "📊 컨테이너 상태:" | |
| sudo docker-compose ps | |
| echo "==========================================" | |
| echo "✅ 배포 완료!" | |
| echo "==========================================" | |
| - name: 배포 실패 시 알림 | |
| if: failure() | |
| run: | | |
| echo "❌ 배포 실패!" | |
| echo "원인: Docker 빌드 또는 Health Check 실패" |