# Dockerfile - First Garden Static Analysis Service # Python 3.11 기반의 가벼운 이미지 사용 FROM python:3.11-slim-bullseye # 메타데이터 설정 LABEL maintainer="First Garden Team" LABEL description="First Garden Static Analysis - Data Collection & Visitor Forecasting Service" # 작업 디렉토리 설정 WORKDIR /app # 타임존 설정 ENV TZ=Asia/Seoul ENV PYTHONUNBUFFERED=1 ENV PYTHONDONTWRITEBYTECODE=1 # 시스템 패키지 업데이트 및 필수 도구 설치 # mysqldump 및 mysql 클라이언트 추가 (DB 백업/복구 용) RUN apt-get update && apt-get install -y --no-install-recommends \ gcc \ g++ \ build-essential \ libmysqlclient-dev \ libssl-dev \ libffi-dev \ curl \ wget \ git \ cron \ mariadb-client \ && rm -rf /var/lib/apt/lists/* \ && apt-get clean # Python 의존성 설치 COPY requirements.txt ./ RUN pip install --no-cache-dir --upgrade pip setuptools wheel && \ pip install --no-cache-dir -r requirements.txt # 앱 코드 복사 COPY . . # 로그 디렉토리 생성 RUN mkdir -p /app/logs /app/data /app/output /app/uploads /app/dbbackup && \ chmod 755 /app/logs /app/data /app/output /app/uploads /app/dbbackup # 크론 작업 설정: 매일 11시 UTC (서울 시간 20시)에 daily_run.py 실행 RUN echo "0 11 * * * cd /app && python daily_run.py >> /app/logs/daily_run.log 2>&1" > /etc/cron.d/daily-forecast && \ chmod 0644 /etc/cron.d/daily-forecast && \ crontab /etc/cron.d/daily-forecast # 헬스체크 스크립트 생성 RUN cat > /app/healthcheck.sh << 'EOF' #!/bin/bash set -e # DB 연결 확인 python -c " import sys sys.path.insert(0, '/app') from conf import db try: session = db.get_session() session.execute('SELECT 1') session.close() print('DB Connection OK') except Exception as e: print(f'DB Connection Failed: {e}') sys.exit(1) " && exit 0 || exit 1 EOF RUN chmod +x /app/healthcheck.sh # 컨테이너 시작 스크립트 생성 # Flask 웹 서버(포트 8889) + 크론 + 파일 감시 서비스 병렬 실행 RUN cat > /app/docker-entrypoint.sh << 'EOF' #!/bin/bash set -e echo "[$(date +'%Y-%m-%d %H:%M:%S')] =========================================" echo "[$(date +'%Y-%m-%d %H:%M:%S')] Starting First Garden Static Service" echo "[$(date +'%Y-%m-%d %H:%M:%S')] =========================================" # 크론 데몬 시작 (백그라운드) # 일정 시간에 daily_run.py 자동 실행 echo "[$(date +'%Y-%m-%d %H:%M:%S')] Starting cron daemon..." cron -f > /app/logs/cron.log 2>&1 & CRON_PID=$! echo "[$(date +'%Y-%m-%d %H:%M:%S')] Cron daemon started (PID: $CRON_PID)" # file_watch.py 실행 (백그라운드) # 로컬 파일 시스템 감시 및 자동 처리 echo "[$(date +'%Y-%m-%d %H:%M:%S')] Starting file watch service..." cd /app python lib/file_watch.py > /app/logs/file_watch.log 2>&1 & WATCH_PID=$! echo "[$(date +'%Y-%m-%d %H:%M:%S')] File watch service started (PID: $WATCH_PID)" # Flask 웹 서버 시작 (포트 8889) # 파일 업로드, DB 백업/복구 API 제공 echo "[$(date +'%Y-%m-%d %H:%M:%S')] Starting Flask file upload server (port 8889)..." cd /app python -c "from app.app import run_app; run_app()" > /app/logs/flask_app.log 2>&1 & FLASK_PID=$! echo "[$(date +'%Y-%m-%d %H:%M:%S')] Flask server started (PID: $FLASK_PID)" # 신호 처리: 컨테이너 종료 시 모든 하위 프로세스 정리 trap " echo '[$(date +\"%Y-%m-%d %H:%M:%S\")] Shutting down services...' kill $CRON_PID $WATCH_PID $FLASK_PID 2>/dev/null || true exit 0 " SIGTERM SIGINT # 프로세스 모니터링 # 하위 프로세스 상태 확인 echo "[$(date +'%Y-%m-%d %H:%M:%S')] Service monitoring started" while true; do wait done EOF chmod +x /app/docker-entrypoint.sh # 포트 노출 선언 # 8889: Flask 파일 업로드 서버 # 5000: 기타 서비스 포트 EXPOSE 8889 5000 # 엔트리포인트 설정 ENTRYPOINT ["/app/docker-entrypoint.sh"]