- WSL2 Ubuntu에서 'image already exists' 오류 해결 문서 추가 - Linux/macOS용 build.sh 스크립트 추가 (BuildKit 비활성화) - Windows PowerShell용 build.ps1 스크립트 추가 - 빌드 오류 트러블슈팅 가이드 추가 - docker-compose.yml에 빌드 오류 관련 주석 추가 - MODULES.md에 Docker 빌드 오류 해결 섹션 추가
540 lines
15 KiB
Markdown
540 lines
15 KiB
Markdown
# ===================================================================
|
|
# FGTools - First Garden 통합 도구
|
|
# ===================================================================
|
|
# 퍼스트가든 운영을 위한 통합 도구 모음입니다.
|
|
# 기상 데이터, 방문객 분석, 알림 등의 기능을 제공합니다.
|
|
# ===================================================================
|
|
|
|
## 📌 개요
|
|
|
|
FGTools는 퍼스트가든 운영에 필요한 다양한 도구들을 통합한 프로젝트입니다.
|
|
|
|
### 주요 기능
|
|
|
|
- **날씨 서비스**: 기상청 API를 통한 날씨 예보 및 ASOS 종관기상 데이터 수집
|
|
- **분석 서비스**: Google Analytics 4, 대기질 데이터 수집 및 방문객 예측
|
|
- **알림 서비스**: Notion 웹훅 처리 및 Mattermost/Telegram 알림 발송
|
|
- **대시보드**: 수집된 데이터를 조회하고 시각화하는 웹 인터페이스
|
|
|
|
## 📁 프로젝트 구조
|
|
|
|
```
|
|
fgtools/
|
|
├── core/ # 핵심 공통 모듈
|
|
│ ├── config.py # 통합 설정 관리
|
|
│ ├── database.py # 데이터베이스 연결 관리
|
|
│ ├── logging_utils.py # 로깅 유틸리티
|
|
│ ├── http_client.py # HTTP 클라이언트 (재시도 지원)
|
|
│ └── message_sender.py # 다중 플랫폼 메시지 발송
|
|
│
|
|
├── services/ # 도메인 서비스
|
|
│ ├── weather/ # 기상 데이터 서비스
|
|
│ │ ├── forecast.py # 예보 API (초단기/단기/중기)
|
|
│ │ ├── asos.py # ASOS 종관기상 데이터
|
|
│ │ └── precipitation.py # 강수량 서비스
|
|
│ │
|
|
│ ├── analytics/ # 분석 서비스
|
|
│ │ ├── ga4.py # Google Analytics 4
|
|
│ │ ├── air_quality.py # 대기질 데이터
|
|
│ │ └── visitor_forecast.py # 방문객 예측
|
|
│ │
|
|
│ └── notification/ # 알림 서비스
|
|
│ ├── notion.py # Notion 웹훅 처리
|
|
│ └── mattermost.py # Mattermost 알림
|
|
│
|
|
├── apps/ # 웹 애플리케이션
|
|
│ ├── dashboard/ # 대시보드 API
|
|
│ ├── weather_api/ # 날씨 API 서버
|
|
│ └── webhook/ # 웹훅 수신 서버
|
|
│
|
|
├── .env.sample # 환경변수 샘플
|
|
├── requirements.txt # Python 의존성
|
|
└── docker-compose.yml # Docker 구성
|
|
```
|
|
|
|
## 🚀 시작하기
|
|
|
|
### 1. 환경 설정
|
|
|
|
```bash
|
|
# 저장소 클론
|
|
git clone https://git.siane.kr/firstgarden/fgtools.git
|
|
cd fgtools
|
|
|
|
# 가상환경 생성 및 활성화
|
|
python -m venv venv
|
|
source venv/bin/activate # Linux/Mac
|
|
# 또는
|
|
.\venv\Scripts\activate # Windows
|
|
|
|
# 의존성 설치
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
### 2. 설정 파일 생성
|
|
|
|
```bash
|
|
# .env 파일 생성
|
|
cp .env.sample .env
|
|
|
|
# .env 파일을 편집하여 실제 값 입력
|
|
# - 데이터베이스 접속 정보
|
|
# - API 키
|
|
# - 알림 설정 등
|
|
```
|
|
|
|
### 3. 애플리케이션 실행
|
|
|
|
```bash
|
|
# 대시보드 서버 실행
|
|
python -m apps.dashboard.app
|
|
|
|
# 날씨 API 서버 실행
|
|
python -m apps.weather_api.app
|
|
|
|
# 웹훅 수신 서버 실행
|
|
python -m apps.webhook.app
|
|
```
|
|
|
|
### 4. Docker로 실행 (개발용)
|
|
|
|
```bash
|
|
# Docker Compose로 모든 서비스 실행
|
|
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
|
|
```
|
|
|
|
### 9. 빌드 오류 해결
|
|
|
|
#### 오류: "image already exists"
|
|
```bash
|
|
# 증상
|
|
# > [weather-api] exporting to image:
|
|
# [+] build 0/1
|
|
# target weather-api: failed to solve: image "reg.firstgarden.co.kr/fgtools:latest": already exists
|
|
|
|
# 해결 방법 1: BuildKit 비활성화 (권장)
|
|
DOCKER_BUILDKIT=0 docker compose build
|
|
|
|
# 해결 방법 2: 캐시 무시하고 빌드
|
|
docker compose build --no-cache
|
|
|
|
# 해결 방법 3: 이전 이미지 삭제 후 빌드
|
|
docker rmi reg.firstgarden.co.kr/fgtools:latest
|
|
docker compose build
|
|
|
|
# 해결 방법 4: 완전 초기화
|
|
docker compose down
|
|
docker rmi reg.firstgarden.co.kr/fgtools:latest
|
|
docker buildx prune -a
|
|
docker compose build
|
|
|
|
# 해결 방법 5: 빌드 스크립트 사용 (권장)
|
|
# Linux/macOS
|
|
chmod +x scripts/build.sh
|
|
./scripts/build.sh clean # 또는 ./scripts/build.sh force
|
|
|
|
# Windows PowerShell
|
|
.\scripts\build.ps1 -Clean # 또는 .\scripts\build.ps1 -Force
|
|
```
|
|
|
|
#### 빌드 스크립트 사용
|
|
|
|
자동화된 빌드 스크립트를 제공합니다:
|
|
|
|
**Linux/macOS:**
|
|
```bash
|
|
chmod +x scripts/build.sh
|
|
|
|
# 기본 빌드 (BuildKit 비활성화)
|
|
./scripts/build.sh
|
|
|
|
# 캐시 무시하고 빌드
|
|
./scripts/build.sh clean
|
|
|
|
# 완전 초기화 후 빌드
|
|
./scripts/build.sh force
|
|
|
|
# 빌드 및 사설 레지스트리에 푸시
|
|
./scripts/build.sh push
|
|
```
|
|
|
|
**Windows PowerShell:**
|
|
```powershell
|
|
# 첫 실행 시 실행 정책 설정
|
|
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
|
|
|
# 기본 빌드
|
|
.\scripts\build.ps1
|
|
|
|
# 캐시 무시하고 빌드
|
|
.\scripts\build.ps1 -Clean
|
|
|
|
# 완전 초기화 후 빌드
|
|
.\scripts\build.ps1 -Force
|
|
|
|
# 빌드 및 푸시
|
|
.\scripts\build.ps1 -Push
|
|
```
|
|
|
|
#### WSL2 Ubuntu에서 권장 방법
|
|
```bash
|
|
# WSL2 우분투에서 BuildKit 문제가 자주 발생합니다.
|
|
# 다음 방법들을 순서대로 시도하세요:
|
|
|
|
# 1단계: BuildKit 비활성화로 빌드
|
|
DOCKER_BUILDKIT=0 docker compose build
|
|
|
|
# 실패하면:
|
|
# 2단계: 캐시 무시하고 빌드
|
|
DOCKER_BUILDKIT=0 docker compose build --no-cache
|
|
|
|
# 여전히 실패하면:
|
|
# 3단계: 완전 초기화
|
|
docker compose down
|
|
docker rmi reg.firstgarden.co.kr/fgtools:latest
|
|
docker buildx prune -a
|
|
DOCKER_BUILDKIT=0 docker compose build
|
|
|
|
# 또는 제공된 빌드 스크립트 사용:
|
|
chmod +x scripts/build.sh
|
|
./scripts/build.sh force
|
|
```
|
|
|
|
## 📖 API 문서
|
|
|
|
### Dashboard API (포트 5000)
|
|
|
|
| 엔드포인트 | 메서드 | 설명 |
|
|
|-----------|--------|------|
|
|
| `/api/dashboard/health` | GET | 헬스 체크 |
|
|
| `/api/dashboard/stats` | GET | 통계 조회 |
|
|
| `/api/dashboard/weather/forecast` | GET | 날씨 예보 |
|
|
| `/api/dashboard/weather/precipitation` | GET | 강수량 예보 |
|
|
|
|
### Weather API (포트 5001)
|
|
|
|
| 엔드포인트 | 메서드 | 설명 |
|
|
|-----------|--------|------|
|
|
| `/api/weather/health` | GET | 헬스 체크 |
|
|
| `/api/weather/precipitation` | GET | 시간별 강수량 |
|
|
| `/api/weather/forecast/ultra` | GET | 초단기예보 |
|
|
| `/api/weather/forecast/vilage` | GET | 단기예보 |
|
|
| `/api/weather/forecast/midterm` | GET | 중기예보 |
|
|
|
|
### Webhook API (포트 5002)
|
|
|
|
| 엔드포인트 | 메서드 | 설명 |
|
|
|-----------|--------|------|
|
|
| `/webhook/health` | GET | 헬스 체크 |
|
|
| `/webhook/notion` | POST | Notion 웹훅 수신 |
|
|
| `/webhook/notify` | POST | 알림 발송 |
|
|
|
|
## ⚙️ 환경변수 설명
|
|
|
|
주요 환경변수는 `.env.sample` 파일을 참고하세요.
|
|
|
|
| 변수명 | 설명 | 필수 |
|
|
|--------|------|------|
|
|
| `DB_HOST` | 데이터베이스 호스트 | ✅ |
|
|
| `DB_USER` | 데이터베이스 사용자 | ✅ |
|
|
| `DB_PASSWORD` | 데이터베이스 비밀번호 | ✅ |
|
|
| `DATA_API_SERVICE_KEY` | 공공데이터포털 API 키 | ✅ |
|
|
| `MATTERMOST_URL` | Mattermost 서버 URL | ❌ |
|
|
| `NOTION_API_SECRET` | Notion API 시크릿 | ❌ |
|
|
|
|
## 🔑 API 키 발급 가이드
|
|
|
|
### 1. 공공데이터포털 API 키 (DATA_API_SERVICE_KEY, SERVICE_KEY)
|
|
|
|
기상청 API, 대기질 API 등 공공데이터 사용에 필요합니다.
|
|
|
|
1. [공공데이터포털](https://data.go.kr) 접속 및 회원가입
|
|
2. 로그인 후 필요한 API 검색:
|
|
- **기상청_단기예보 조회서비스**: 초단기/단기 예보
|
|
- **기상청_중기예보 조회서비스**: 중기 예보
|
|
- **기상청_지상(종관, ASOS) 일자료 조회서비스**: ASOS 데이터
|
|
- **한국환경공단_에어코리아_대기오염정보**: 대기질 정보
|
|
3. 각 API의 "활용신청" 클릭
|
|
4. 신청 승인 후 마이페이지 → 인증키 발급현황에서 **일반 인코딩 키** 복사
|
|
5. `.env` 파일의 `DATA_API_SERVICE_KEY` 및 `SERVICE_KEY`에 동일한 키 입력
|
|
|
|
### 2. Google Analytics 4 (GA4_*)
|
|
|
|
웹사이트 방문자 데이터 수집에 필요합니다.
|
|
|
|
#### GA4 Property ID 확인
|
|
1. [Google Analytics](https://analytics.google.com) 접속
|
|
2. 관리(⚙️) → 속성 설정 → **속성 ID** 확인
|
|
3. `.env` 파일의 `GA4_PROPERTY_ID`에 입력
|
|
|
|
#### 서비스 계정 생성 (API 접근용)
|
|
1. [Google Cloud Console](https://console.cloud.google.com) 접속
|
|
2. 새 프로젝트 생성 또는 기존 프로젝트 선택
|
|
3. **API 및 서비스** → **라이브러리** → "Google Analytics Data API" 검색 후 **사용 설정**
|
|
4. **API 및 서비스** → **사용자 인증 정보** → **+ 사용자 인증 정보 만들기** → **서비스 계정**
|
|
5. 서비스 계정 생성 후 **키** 탭 → **키 추가** → **새 키 만들기** → JSON 선택
|
|
6. 다운로드된 JSON 파일을 `conf/service-account-credentials.json`으로 저장
|
|
7. `.env` 파일의 `GA4_SERVICE_ACCOUNT_FILE`에 경로 입력
|
|
|
|
#### GA4에 서비스 계정 권한 부여
|
|
1. Google Analytics → 관리(⚙️) → 속성 액세스 관리
|
|
2. **+** 클릭 → **사용자 추가**
|
|
3. 서비스 계정 이메일 (예: `xxx@project-id.iam.gserviceaccount.com`) 입력
|
|
4. **뷰어** 권한 부여 후 저장
|
|
|
|
### 3. Mattermost (MATTERMOST_*)
|
|
|
|
Mattermost 알림 발송에 필요합니다.
|
|
|
|
#### Bot 토큰 방식 (권장)
|
|
1. Mattermost 서버 → **통합** → **봇 계정**
|
|
2. **봇 계정 추가** 클릭
|
|
3. 봇 이름, 설명 입력 후 생성
|
|
4. 생성된 **액세스 토큰**을 `MATTERMOST_TOKEN`에 입력
|
|
5. 봇을 사용할 채널에 봇 추가
|
|
6. 채널 설정 → URL에서 채널 ID 확인 또는 API로 조회
|
|
7. `MATTERMOST_CHANNEL_ID`에 채널 ID 입력
|
|
|
|
#### 웹훅 방식 (대안)
|
|
1. Mattermost 서버 → **통합** → **수신 웹훅**
|
|
2. **수신 웹훅 추가** 클릭
|
|
3. 채널 선택 후 생성
|
|
4. 생성된 웹훅 URL을 `MATTERMOST_WEBHOOK_URL`에 입력
|
|
|
|
### 4. Telegram Bot (TELEGRAM_*)
|
|
|
|
Telegram 알림 발송에 필요합니다.
|
|
|
|
1. Telegram에서 [@BotFather](https://t.me/BotFather) 검색
|
|
2. `/newbot` 명령어 입력
|
|
3. 봇 이름과 사용자명 입력
|
|
4. 발급된 **HTTP API 토큰**을 `TELEGRAM_BOT_TOKEN`에 입력
|
|
5. 봇과 대화 시작 (또는 그룹에 봇 추가)
|
|
6. `https://api.telegram.org/bot<TOKEN>/getUpdates` 접속
|
|
7. 응답에서 `chat.id` 값을 `TELEGRAM_CHAT_ID`에 입력
|
|
|
|
### 5. Notion API (NOTION_*)
|
|
|
|
Notion 웹훅 처리에 필요합니다.
|
|
|
|
1. [Notion Developers](https://developers.notion.com) 접속
|
|
2. **+ New integration** 클릭
|
|
3. 이름 입력, 워크스페이스 선택 후 생성
|
|
4. **Internal Integration Secret**을 `NOTION_API_SECRET`에 입력
|
|
5. Notion에서 연동할 페이지/DB 열기
|
|
6. **···** → **커넥션** → 생성한 통합 추가
|
|
|
|
### 6. Synology Chat (SYNOLOGY_*)
|
|
|
|
Synology Chat 알림 발송에 필요합니다.
|
|
|
|
1. Synology Chat 앱 실행
|
|
2. 채널 설정 → **통합** → **봇**
|
|
3. **+ 추가** → **수신 웹훅** 선택
|
|
4. 봇 이름 입력 후 생성
|
|
5. 생성된 **웹훅 URL**을 `SYNOLOGY_CHAT_URL`에 입력
|
|
6. URL에 포함된 토큰을 `SYNOLOGY_CHAT_TOKEN`에 입력
|
|
|
|
## 🔧 개발
|
|
|
|
### 코드 스타일
|
|
|
|
- Python 3.10 이상
|
|
- Type hints 사용
|
|
- Docstring 필수
|
|
- Black 포매터 권장
|
|
|
|
### 테스트
|
|
|
|
```bash
|
|
# 테스트 실행
|
|
pytest tests/
|
|
|
|
# 커버리지 포함
|
|
pytest --cov=. tests/
|
|
```
|
|
|
|
## 📝 라이선스
|
|
|
|
Private - First Garden Internal Use Only
|
|
|
|
## 📞 연락처
|
|
|
|
기술 지원: dev@firstgarden.kr
|