From 24939ab7a7d40408db6384ebf08060c6be202544 Mon Sep 17 00:00:00 2001 From: KWON Date: Wed, 31 Dec 2025 11:16:59 +0900 Subject: [PATCH] feat: add Docker support with private registry - Add Dockerfile with vim, Korean locale, visual mode disabled - Add docker-compose.yml with build/push support for reg.firstgarden.co.kr - Add docker-entrypoint.sh for multi-service support - Add .dockerignore - Update README.md with Docker deployment guide - Consolidate SERVICE_KEY into DATA_API_SERVICE_KEY --- .dockerignore | 55 ++++++++++++++ Dockerfile | 72 ++++++++++++++++++ README.md | 175 ++++++++++++++++++++++++++++++++++++++++++- core/config.py | 4 +- docker-compose.yml | 102 +++++++++++++++++++++++++ docker-entrypoint.sh | 52 +++++++++++++ 6 files changed, 457 insertions(+), 3 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 docker-entrypoint.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..eb16af1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,55 @@ +# Git +.git +.gitignore + +# Python +__pycache__ +*.py[cod] +*$py.class +*.so +.Python +*.egg-info +.eggs +*.egg +.pytest_cache +.coverage +htmlcov + +# 가상환경 +venv/ +.venv/ +ENV/ +env/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo + +# 로그 및 데이터 (컨테이너에서 볼륨으로 마운트) +logs/ +data/ +*.log + +# 환경 파일 (docker-compose에서 env_file로 마운트) +.env + +# 임시 파일 +tmp/ +temp/ +*.tmp +*.bak + +# Docker 관련 +Dockerfile +docker-compose*.yml +.dockerignore + +# 문서 +*.md +!README.md + +# 기타 +*.sqlite +*.db diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..fca8d0a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,72 @@ +# ################################################################### +# Dockerfile - FGTools +# ################################################################### +# 퍼스트가든 통합 도구 Docker 이미지 +# ################################################################### + +FROM python:3.11-slim + +LABEL maintainer="dev@firstgarden.co.kr" +LABEL description="FGTools - First Garden 통합 도구" + +# 환경변수 설정 +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 +ENV PYTHONIOENCODING=utf-8 +ENV LANG=C.UTF-8 +ENV LC_ALL=C.UTF-8 +ENV TZ=Asia/Seoul + +# 작업 디렉토리 설정 +WORKDIR /app + +# 시스템 패키지 설치 (vim + 한글 지원 + 타임존) +RUN apt-get update && apt-get install -y --no-install-recommends \ + vim \ + locales \ + tzdata \ + curl \ + && rm -rf /var/lib/apt/lists/* \ + && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \ + && echo $TZ > /etc/timezone + +# 한글 로케일 설정 +RUN sed -i '/ko_KR.UTF-8/s/^# //g' /etc/locale.gen && \ + locale-gen ko_KR.UTF-8 +ENV LANG=ko_KR.UTF-8 +ENV LC_ALL=ko_KR.UTF-8 + +# vim 설정 (visual mode 비활성화 + 한글 지원) +RUN echo 'set mouse-=a' >> /etc/vim/vimrc.local && \ + echo 'set encoding=utf-8' >> /etc/vim/vimrc.local && \ + echo 'set fileencodings=utf-8,cp949,euc-kr' >> /etc/vim/vimrc.local && \ + echo 'set termencoding=utf-8' >> /etc/vim/vimrc.local + +# Python 의존성 설치 +COPY requirements.txt . +RUN pip install --no-cache-dir --upgrade pip && \ + pip install --no-cache-dir -r requirements.txt && \ + pip install --no-cache-dir gunicorn + +# 애플리케이션 코드 복사 +COPY core/ ./core/ +COPY services/ ./services/ +COPY apps/ ./apps/ +COPY *.py ./ + +# 로그 및 데이터 디렉토리 생성 +RUN mkdir -p /app/logs /app/data /app/conf + +# 헬스체크 +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:${FLASK_PORT:-5000}/api/dashboard/health || exit 1 + +# 기본 포트 노출 +EXPOSE 5000 5001 5002 + +# 엔트리포인트 +COPY docker-entrypoint.sh /docker-entrypoint.sh +RUN chmod +x /docker-entrypoint.sh + +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["dashboard"] diff --git a/README.md b/README.md index 3be57ce..283cd80 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ python -m apps.weather_api.app python -m apps.webhook.app ``` -### 4. Docker로 실행 +### 4. Docker로 실행 (개발용) ```bash # Docker Compose로 모든 서비스 실행 @@ -106,6 +106,179 @@ docker-compose up -d docker-compose logs -f ``` +## 🐳 Docker 배포 (운영 서버) + +운영 서버에서는 `docker-compose.yml`과 `.env` 파일만으로 서비스를 실행할 수 있습니다. + +### 1. 디렉토리 및 파일 준비 + +```bash +# 작업 디렉토리 생성 +mkdir -p /opt/fgtools +cd /opt/fgtools + +# 필요한 디렉토리 생성 +mkdir -p logs data conf +``` + +### 2. docker-compose.yml 다운로드 + +```bash +# docker-compose.yml 다운로드 +curl -o docker-compose.yml https://git.siane.kr/firstgarden/fgtools/raw/branch/main/docker-compose.yml +``` + +또는 아래 내용으로 `docker-compose.yml` 파일을 직접 생성: + +```yaml +version: '3.8' + +x-common: &common + image: reg.firstgarden.co.kr/fgtools:latest + env_file: + - .env + environment: + - TZ=Asia/Seoul + - PYTHONIOENCODING=utf-8 + restart: unless-stopped + networks: + - fgtools-network + +services: + dashboard: + <<: *common + container_name: fgtools-dashboard + command: ["dashboard"] + ports: + - "5000:5000" + environment: + - FLASK_PORT=5000 + volumes: + - ./logs:/app/logs + - ./data:/app/data + - ./conf:/app/conf:ro + + weather-api: + <<: *common + container_name: fgtools-weather + command: ["weather"] + ports: + - "5001:5001" + environment: + - FLASK_PORT=5001 + volumes: + - ./logs:/app/logs + - ./data:/app/data + - ./conf:/app/conf:ro + + webhook: + <<: *common + container_name: fgtools-webhook + command: ["webhook"] + ports: + - "5002:5002" + environment: + - FLASK_PORT=5002 + volumes: + - ./logs:/app/logs + - ./data:/app/data + - ./conf:/app/conf:ro + +networks: + fgtools-network: + driver: bridge +``` + +### 3. 환경 설정 파일 생성 + +```bash +# .env 파일 생성 (아래 내용 참고하여 편집) +cat > .env << 'EOF' +# 공공데이터포털 API 키 +DATA_API_SERVICE_KEY=your_api_key_here + +# 데이터베이스 +DB_HOST=your_db_host +DB_USER=your_db_user +DB_PASSWORD=your_db_password +DB_NAME=your_db_name +DB_CHARSET=utf8mb4 + +# Mattermost 알림 +MATTERMOST_ENABLED=true +MATTERMOST_URL=https://your-mattermost.com +MATTERMOST_TOKEN=your_token +MATTERMOST_CHANNEL_ID=your_channel_id + +# 기타 설정은 필요에 따라 추가 +EOF + +# .env 파일 편집 +vi .env +``` + +### 4. 사설 레지스트리 로그인 + +```bash +# 사설 레지스트리 로그인 +docker login reg.firstgarden.co.kr +``` + +### 5. 서비스 실행 + +```bash +# 이미지 다운로드 및 서비스 시작 +docker-compose pull +docker-compose up -d + +# 상태 확인 +docker-compose ps + +# 로그 확인 +docker-compose logs -f +``` + +### 6. 서비스 관리 + +```bash +# 전체 서비스 중지 +docker-compose down + +# 특정 서비스만 재시작 +docker-compose restart dashboard + +# 서비스 업데이트 (새 이미지 배포 시) +docker-compose pull +docker-compose up -d + +# 컨테이너 쉘 접속 +docker exec -it fgtools-dashboard /bin/bash +``` + +### 7. 포트 및 서비스 정보 + +| 서비스 | 컨테이너명 | 포트 | 헬스체크 URL | +|--------|-----------|------|--------------| +| Dashboard | fgtools-dashboard | 5000 | http://localhost:5000/api/dashboard/health | +| Weather API | fgtools-weather | 5001 | http://localhost:5001/api/weather/health | +| Webhook | fgtools-webhook | 5002 | http://localhost:5002/webhook/health | + +### 8. 이미지 빌드 및 푸시 (개발자용) + +```bash +# 소스 디렉토리에서 실행 +cd /path/to/fgtools + +# 이미지 빌드 +docker-compose build + +# 사설 레지스트리에 푸시 +docker-compose push + +# 빌드와 푸시 한번에 +docker-compose build && docker-compose push +``` + ## 📖 API 문서 ### Dashboard API (포트 5000) diff --git a/core/config.py b/core/config.py index 744fbd2..77ac33b 100644 --- a/core/config.py +++ b/core/config.py @@ -160,9 +160,9 @@ class Config: self.force_update = self._get_bool('FORCE_UPDATE', False) - # Weather 서비스 설정 + # Weather 서비스 설정 (DATA_API_SERVICE_KEY 사용) self.weather_service = { - 'service_key': self._get_env('SERVICE_KEY', ''), + 'service_key': self._get_env('DATA_API_SERVICE_KEY', ''), } # FTP 설정 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..79e411e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,102 @@ +# ################################################################### +# docker-compose.yml - FGTools 서비스 구성 +# ################################################################### +# 사설 레지스트리: reg.firstgarden.co.kr +# +# 사용법: +# 빌드: docker-compose build +# 푸시: docker-compose push +# 실행: docker-compose up -d +# 중지: docker-compose down +# 로그: docker-compose logs -f +# ################################################################### + +version: '3.8' + +x-common: &common + image: reg.firstgarden.co.kr/fgtools:latest + build: + context: . + dockerfile: Dockerfile + env_file: + - .env + environment: + - TZ=Asia/Seoul + - PYTHONIOENCODING=utf-8 + restart: unless-stopped + networks: + - fgtools-network + +services: + # ================================================================= + # Dashboard API - 대시보드 및 통계 API + # ================================================================= + dashboard: + <<: *common + container_name: fgtools-dashboard + command: ["dashboard"] + ports: + - "5000:5000" + environment: + - FLASK_PORT=5000 + - GUNICORN_WORKERS=2 + volumes: + - ./logs:/app/logs + - ./data:/app/data + - ./conf:/app/conf:ro + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5000/api/dashboard/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + + # ================================================================= + # Weather API - 날씨 정보 API + # ================================================================= + weather-api: + <<: *common + container_name: fgtools-weather + command: ["weather"] + ports: + - "5001:5001" + environment: + - FLASK_PORT=5001 + - GUNICORN_WORKERS=2 + volumes: + - ./logs:/app/logs + - ./data:/app/data + - ./conf:/app/conf:ro + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5001/api/weather/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + + # ================================================================= + # Webhook Server - 웹훅 수신 서버 (Notion 등) + # ================================================================= + webhook: + <<: *common + container_name: fgtools-webhook + command: ["webhook"] + ports: + - "5002:5002" + environment: + - FLASK_PORT=5002 + - GUNICORN_WORKERS=2 + volumes: + - ./logs:/app/logs + - ./data:/app/data + - ./conf:/app/conf:ro + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5002/webhook/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + +networks: + fgtools-network: + driver: bridge diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..a984181 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# ################################################################### +# docker-entrypoint.sh - FGTools 컨테이너 시작 스크립트 +# ################################################################### + +set -e + +# PYTHONPATH 설정 +export PYTHONPATH=/app:$PYTHONPATH + +# 서비스별 실행 +case "$1" in + dashboard) + echo "[FGTools] Starting Dashboard API on port ${FLASK_PORT:-5000}..." + exec gunicorn \ + --bind 0.0.0.0:${FLASK_PORT:-5000} \ + --workers ${GUNICORN_WORKERS:-2} \ + --timeout 120 \ + --access-logfile - \ + --error-logfile - \ + "apps.dashboard.app:create_app()" + ;; + weather) + echo "[FGTools] Starting Weather API on port ${FLASK_PORT:-5001}..." + exec gunicorn \ + --bind 0.0.0.0:${FLASK_PORT:-5001} \ + --workers ${GUNICORN_WORKERS:-2} \ + --timeout 120 \ + --access-logfile - \ + --error-logfile - \ + "apps.weather_api.app:create_app()" + ;; + webhook) + echo "[FGTools] Starting Webhook Server on port ${FLASK_PORT:-5002}..." + exec gunicorn \ + --bind 0.0.0.0:${FLASK_PORT:-5002} \ + --workers ${GUNICORN_WORKERS:-2} \ + --timeout 120 \ + --access-logfile - \ + --error-logfile - \ + "apps.webhook.app:create_app()" + ;; + shell) + echo "[FGTools] Starting interactive shell..." + exec /bin/bash + ;; + *) + echo "[FGTools] Unknown service: $1" + echo "Available services: dashboard, weather, webhook, shell" + exit 1 + ;; +esac