diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index c877b2c..896921e 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -22,43 +22,43 @@ jobs: GITHUB_ACTIONS: true steps: - - name: 코드 체크아웃 - uses: actions/checkout@v4 - - - name: Python 환경 설정 - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: 의존성 캐시 - uses: actions/cache@v4 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - - name: 의존성 설치 - run: | - python -m pip install --upgrade pip - # 먼저 테스트 도구들 설치 (pytest-env 추가) - pip install pytest==8.3.4 pytest-asyncio==0.25.0 pytest-env==1.1.5 flake8==7.1.1 black==25.1.0 isort==5.13.2 - # 그 다음 프로젝트 의존성 설치 - pip install -r requirements.txt - - - name: 코드 품질 검사 - run: | - # 중요한 구문 오류만 체크 - flake8 app/ --count --select=E9,F63,F7,F82 --show-source --statistics --exit-zero - echo "코드 품질 검사 완료" - - - name: 테스트 실행 - run: | - export APP_NAME="Ururu AI Recommendation System" - export EMBEDDING_MODEL_NAME="sentence-transformers/all-MiniLM-L6-v2" - export EMBEDDING_DIMENSION="384" - python -m pytest tests/ -v --tb=short - continue-on-error: false + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Setup Python Environment + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Cache Dependencies + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + # Install test tools first (including pytest-env) + pip install pytest==8.3.4 pytest-asyncio==0.25.0 pytest-env==1.1.5 flake8==7.1.1 black==25.1.0 isort==5.13.2 + # Then install project dependencies + pip install -r requirements.txt + + - name: Code Quality Check + run: | + # Check only critical syntax errors + flake8 app/ --count --select=E9,F63,F7,F82 --show-source --statistics + echo "Code quality check completed" + + - name: Run Tests + run: | + export APP_NAME="Ururu AI Recommendation System" + export EMBEDDING_MODEL_NAME="sentence-transformers/all-MiniLM-L6-v2" + export EMBEDDING_DIMENSION="384" + python -m pytest tests/ -v --tb=short + continue-on-error: false build-and-push: needs: test @@ -66,40 +66,40 @@ jobs: if: github.event_name == 'push' steps: - - name: 코드 체크아웃 - uses: actions/checkout@v4 - - - name: Docker Buildx 설정 - uses: docker/setup-buildx-action@v3 - - - name: 컨테이너 레지스트리 로그인 - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ secrets.GHCR_USERNAME }} - password: ${{ secrets.GHCR_TOKEN }} - - - name: 메타데이터 추출 - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=ref,event=branch - type=ref,event=pr - type=sha,prefix=sha- - type=raw,value=latest,enable={{is_default_branch}} - - - name: Docker 이미지 빌드 및 푸시 - uses: docker/build-push-action@v5 - with: - context: . - file: ./Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.GHCR_USERNAME }} + password: ${{ secrets.GHCR_TOKEN }} + + - name: Extract Metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=sha,prefix=sha- + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and Push Docker Image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max deploy-development: needs: build-and-push @@ -108,28 +108,49 @@ jobs: environment: development steps: - - name: 코드 체크아웃 - uses: actions/checkout@v4 - - - name: 개발 환경 배포 설정 - run: | - printf 'SPRING_BOOT_BASE_URL=%s\n' "${{ secrets.DEV_SPRING_BACKEND_URL }}" >> .env.development - printf 'REDIS_URL=%s\n' "${{ secrets.DEV_REDIS_URL }}" >> .env.development - - - name: Docker Compose 설정 검증 - run: | - echo "개발 환경 설정 파일 검증" - echo "docker-compose.development.yml 구문 검증" - docker compose -f docker-compose.development.yml config --quiet - echo "개발 환경 배포 준비 완료" - - - name: 배포 시뮬레이션 (실제 EC2 배포 없음) - run: | - echo "개발 환경 배포 시뮬레이션" - echo "- Docker 이미지: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:develop" - echo "- Spring Boot URL: [MASKED]" - echo "- Redis URL: [MASKED]" - echo "개발 환경 배포 설정 완료" + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Checkout Config Repository + uses: actions/checkout@v4 + with: + repository: UruruLab/Ururu-AI-Config + path: config + token: ${{ secrets.PRIVATE_REPO_TOKEN }} + + - name: Copy Development Environment Config Files + run: | + if compgen -G "config/.env*" > /dev/null; then + if [ -f "config/.env.development" ]; then + cp config/.env.development .env.development + echo "✅ Development environment config files copied successfully" + else + echo "❌ .env.development not found in config repository" + exit 1 + fi + else + echo "❌ No config files found in config repository" + exit 1 + fi + + - name: Validate Docker Compose Configuration + run: | + echo "Validating development environment configuration files" + echo "Validating docker-compose.development.yml syntax" + ENVIRONMENT=development docker compose -f docker-compose.development.yml config --quiet + echo "Verifying environment variable bindings" + ENVIRONMENT=development docker compose -f docker-compose.development.yml config \ + | grep -A 10 "environment:" \ + | grep "^[[:space:]]*[[:alpha:]]" \ + | sed 's/.*$/&/' || true + echo "Development environment deployment preparation completed" + + - name: Simulate Deployment (No actual EC2 deployment) + run: | + echo "Development environment deployment simulation" + echo "- Docker Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:develop" + echo "- Config File: .env.development (fetched from Config repository)" + echo "Development environment deployment configuration completed" deploy-production: needs: build-and-push @@ -138,32 +159,53 @@ jobs: environment: production steps: - - name: 코드 체크아웃 - uses: actions/checkout@v4 - - - name: 운영 환경 배포 설정 - run: | - printf 'SPRING_BOOT_BASE_URL=%s\n' "${{ secrets.PROD_SPRING_BACKEND_URL }}" >> .env.production - printf 'REDIS_URL=%s\n' "${{ secrets.PROD_REDIS_URL }}" >> .env.production - - - name: Docker Compose 설정 검증 - run: | - echo "운영 환경 설정 파일 검증" - echo "docker-compose.production.yml 구문 검증" - docker compose -f docker-compose.production.yml config --quiet - echo "운영 환경 배포 준비 완료" - - - name: 배포 알림 준비 - run: | - echo "운영 환경 배포 준비 완료" - echo "- Docker 이미지: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" - echo "- Spring Boot URL: [MASKED]" - echo "- Redis URL: [MASKED]" - echo "실제 EC2 배포는 별도 프로세스에서 진행" + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Checkout Config Repository + uses: actions/checkout@v4 + with: + repository: UruruLab/Ururu-AI-Config + path: config + token: ${{ secrets.PRIVATE_REPO_TOKEN }} + + - name: Copy Production Environment Config Files + run: | + if compgen -G "config/.env*" > /dev/null; then + if [ -f "config/.env.production" ]; then + cp config/.env.production .env.production + echo "✅ Production environment config files copied successfully" + else + echo "❌ .env.production not found in config repository" + exit 1 + fi + else + echo "❌ No config files found in config repository" + exit 1 + fi - - name: 배포 완료 알림 - if: success() - run: | - echo "GitHub Actions 배포 파이프라인이 성공적으로 완료되었습니다." - echo "Docker 이미지가 GitHub Container Registry에 푸시되었습니다." - echo "EC2 서버에서 수동으로 docker compose pull && docker compose up -d 실행이 필요합니다." + - name: Validate Docker Compose Configuration + run: | + echo "Validating production environment configuration files" + echo "Validating docker-compose.production.yml syntax" + ENVIRONMENT=production docker compose -f docker-compose.production.yml config --quiet + echo "Verifying environment variable bindings" + ENVIRONMENT=production docker compose -f docker-compose.production.yml config \ + | grep -A 10 "environment:" \ + | grep "^[[:space:]]*[[:alpha:]]" \ + | sed 's/.*$/&/' || true + echo "Production environment deployment preparation completed" + + - name: Prepare Deployment Notification + run: | + echo "Production environment deployment preparation completed" + echo "- Docker Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" + echo "- Config File: .env.production (fetched from Config repository)" + echo "Actual EC2 deployment will be handled by separate process" + + - name: Deployment Completion Notification + if: success() + run: | + echo "GitHub Actions deployment pipeline completed successfully." + echo "Docker image has been pushed to GitHub Container Registry." + echo "Manual execution required on EC2 server: docker compose pull && docker compose up -d" diff --git a/.github/workflows/docker-health-check.yml b/.github/workflows/docker-health-check.yml index c0c29f0..3164eac 100644 --- a/.github/workflows/docker-health-check.yml +++ b/.github/workflows/docker-health-check.yml @@ -4,44 +4,106 @@ on: schedule: - cron: '0 */6 * * *' workflow_dispatch: + push: + branches: + - main + - 'fix/*' + pull_request: + branches: + - main + - 'fix/*' jobs: health-check: runs-on: ubuntu-latest steps: - - name: 코드 체크아웃 - uses: actions/checkout@v4 - - - name: Docker Compose 설정 검증 - run: | - echo "✅ Docker Compose 파일 구문 검증" - docker compose config --quiet - echo "✅ 개발환경 설정 검증" - docker compose -f docker-compose.development.yml config --quiet - echo "✅ 운영환경 설정 검증" - docker compose -f docker-compose.production.yml config --quiet - - - name: 헬스체크 시뮬레이션 - run: | - echo "🔍 AI 서비스 헬스체크 시뮬레이션" - echo "- 체크 대상: http://localhost:8000/health" - echo "- 예상 응답: {\"status\": \"healthy\", \"service\": \"ururu-ai-recommendation\"}" - - echo "🔍 Spring Backend 연결 테스트 시뮬레이션" - echo "- 체크 대상: http://localhost:8080/health" - echo "- 실제 연결은 EC2 환경에서만 가능" - - - name: GitHub Container Registry 이미지 확인 - run: | - echo "📦 최신 Docker 이미지 확인" - echo "- Registry: ghcr.io/${{ github.repository }}" - echo "- 최신 태그: latest, main, develop" - - - name: 헬스체크 보고서 - run: | - echo "📊 헬스체크 완료 보고서" - echo "✅ Docker Compose 설정 파일 정상" - echo "✅ 워크플로우 설정 정상" - echo "⚠️ 실제 서비스 상태는 EC2에서 별도 확인 필요" - echo "💡 EC2에서 실행: docker compose ps && docker compose logs" + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Checkout Config Repository + uses: actions/checkout@v4 + with: + repository: UruruLab/Ururu-AI-Config + path: config + token: ${{ secrets.PRIVATE_REPO_TOKEN }} + + - name: Copy Config Files (.env files) + run: | + mkdir -p ./ + if compgen -G "config/.env*" > /dev/null; then + cp config/.env* ./ + echo "✅ Config files copied successfully" + else + echo "❌ Config files not found in config repository" + exit 1 + fi + + - name: Verify Environment Files + run: | + echo "📁 Checking copied environment files" + ls -la .env* + if [ -f ".env.development" ]; then + echo "✅ .env.development file exists" + else + echo "❌ .env.development file missing" + exit 1 + fi + if [ -f ".env.production" ]; then + echo "✅ .env.production file exists" + else + echo "❌ .env.production file missing" + exit 1 + fi + + - name: Validate Docker Compose Configuration + run: | + echo "✅ Validating Docker Compose file syntax" + docker compose config --quiet + echo "✅ Validating development environment (using copied config files)" + ENVIRONMENT=development docker compose -f docker-compose.development.yml config --quiet + echo "✅ Validating production environment (using copied config files)" + ENVIRONMENT=production docker compose -f docker-compose.production.yml config --quiet + + - name: Verify Environment Variable Bindings + run: | + echo "🔍 Verifying environment variable bindings" + echo "Development environment key variables:" + ENVIRONMENT=development docker compose -f docker-compose.development.yml config \ + | grep -A 20 "environment:" \ + | grep "^[[:space:]]*[[:alpha:]]" \ + | sed 's/.*$/&/' \ + | head -10 + echo "" + echo "Production environment key variables:" + ENVIRONMENT=production docker compose -f docker-compose.production.yml config \ + | grep -A 20 "environment:" \ + | grep "^[[:space:]]*[[:alpha:]]" \ + | sed 's/.*$/&/' \ + | head -10 + + - name: Simulate Health Check + run: | + echo "🔍 AI Service Health Check Simulation" + echo "- Target: http://localhost:8000/health" + echo "- Expected Response: {\"status\": \"healthy\", \"service\": \"ururu-ai-recommendation\"}" + + echo "🔍 Spring Backend Connection Test Simulation" + echo "- Target: http://localhost:8080/health" + echo "- Actual connection only available in EC2 environment" + + - name: Check GitHub Container Registry Images + run: | + echo "📦 Checking latest Docker images" + echo "- Registry: ghcr.io/${{ github.repository }}" + echo "- Latest tags: latest, main, develop" + + - name: Generate Health Check Report + run: | + echo "📊 Health Check Completion Report" + echo "✅ Docker Compose configuration files validated" + echo "✅ Config repository integration working" + echo "✅ Environment-specific configuration files verified" + echo "✅ Workflow configuration validated" + echo "️ Actual service status needs separate verification on EC2" + echo "Run on EC2: docker compose ps && docker compose logs" diff --git a/.github/workflows/performance-test.yml b/.github/workflows/performance-test.yml index 7c5a178..1f56844 100644 --- a/.github/workflows/performance-test.yml +++ b/.github/workflows/performance-test.yml @@ -4,12 +4,12 @@ on: workflow_dispatch: inputs: test_duration: - description: '테스트 실행 시간 (초)' + description: 'Test execution time (seconds)' required: true default: '60' type: string concurrent_users: - description: '동시 사용자 수' + description: 'Number of concurrent users' required: true default: '5' type: string @@ -19,151 +19,151 @@ jobs: runs-on: ubuntu-latest steps: - - name: 코드 체크아웃 - uses: actions/checkout@v4 - - - name: Python 환경 설정 - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: 성능 테스트 도구 설치 - run: | - pip install locust==2.31.0 requests==2.32.3 fastapi==0.111.0 uvicorn==0.30.0 - - - name: 테스트용 FastAPI 서버 시작 - run: | - # 간단한 테스트 서버 생성 - cat > test_server.py << 'EOF' - from fastapi import FastAPI - import uvicorn - import asyncio - - app = FastAPI(title="Test Ururu AI Server") - - @app.get("/health") - async def health_check(): - return {"status": "healthy", "service": "ururu-ai-test"} - - @app.post("/api/v1/recommendations") - async def mock_recommendations(): - await asyncio.sleep(0.1) # 실제 AI 처리 시간 시뮬레이션 - return { - "recommendations": [ - {"product_id": 1, "score": 0.95, "name": "테스트 상품 1"}, - {"product_id": 2, "score": 0.89, "name": "테스트 상품 2"} - ], - "total_count": 2, - "processing_time_ms": 100 - } - EOF - - # 백그라운드에서 서버 실행 - python -c " - import uvicorn - import sys - sys.path.append('.') - uvicorn.run('test_server:app', host='0.0.0.0', port=8000, log_level='warning') - " & - - # 서버 시작 대기 - sleep 10 - - - name: 서버 준비 상태 확인 - run: | - for i in {1..30}; do - if curl -f http://localhost:8000/health; then - echo "✅ 테스트 서버가 준비되었습니다." - break + - name: 코드 체크아웃 + uses: actions/checkout@v4 + + - name: Python 환경 설정 + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: 성능 테스트 도구 설치 + run: | + pip install locust==2.31.0 requests==2.32.3 fastapi==0.111.0 uvicorn==0.30.0 + + - name: 테스트용 FastAPI 서버 시작 + run: | + # 간단한 테스트 서버 생성 + cat > test_server.py << 'EOF' + from fastapi import FastAPI + import uvicorn + import asyncio + + app = FastAPI(title="Test Ururu AI Server") + + @app.get("/health") + async def health_check(): + return {"status": "healthy", "service": "ururu-ai-test"} + + @app.post("/api/v1/recommendations") + async def mock_recommendations(): + await asyncio.sleep(0.1) # 실제 AI 처리 시간 시뮬레이션 + return { + "recommendations": [ + {"product_id": 1, "score": 0.95, "name": "테스트 상품 1"}, + {"product_id": 2, "score": 0.89, "name": "테스트 상품 2"} + ], + "total_count": 2, + "processing_time_ms": 100 + } + EOF + + # 백그라운드에서 서버 실행 + python -c " + import uvicorn + import sys + sys.path.append('.') + uvicorn.run('test_server:app', host='0.0.0.0', port=8000, log_level='warning') + " & + + # 서버 시작 대기 + sleep 10 + + - name: 서버 준비 상태 확인 + run: | + for i in {1..30}; do + if curl -f http://localhost:8000/health; then + echo "✅ 테스트 서버가 준비되었습니다." + break + fi + echo "테스트 서버 시작을 기다리는 중... ($i/30)" + sleep 2 + done + + - name: Create Locust Performance Test File + run: | + cat > locustfile.py << 'EOF' + from locust import HttpUser, task, between + import json + + class UruruAITestUser(HttpUser): + wait_time = between(1, 3) + + def on_start(self): + self.client.verify = False + + @task(3) + def get_recommendations(self): + payload = { + "user_diagnosis": "I have dry skin and lack moisture", + "top_k": 10, + "max_price": 50000 + } + + with self.client.post( + "/api/v1/recommendations", + json=payload, + headers={"Content-Type": "application/json"}, + catch_response=True + ) as response: + if response.status_code == 200: + response.success() + else: + response.failure(f"Recommendation API failed: {response.status_code}") + + @task(1) + def health_check(self): + with self.client.get("/health", catch_response=True) as response: + if response.status_code == 200: + response.success() + else: + response.failure(f"Health check failed: {response.status_code}") + EOF + + - name: Run Performance Test + run: | + echo "🚀 Starting performance test (Users: ${{ github.event.inputs.concurrent_users }}, Time: ${{ github.event.inputs.test_duration }}s)" + locust \ + --host=http://localhost:8000 \ + --users=${{ github.event.inputs.concurrent_users }} \ + --spawn-rate=1 \ + --run-time=${{ github.event.inputs.test_duration }}s \ + --headless \ + --csv=performance_results \ + --html=performance_report.html || echo "Performance test completed" + + - name: Analyze Performance Test Results + run: | + echo "=== Performance Test Results Summary ===" + if [ -f performance_results_stats.csv ]; then + echo "📊 Request Statistics:" + cat performance_results_stats.csv | head -5 + echo "" + echo "❌ Failure Statistics:" + cat performance_results_failures.csv 2>/dev/null || echo "No failures" + else + echo "⚠️ Performance test result files not found." fi - echo "테스트 서버 시작을 기다리는 중... ($i/30)" - sleep 2 - done - - - name: Locust 성능 테스트 파일 생성 - run: | - cat > locustfile.py << 'EOF' - from locust import HttpUser, task, between - import json - - class UruruAITestUser(HttpUser): - wait_time = between(1, 3) - - def on_start(self): - self.client.verify = False - - @task(3) - def get_recommendations(self): - payload = { - "user_diagnosis": "건성 피부로 수분이 부족해요", - "top_k": 10, - "max_price": 50000 - } - - with self.client.post( - "/api/v1/recommendations", - json=payload, - headers={"Content-Type": "application/json"}, - catch_response=True - ) as response: - if response.status_code == 200: - response.success() - else: - response.failure(f"추천 API 실패: {response.status_code}") - - @task(1) - def health_check(self): - with self.client.get("/health", catch_response=True) as response: - if response.status_code == 200: - response.success() - else: - response.failure(f"헬스체크 실패: {response.status_code}") - EOF - - - name: 성능 테스트 실행 - run: | - echo "🚀 성능 테스트 시작 (사용자: ${{ github.event.inputs.concurrent_users }}, 시간: ${{ github.event.inputs.test_duration }}초)" - locust \ - --host=http://localhost:8000 \ - --users=${{ github.event.inputs.concurrent_users }} \ - --spawn-rate=1 \ - --run-time=${{ github.event.inputs.test_duration }}s \ - --headless \ - --csv=performance_results \ - --html=performance_report.html || echo "성능 테스트 완료" - - name: 성능 테스트 결과 분석 - run: | - echo "=== 성능 테스트 결과 요약 ===" - if [ -f performance_results_stats.csv ]; then - echo "📊 요청 통계:" - cat performance_results_stats.csv | head -5 echo "" - echo "❌ 실패 통계:" - cat performance_results_failures.csv 2>/dev/null || echo "실패 없음" - else - echo "⚠️ 성능 테스트 결과 파일을 찾을 수 없습니다." - fi - - echo "" - echo "=== 테스트 환경 정보 ===" - echo "- 동시 사용자 수: ${{ github.event.inputs.concurrent_users }}" - echo "- 테스트 시간: ${{ github.event.inputs.test_duration }}초" - echo "- 서버 환경: GitHub Actions (ubuntu-latest)" - echo "- 테스트 대상: Mock FastAPI 서버" - - - name: 결과 파일 업로드 - uses: actions/upload-artifact@v4 - if: always() - with: - name: performance-test-results-${{ github.run_number }} - path: | - performance_results*.csv - performance_report.html - - - name: 테스트 완료 정리 - if: always() - run: | - echo "🧹 테스트 환경 정리" - pkill -f "uvicorn" || echo "서버 프로세스 정리 완료" - echo "✅ 성능 테스트가 완료되었습니다!" + echo "=== Test Environment Information ===" + echo "- Concurrent Users: ${{ github.event.inputs.concurrent_users }}" + echo "- Test Duration: ${{ github.event.inputs.test_duration }}s" + echo "- Server Environment: GitHub Actions (ubuntu-latest)" + echo "- Test Target: Mock FastAPI Server" + + - name: Upload Result Files + uses: actions/upload-artifact@v4 + if: always() + with: + name: performance-test-results-${{ github.run_number }} + path: | + performance_results*.csv + performance_report.html + + - name: Cleanup Test Environment + if: always() + run: | + echo "🧹 Cleaning up test environment" + pkill -f "uvicorn" || echo "Server process cleanup completed" + echo "✅ Performance test completed!" diff --git a/docker-compose.development.yml b/docker-compose.development.yml index 8a5df5c..678109a 100644 --- a/docker-compose.development.yml +++ b/docker-compose.development.yml @@ -1,12 +1,15 @@ -version: '3.8' - services: ururu-ai: build: target: development environment: - - DEBUG=true - - LOG_LEVEL=DEBUG + - ENVIRONMENT=development + - REDIS_HOST=redis # 개발환경에서는 Redis 컨테이너와 연결 + - REDIS_URL=redis://redis:6379 + - SPRING_BOOT_INTEGRATION_ENABLED=false # 개발환경에서는 Spring Boot 연동 비활성화 + - USE_MOCK_DATA=true # Mock 데이터 사용 + env_file: + - .env.development volumes: - .:/app # 컨테이너 내부 venv 디렉토리 보호 @@ -15,6 +18,16 @@ services: # 개발환경에서만 디버깅용 포트 노출 (선택적) ports: - "${AI_PORT:-8001}:8000" # 개발용으로만 8001 포트 노출 + networks: + - ururu-network + depends_on: + - redis + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s # 개발용 Redis (캐싱 및 세션 저장용) redis: @@ -28,6 +41,11 @@ services: networks: - ururu-network +networks: + ururu-network: + driver: bridge + name: ururu-network + volumes: redis_data: driver: local diff --git a/docker-compose.production.yml b/docker-compose.production.yml index 2e092ed..bcf705b 100644 --- a/docker-compose.production.yml +++ b/docker-compose.production.yml @@ -1,17 +1,23 @@ -version: '3.8' - services: ururu-ai: build: target: production environment: - - DEBUG=false - - LOG_LEVEL=INFO - # 운영환경에서는 Spring Boot 서버 IP/도메인으로 설정 - - SPRING_BOOT_BASE_URL=${SPRING_BOOT_BASE_URL:-http://api.ururu.shop} - - GUNICORN_WORKERS=${GUNICORN_WORKERS:-4} + - ENVIRONMENT=production + - SPRING_BOOT_INTEGRATION_ENABLED=true # 운영환경에서는 Spring Boot 연동 필수 + - USE_MOCK_DATA=false # 실제 데이터 사용 + env_file: + - .env.production ports: - "${AI_PORT:-8000}:8000" # Spring Boot 서버에서 접근 가능 + networks: + - ururu-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s deploy: replicas: 2 resources: @@ -39,4 +45,5 @@ services: networks: ururu-network: - driver: bridge \ No newline at end of file + driver: bridge + name: ururu-network \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 85a5a50..aaa8360 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: # Private Config 가져오기 서비스 config-fetcher: @@ -10,16 +8,22 @@ services: environment: - GITHUB_TOKEN=${GITHUB_TOKEN} - CONFIG_REPO_URL=https://github.com/UruruLab/Ururu-AI-Config.git - - ENVIRONMENT=${ENVIRONMENT:-development} + - ENVIRONMENT=${ENVIRONMENT:-production} command: /scripts/fetch-config.sh restart: "no" + healthcheck: + test: ["CMD", "test", "-f", "/config/.env.${ENVIRONMENT:-production}"] + interval: 10s + timeout: 5s + retries: 3 + start_period: 30s # FastAPI AI 추천 서비스 (Spring Boot 서버와 통신) ururu-ai: build: context: . dockerfile: Dockerfile - target: ${BUILD_TARGET:-development} + target: ${BUILD_TARGET:-production} container_name: ururu-ai-service ports: - "${AI_PORT:-8000}:8000" # Spring Boot 서버에서 접근용 @@ -27,16 +31,11 @@ services: - ./logs:/app/logs - ./config:/app/config:ro environment: - - ENVIRONMENT=${ENVIRONMENT:-development} - - DEBUG=${DEBUG:-true} - - LOG_LEVEL=${LOG_LEVEL:-INFO} + - ENVIRONMENT=${ENVIRONMENT:-production} + # 컨테이너에서 호스트의 Spring Boot에 접근하기 위한 설정 - SPRING_BOOT_BASE_URL=${SPRING_BOOT_BASE_URL:-http://host.docker.internal:8080} - - HTTP_TIMEOUT=${HTTP_TIMEOUT:-30} - - HTTP_RETRY_COUNT=${HTTP_RETRY_COUNT:-3} - - HTTP_RETRY_DELAY=${HTTP_RETRY_DELAY:-1} - - GUNICORN_WORKERS=${GUNICORN_WORKERS:-4} env_file: - - ./config/.env.${ENVIRONMENT:-development} + - ./config/.env.${ENVIRONMENT:-production} depends_on: config-fetcher: condition: service_healthy @@ -50,7 +49,7 @@ services: networks: - ururu-network extra_hosts: - - "host.docker.internal:host-gateway" + - "host.docker.internal:host-gateway" # Docker Desktop에서 호스트 접근 가능 logging: driver: "json-file" options: diff --git a/scripts/run-dev.sh b/scripts/run-dev.sh new file mode 100644 index 0000000..f7b07ae --- /dev/null +++ b/scripts/run-dev.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +echo "🚀 개발환경에서 Ururu AI 서비스 시작" +echo "환경: Development" +echo "Spring Boot 연동: 비활성화" +echo "데이터: Mock 데이터 사용" + +export ENVIRONMENT=development +export BUILD_TARGET=development + +# 환경 파일 존재 확인 +if [ ! -f ".env.development" ]; then + echo "❌ .env.development 파일을 찾을 수 없습니다." + echo "💡 Config 레포지토리에서 환경 파일을 가져와주세요." + exit 1 +fi + +docker compose -f docker-compose.development.yml up --build + +echo "✅ 개발환경 서비스가 시작되었습니다." +echo "🌐 AI 서비스 접근: http://localhost:8001" +echo "📚 API 문서: http://localhost:8001/docs" diff --git a/scripts/run-prod.sh b/scripts/run-prod.sh new file mode 100644 index 0000000..0ab555e --- /dev/null +++ b/scripts/run-prod.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +echo "🚀 운영환경에서 Ururu AI 서비스 시작" +echo "환경: Production" +echo "Spring Boot 연동: 활성화" +echo "데이터: 실제 데이터베이스 사용" + +export ENVIRONMENT=production +export BUILD_TARGET=production + +# 환경 파일 존재 확인 +if [ ! -f ".env.production" ]; then + echo "❌ .env.production 파일을 찾을 수 없습니다." + echo "💡 Config 레포지토리에서 환경 파일을 가져와주세요." + exit 1 +fi + +# Spring Boot 연결 확인 +echo "🔍 Spring Boot 서버 연결 확인 중..." +if curl -f --connect-timeout 5 http://localhost:8080/health 2>/dev/null; then + echo "✅ Spring Boot 서버 연결 확인됨" +else + echo "⚠️ Spring Boot 서버에 연결할 수 없습니다." + echo " Docker 환경에서는 host.docker.internal:8080으로 연결을 시도합니다." +fi + +docker compose up --build + +echo "✅ 운영환경 서비스가 시작되었습니다." +echo "🌐 AI 서비스 접근: http://localhost:8000" +echo "📚 API 문서: http://localhost:8000/docs" +echo "🔗 Spring Boot 연동: 활성화됨"