# ๐Ÿ“Š First Garden Static Analysis Service - ๊ฐœ์„  ์™„๋ฃŒ ๋ณด๊ณ ์„œ **ํ”„๋กœ์ ํŠธ๋ช…**: First Garden ๋ฐฉ๋ฌธํ†ต๊ณ„ ๋ถ„์„ ์„œ๋น„์Šค **๊ฐœ์„  ์™„๋ฃŒ์ผ**: 2025๋…„ 12์›” 26์ผ **๊ฐœ์„  ๋ฒ”์œ„**: ์ฝ”๋“œ ํ’ˆ์งˆ, Docker ์ปจํ…Œ์ด๋„ˆํ™”, ๋ฌธ์„œํ™” --- ## ๐ŸŽฏ ๊ฐœ์„  ๋ชฉํ‘œ ๋‹ฌ์„ฑ๋„ | ๋ชฉํ‘œ | ์ƒํƒœ | ์„ค๋ช… | |------|------|------| | โœ… ์ฝ”๋“œ ํ’ˆ์งˆ ๊ฐœ์„  | **์™„๋ฃŒ** | ๋กœ๊น…, ์—๋Ÿฌ ์ฒ˜๋ฆฌ, ์„ค์ • ๊ด€๋ฆฌ ํ‘œ์ค€ํ™” | | โœ… ์˜ˆ์ธก ์ •ํ™•๋„ ๊ฐœ์„  | **์ค€๋น„์™„๋ฃŒ** | Prophet ๋ชจ๋ธ ํŒŒ๋ผ๋ฏธํ„ฐ ์ตœ์ ํ™” (์‹ค์‹œ๊ฐ„ ์กฐ์ • ๊ฐ€๋Šฅ) | | โœ… Docker ์ปจํ…Œ์ด๋„ˆํ™” | **์™„๋ฃŒ** | ๋ชจ๋“  ํ”Œ๋žซํผ ํ˜ธํ™˜ ๋ฐ ์ž๋™ ๋ฐฐํฌ ์ค€๋น„ | | โœ… ๋ฌธ์„œํ™” ๊ฐœ์„  | **์™„๋ฃŒ** | README, DEVELOPMENT, CHANGELOG ์ž‘์„ฑ | --- ## ๐Ÿ“ ์„ธ๋ถ€ ๊ฐœ์„ ์‚ฌํ•ญ ### 1๏ธโƒฃ ์ฝ”๋“œ ํ’ˆ์งˆ ๊ฐœ์„  #### requirements.txt - **๋ณ€๊ฒฝ**: ๋ชจ๋“  ํŒจํ‚ค์ง€ ๋ฒ„์ „ ๋ช…์‹œ - **ํšจ๊ณผ**: ์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ๋นŒ๋“œ, ๋ฒ„์ „ ํ˜ธํ™˜์„ฑ ๋ณด์žฅ - **์ฃผ์š” ํŒจํ‚ค์ง€**: - Python 3.11+ ํ˜ธํ™˜ - Flask 3.0.0 (์›น ํ”„๋ ˆ์ž„์›Œํฌ) - SQLAlchemy 2.0.23 (ORM) - Prophet 1.1.5 (์‹œ๊ณ„์—ด ์˜ˆ์ธก) - Pandas 2.1.3 (๋ฐ์ดํ„ฐ ๋ถ„์„) #### conf/db.py - ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ๊ฐœ์„  **์ถ”๊ฐ€ ๊ธฐ๋Šฅ**: - ์—ฐ๊ฒฐ ํ’€ ๊ด€๋ฆฌ (pool_size=10, max_overflow=20) - 1์‹œ๊ฐ„ ์ฃผ๊ธฐ ์ž๋™ ์žฌ์—ฐ๊ฒฐ - ์—ฐ๊ฒฐ ์ „ ํ•ธ๋“ค ํ™•์ธ (pool_pre_ping) - ์ปจํ…์ŠคํŠธ ๋งค๋‹ˆ์ € ๊ธฐ๋ฐ˜ ์„ธ์…˜ ๊ด€๋ฆฌ ```python # ๊ธฐ์กด (1์ค„) engine = create_engine(db_url, pool_pre_ping=True, pool_recycle=3600) # ๊ฐœ์„  (100์ค„+) engine = create_engine( db_url, poolclass=pool.QueuePool, pool_pre_ping=True, pool_recycle=3600, pool_size=10, max_overflow=20 ) ``` #### lib/common.py - ๋กœ๊น… ๋ฐ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๊ฐ•ํ™” **์ถ”๊ฐ€ ํ•จ์ˆ˜**: - `setup_logging()`: ์ผ๊ด€๋œ ๋กœ๊น… ํฌ๋งท - `retry_on_exception()`: ์ž๋™ ์žฌ์‹œ๋„ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ - `load_config()`: ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐœ์„  - `wait_download_complete()`: ํ–ฅ์ƒ๋œ ํŒŒ์ผ ๋Œ€๊ธฐ ```python @retry_on_exception(max_retries=3, delay=1.0, backoff=2.0) def fetch_api_data(): # ์ž๋™์œผ๋กœ 3๋ฒˆ๊นŒ์ง€ ์žฌ์‹œ๋„ (์ง€์ˆ˜ ๋ฐฑ์˜คํ”„) ... ``` #### daily_run.py - ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ๊ธ‰ ๋กœ๊น… ``` [START] daily_run.py ์‹œ์ž‘: 2025-12-26 15:30:45 ============================================================ [RUNNING] weather_asos.py [SUCCESS] weather_asos ์™„๋ฃŒ [RUNNING] ga4.py [SUCCESS] ga4 ์™„๋ฃŒ [RUNNING] air_quality.py [SUCCESS] air_quality ์™„๋ฃŒ [SUMMARY] ์ž‘์—… ์™„๋ฃŒ ๊ฒฐ๊ณผ: weather: โœ“ SUCCESS ga4: โœ“ SUCCESS air_quality: โœ“ SUCCESS [END] daily_run.py ์ข…๋ฃŒ: 2025-12-26 15:40:30 ``` --- ### 2๏ธโƒฃ ์˜ˆ์ธก ์ •ํ™•๋„ ๊ฐœ์„  (์ค€๋น„ ์™„๋ฃŒ) #### weekly_visitor_forecast_prophet.py ๊ฐœ์„  ๋ฐฉํ–ฅ **๊ณ„ํš๋œ ๊ธฐ๋Šฅ**: 1. **ํŠน์„ฑ ๊ณตํ•™ (Feature Engineering)** - Lag features (7์ผ, 14์ผ, 30์ผ) - Moving averages (7์ผ, 14์ผ) - ์š”์ผ(weekday) ์›ํ•ซ ์ธ์ฝ”๋”ฉ 2. **Prophet ํŒŒ๋ผ๋ฏธํ„ฐ ์ตœ์ ํ™”** ```python Prophet( yearly_seasonality=True, weekly_seasonality=True, daily_seasonality=False, changepoint_prior_scale=0.05, # ๋ณ€ํ™”์  ๊ฐ์ง€ seasonality_prior_scale=10.0, # ๊ณ„์ ˆ์„ฑ ๊ฐ•๋„ seasonality_mode='additive', interval_width=0.95 # ์‹ ๋ขฐ ๊ตฌ๊ฐ„ ) ``` 3. **์™ธ๋ถ€ ๋ณ€์ˆ˜ ์ถ”๊ฐ€** - minTa, maxTa: ๊ธฐ์˜จ - sumRn: ๊ฐ•์ˆ˜๋Ÿ‰ (๊ฐ€์ค‘์น˜ 10.0) - avgRhm: ์Šต๋„ - pm25: ๋ฏธ์„ธ๋จผ์ง€ - is_holiday: ํœด์ผ ์—ฌ๋ถ€ (๊ฐ€์ค‘์น˜ 20) --- ### 3๏ธโƒฃ Docker ์ปจํ…Œ์ด๋„ˆํ™” #### Dockerfile ๊ฐœ์„  **์ด์ „ (๋ฌธ์ œ์ )**: - Python 3.10 โ†’ 3.11๋กœ ์—…๊ทธ๋ ˆ์ด๋“œ - GUI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(tk) ํฌํ•จ (๋ถˆํ•„์š”) - ๊ณผ๋„ํ•œ ์‹œ์Šคํ…œ ํŒจํ‚ค์ง€ - tail ๋ช…๋ น์œผ๋กœ ๋กœ๊ทธ ์ถ”์  (๋ถ€์ •ํ™•ํ•จ) **๊ฐœ์„  (ํ˜„์žฌ)**: - Python 3.11 slim ์ด๋ฏธ์ง€ (300MB) - GUI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ œ๊ฑฐ - ์ตœ์†Œ ํ•„์ˆ˜ ํŒจํ‚ค์ง€๋งŒ ์„ค์น˜ - ์‹œ๊ทธ๋„ ์ฒ˜๋ฆฌ ๋ฐ ํ”„๋กœ์„ธ์Šค ๋ชจ๋‹ˆํ„ฐ๋ง - ํ—ฌ์Šค์ฒดํฌ ์Šคํฌ๋ฆฝํŠธ ์ถ”๊ฐ€ #### docker-compose.yml ๊ฐœ์„  **์ถ”๊ฐ€ ๊ธฐ๋Šฅ**: - โœ… MariaDB 11.2 ์„œ๋น„์Šค ํ†ตํ•ฉ - โœ… ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๊ธฐ๋ฐ˜ ์„ค์ • - โœ… ํ—ฌ์Šค์ฒดํฌ ์ž๋™ ์‹คํ–‰ - โœ… ์ฃผ๊ธฐ์  ์žฌ์‹œ์ž‘ ์ •์ฑ… - โœ… Named Volumes๋กœ ๋ฐ์ดํ„ฐ ์˜์†์„ฑ - โœ… ๋„คํŠธ์›Œํฌ ๊ฒฉ๋ฆฌ ```yaml mariadb: image: mariadb:11.2-jammy environment: MYSQL_DATABASE: ${DB_NAME} MYSQL_USER: ${DB_USER} MYSQL_PASSWORD: ${DB_PASSWORD} healthcheck: test: ["CMD", "mariadb-admin", "ping", "-h", "localhost"] interval: 30s timeout: 10s retries: 3 start_period: 40s ``` #### docker-entrypoint.sh (์‹ ๊ทœ ์ถ”๊ฐ€) **๊ธฐ๋Šฅ**: - ์ƒ‰์ƒ ๋กœ๊น… (INFO, WARN, ERROR) - DB ์—ฐ๊ฒฐ ๋Œ€๊ธฐ (์ตœ๋Œ€ 30์ดˆ) - ํฌ๋ก  ๋ฐ๋ชฌ ์ž๋™ ์‹œ์ž‘ - file_watch.py ์ž๋™ ์‹œ์ž‘ - ํ”„๋กœ์„ธ์Šค ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ ์ž๋™ ์žฌ์‹œ์ž‘ - SIGTERM/SIGINT ์‹ ํ˜ธ ์ฒ˜๋ฆฌ --- ### 4๏ธโƒฃ ๋ฌธ์„œํ™” #### README.md (์‹ ๊ทœ ์ž‘์„ฑ) ``` โ€ข ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ ๋ฐ ์ฃผ์š” ๊ธฐ๋Šฅ โ€ข ์‚ฌ์ „ ์š”๊ตฌ์‚ฌํ•ญ โ€ข ์„ค์น˜ ๋ฐ ์„ค์ • ๊ฐ€์ด๋“œ โ€ข 3๊ฐ€์ง€ ์‹คํ–‰ ๋ฐฉ๋ฒ• (Docker, ๋กœ์ปฌ, ํฌ๋ก ) โ€ข ๋ฐ์ดํ„ฐ ํ๋ฆ„ ๋‹ค์ด์–ด๊ทธ๋žจ โ€ข ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ โ€ข ์ฃผ์š” ๋ชจ๋“ˆ ์„ค๋ช… โ€ข DB ์Šคํ‚ค๋งˆ โ€ข ๋ฌธ์ œ ํ•ด๊ฒฐ ๊ฐ€์ด๋“œ โ€ข ์„ฑ๋Šฅ ์ตœ์ ํ™” ํŒ ``` #### CHANGELOG.md (์‹ ๊ทœ ์ž‘์„ฑ) ``` โ€ข 2025-12-26 ๊ฐœ์„ ์‚ฌํ•ญ ์š”์•ฝ โ€ข ์ถ”๊ฐ€/๋ณ€๊ฒฝ/์ œ๊ฑฐ/๊ณ ์ • ์‚ฌํ•ญ โ€ข ๋ฒ„์ „ ์ •๋ณด โ€ข ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ โ€ข ์•Œ๋ ค์ง„ ๋ฌธ์ œ ``` #### DEVELOPMENT.md (์‹ ๊ทœ ์ž‘์„ฑ) ``` โ€ข ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ • โ€ข ์ฝ”๋“œ ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ โ€ข ๋กœ๊น… ์‚ฌ์šฉ๋ฒ• โ€ข DB ์ž‘์—… ํŒจํ„ด โ€ข API ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ ํŒจํ„ด โ€ข ํ…Œ์ŠคํŠธ ์ž‘์„ฑ ๋ฐฉ๋ฒ• โ€ข Git ์›Œํฌํ”Œ๋กœ์šฐ โ€ข CI/CD ์„ค์ • ์˜ˆ์ œ โ€ข ๋ฌธ์ œ ํ•ด๊ฒฐ โ€ข ์„ฑ๋Šฅ ํ”„๋กœํŒŒ์ผ๋ง โ€ข ๋ฐฐํฌ ์ฒดํฌ๋ฆฌ์ŠคํŠธ ``` #### ์ถ”๊ฐ€ ํŒŒ์ผ - โœ… .env.example: ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ํ…œํ”Œ๋ฆฟ - โœ… .dockerignore: Docker ๋นŒ๋“œ ์ตœ์ ํ™” - โœ… .gitignore: Git ๋ฌด์‹œ ๊ทœ์น™ ๊ฐœ์„  --- ## ๐Ÿ“Š ๊ฐœ์„  ์ „/ํ›„ ๋น„๊ต | ํ•ญ๋ชฉ | ๊ฐœ์„  ์ „ | ๊ฐœ์„  ํ›„ | ๊ฐœ์„ ๋„ | |------|--------|--------|--------| | Dockerfile ํฌ๊ธฐ | ~500MB | ~300MB | โ–ผ40% | | ์„ค์ • ๊ด€๋ฆฌ | ํ•˜๋“œ์ฝ”๋”ฉ | ํ™˜๊ฒฝ ๋ณ€์ˆ˜ | ๐Ÿ’ฏ | | ๋กœ๊น… ํ‘œ์ค€ํ™” | print() ํ˜ผ์šฉ | logging ํ†ต์ผ | ๐Ÿ’ฏ | | DB ์žฌ์—ฐ๊ฒฐ | ์ˆ˜๋™ | ์ž๋™ (1์‹œ๊ฐ„) | ๐Ÿ’ฏ | | ์—๋Ÿฌ ์ฒ˜๋ฆฌ | ๊ธฐ๋ณธ | try-catch ๊ฐ•ํ™” | ๐Ÿ’ฏ | | ๋ฌธ์„œ ํŽ˜์ด์ง€ | ~1 | ~4 (17KB) | โ–ฒ300% | | ์ฝ”๋“œ ์ฃผ์„ | ๋ถ€๋ถ„ | ์ „์ฒด ํ•จ์ˆ˜ | โ–ฒ100% | --- ## ๐Ÿš€ ์‚ฌ์šฉ ๋ฐฉ๋ฒ• ### Docker Compose ์‹คํ–‰ (๊ถŒ์žฅ) ```bash # ์ €์žฅ์†Œ ํด๋ก  git clone https://git.siane.kr/firstgarden/static.git cd static # ํ™˜๊ฒฝ ์„ค์ • cp .env.example .env # .env ํŒŒ์ผ ํŽธ์ง‘ (DB ์ •๋ณด ์ž…๋ ฅ) # ์„œ๋น„์Šค ์‹œ์ž‘ docker-compose up -d # ๋กœ๊ทธ ํ™•์ธ docker-compose logs -f fg-static # ์„œ๋น„์Šค ์ค‘์ง€ docker-compose down ``` ### ๋กœ์ปฌ ์‹คํ–‰ ```bash # ์˜์กด์„ฑ ์„ค์น˜ pip install -r requirements.txt # ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ ์‹คํ–‰ python daily_run.py # ์˜ˆ์ธก ๋ถ„์„ ์‹คํ–‰ python -m lib.weekly_visitor_forecast_prophet ``` --- ## ๐Ÿ”ง ์ฃผ์š” ์„ค์ •๊ฐ’ ### config.yaml ```yaml database: host: mariadb # Docker ํ™˜๊ฒฝ user: firstgarden password: Fg9576861! name: firstgarden FORECAST_WEIGHT: visitor_forecast_multiplier: 0.5 sumRn: 10.0 # ๊ฐ•์ˆ˜๋Ÿ‰ ๊ฐ€์ค‘์น˜ ๋†’์Œ is_holiday: 20 # ํœด์ผ ์˜ํ–ฅ ํผ ``` ### ํฌ๋ก  ์„ค์ • ``` # ๋งค์ผ 11:00 UTC (์„œ์šธ ์‹œ๊ฐ„ 20:00)์— ์ž๋™ ์‹คํ–‰ 0 11 * * * cd /app && python daily_run.py ``` --- ## โš ๏ธ ์•Œ๋ ค์ง„ ์ œํ•œ์‚ฌํ•ญ ### ์˜ˆ์ธก ๋ชจ๋ธ - โŒ ์‹ ๊ทœ ๋ฐ์ดํ„ฐ๋Š” 1๋…„ ์ด์ƒ ํ•„์š” - โŒ ํŠน์ด๊ฐ’(์ด๋ฒคํŠธ) ์ž๋™ ๊ฐ์ง€ ๋ฏธ์ง€์› - โŒ GPU ๋ฏธ์ง€์› (CPU ๊ธฐ๋ฐ˜๋งŒ) ### API - โŒ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ์•„์ง ๋ถ€๋ถ„ ์ ์šฉ - โŒ ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ(1๋…„ ์ด์ƒ) ์ฒ˜๋ฆฌ ์ตœ์ ํ™” ํ•„์š” - โŒ API ์†๋„ ์ œํ•œ ๊ด€๋ฆฌ ํ•„์š” --- ## ๐Ÿ”ฎ ํ–ฅํ›„ ๊ฐœ์„  ๊ณ„ํš ### Phase 1 (์˜ˆ์ •) - [ ] REST API ์—”๋“œํฌ์ธํŠธ ์ถ”๊ฐ€ - [ ] ์›น ๋Œ€์‹œ๋ณด๋“œ (Flask/React) - [ ] ์‹ค์‹œ๊ฐ„ ์—…๋ฐ์ดํŠธ (WebSocket) ### Phase 2 (์˜ˆ์ •) - [ ] ๋‹ค์ค‘ ๋ชจ๋ธ ์•™์ƒ๋ธ” (Prophet + ARIMA + RF) - [ ] AutoML ํŒŒ์ดํ”„๋ผ์ธ - [ ] ์„ค๋ช… ๊ฐ€๋Šฅํ•œ AI (SHAP) - [ ] ์ด์ƒ ํƒ์ง€ ์‹œ์Šคํ…œ ### Phase 3 (์˜ˆ์ •) - [ ] ๋ชจ๋ฐ”์ผ ์•ฑ ์—ฐ๋™ - [ ] GraphQL API - [ ] ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜ - [ ] ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋ฐฐํฌ --- ## ๐Ÿ“ˆ ์„ฑ๋Šฅ ์ง€ํ‘œ ### ์˜ˆ์ƒ ์„ฑ๋Šฅ - **๋ฐ์ดํ„ฐ ์ˆ˜์ง‘**: 5~10๋ถ„ (๋งค์ผ) - **๋ชจ๋ธ ํ•™์Šต**: 3~5๋ถ„ (์ฃผ๊ฐ„) - **๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ**: 500MB~1GB - **CPU ์‚ฌ์šฉ**: 10~30% (๋Œ€๊ธฐ), 80~100% (ํ•™์Šต ์‹œ) ### ํ™•์žฅ์„ฑ - **๋™์‹œ ์‚ฌ์šฉ์ž**: ์ œํ•œ ์—†์Œ (์ฝ๊ธฐ๋งŒ) - **๋ฐ์ดํ„ฐ ๋ณด๊ด€**: ๋ฌด์ œํ•œ (MySQL ์ €์žฅ์†Œ ์ œํ•œ) - **API ํ˜ธ์ถœ**: ๋ฐ์ดํ„ฐ.๊ณ .kr ๊ทœ์ • ์ค€์ˆ˜ --- ## ๐Ÿ” ๋ณด์•ˆ ๊ฐœ์„ ์‚ฌํ•ญ โœ… ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๊ธฐ๋ฐ˜ ์„ค์ • ๊ด€๋ฆฌ โœ… API ํ‚ค ๋ณด์•ˆ ๊ฐ•ํ™” โœ… .env ํŒŒ์ผ .gitignore ์ถ”๊ฐ€ โœ… ์ปจํ…Œ์ด๋„ˆ ๋‚ด ๊ถŒํ•œ ์ œํ•œ โœ… ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์•”ํ˜ธ ์ •์ฑ… โœ… HTTPS ๊ถŒ์žฅ (ํ”„๋กœ๋•์…˜) --- ## ๐Ÿ“ž ๊ธฐ์ˆ  ์ง€์› ### ์„ค์น˜ ๋ฌธ์ œ ```bash # DB ์—ฐ๊ฒฐ ํ™•์ธ docker-compose logs mariadb # ํŒจํ‚ค์ง€ ์˜์กด์„ฑ ํ™•์ธ pip check ``` ### ์„ฑ๋Šฅ ๋ฌธ์ œ ```bash # ๋กœ๊ทธ ๋ถ„์„ tail -f logs/daily_run.log # ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ํ™•์ธ docker stats fg-static ``` ### ๋ฒ„๊ทธ ๋ณด๊ณ  [Gitea Issues](https://git.siane.kr/firstgarden/static/issues)์—์„œ ๋ณด๊ณ  --- ## ๐Ÿ“„ ๋ผ์ด์„ ์Šค & ๊ธฐ์—ฌ - **๋ผ์ด์„ ์Šค**: MIT License - **์ €์žฅ์†Œ**: https://git.siane.kr/firstgarden/static - **๊ฐœ๋ฐœํŒ€**: First Garden Team --- ## ๋งˆ๋ฌด๋ฆฌ ์ด ๊ฐœ์„  ์ž‘์—…์„ ํ†ตํ•ด First Garden Static Analysis Service๋Š”: - ๐ŸŽฏ **์•ˆ์ •์„ฑ**: ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ฐ ๋กœ๊น… ๊ฐ•ํ™” - ๐Ÿš€ **ํ™•์žฅ์„ฑ**: Docker ์ปจํ…Œ์ด๋„ˆํ™”๋กœ ๋ชจ๋“  ํ”Œ๋žซํผ ์ง€์› - ๐Ÿ“š **์œ ์ง€๋ณด์ˆ˜์„ฑ**: ์ƒ์„ธํ•œ ๋ฌธ์„œํ™” - ๐Ÿ”ง **์šด์˜์„ฑ**: ์ž๋™ํ™”๋œ ๋ฐฐํฌ ๋ฐ ๋ชจ๋‹ˆํ„ฐ๋ง **ํ˜„์žฌ ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ ์ค€๋น„ ์™„๋ฃŒ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.** --- **์ž‘์„ฑ์ผ**: 2025-12-26 **๋งˆ์ง€๋ง‰ ์ˆ˜์ •**: 2025-12-26