在 Day 22 完成 GitHub Actions CI/CD 自動化測試與建構流水線 後,PrescriptionVLM 系統已具備極高的代碼品質與自動化驗證機制。
然而,在之前的開發測試階段,我們一直是直接使用 Flask 內建的開發用 Server(app.run())來處理請求。Flask 內建 Server 屬於單執行緒(Single-Threaded)架構,無法處理真實生產環境中的高併發(High Concurrency)請求,且缺乏 SSL/TLS 憑證解析、靜態檔案高效快取與 HTTP 標頭安全防禦。
今天我們將為 PrescriptionVLM 系統導入 Gunicorn(Green Unicorn)WSGI 伺服器與 Nginx 反向代理(Reverse Proxy)架構。完成項目包含:
docker-compose.yml) — 整合 Nginx、Gunicorn (Flask) 與 Redis 服務。在 Python Web 應用的生產環境最佳實踐中,Nginx + Gunicorn + Flask 是最經典且穩定高效的三層架構:
requirements.txt & gunicorn.conf.py)1. 在 requirements.txt 加入 Gunicorn
請開啟專案根目錄的 requirements.txt,加入 Gunicorn 套件:
gunicorn==21.2.0
**2. 建立 Gunicorn 設定檔 gunicorn.conf.py**
在專案根目錄建立 gunicorn.conf.py,設定 Worker 數量與綁定連接埠:
import multiprocessing
import os
# 綁定容器內部的 5000 連接埠
bind = "0.0.0.0:5000"
# 工作進程數:通常建議設定為 (2 * CPU 核心數) + 1
workers = int(os.getenv("GUNICORN_WORKERS", multiprocessing.cpu_count() * 2 + 1))
# 工作模式:使用 sync 或 gevent/gthread 處理非同步 I/O
worker_class = "gthread"
threads = 2
# 超時時間:因 Gemini VLM 圖像解析需要數秒時間,將 Timeout 放寬至 120 秒
timeout = 120
# 保持連線時間
keepalive = 5
# 日誌配置
accesslog = "-"
errorlog = "-"
loglevel = "info"
nginx/nginx.conf)在專案根目錄建立 nginx/nginx.conf 檔案,作為對外服務入口的代理規則:
server {
listen 80;
server_name localhost;
# 限制上傳檔案大小(考量高解析度藥袋照片,設定為 16MB)
client_max_body_size 16M;
# 靜態檔案快取優化 (CSS/JS/Images)
location /static/ {
alias /app/static/;
expires 7d;
add_header Cache-Control "public, no-transform";
}
# 反向代理轉發給 Gunicorn Flask 服務
location / {
proxy_pass http://web:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 傳遞 Day 18 建立的 Trace ID
proxy_set_header X-Request-ID $http_x_request_id;
# 調整代理超時時間以利 AI 模型回應
proxy_connect_timeout 120s;
proxy_read_timeout 120s;
proxy_send_timeout 120s;
}
}
Dockerfile 與 docker-compose.yml1. 更新 Dockerfile 的 CMD 啟動指令
修改 Dockerfile 的最後一行,改由 Gunicorn 啟動服務:
# (前段 Multi-Stage 保持不變 ...)
# 切換為非 root 使用者執行
USER appuser
EXPOSE 5000
# 改用 Gunicorn 載入 gunicorn.conf.py 啟動 Flask 服務
CMD ["gunicorn", "-c", "gunicorn.conf.py", "app:app"]
2. 更新 docker-compose.yml 加入 Nginx 服務
修改專案根目錄的 docker-compose.yml,將 Nginx 加入架構中:
version: '3.8'
services:
redis:
image: redis:7.2-alpine
container_name: prescription_redis
ports:
- "6379:6379"
restart: always
web:
build:
context: .
dockerfile: Dockerfile
container_name: prescription_service
env_file:
- .env
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
depends_on:
- redis
restart: always
nginx:
image: nginx:1.25-alpine
container_name: prescription_nginx
ports:
- "80:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- web
restart: always
1. 透過 Docker Compose 啟動生產環境容器組
在 Terminal 執行命令:
docker-compose up --build -d
2. 驗證 Nginx 反向代理與併發處理
對 Nginx 暴露的 80 Port 發送測試請求:
curl -i http://127.0.0.1/dashboard
Server: nginx,代表請求已成功透過 Nginx 反向代理轉發給 Gunicorn。測試通過後,將 Day 23 的修改提交至 GitHub:
git add requirements.txt gunicorn.conf.py nginx/ Dockerfile docker-compose.yml
git commit -m "保留雙引號 改填寫自己要記錄的標記 ex.鐵人賽第二十三天"
git push
今天我們成功升級了 PrescriptionVLM 的架構,導入了 Gunicorn 多進程 WSGI 伺服器 與 Nginx 反向代理門戶,為系統提供了處理高併發請求、靜態快取與前置安全防護的生產級實力。
明天(Day 24),我們將進入雲端架構的最後衝刺,實作 云端伺服器(AWS/GCP/Glow)自動化部署腳本與 SSL/TLS 數位憑證(Let's Encrypt)安全設定,讓 PrescriptionVLM 正式跨入公網營運!