iT邦幫忙

2026 iThome 鐵人賽

DAY 23
0
Build on Google AI

給藥袋裝一張嘴:30 天用 Android 與 Google VLM 實作高齡語音用藥助手系列 第 23 篇

Day 23|邁向正式營運!實作 Gunicorn 高效能 WSGI 伺服器與 Nginx 反向代理配置

  • 分享至 

  • xImage
  •  

✏️【本日實作紀錄:Gunicorn 多工作進程與 Nginx 反向代理架構】

在 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)架構。完成項目包含:

  • Gunicorn 多工作進程(Worker Processes)配置 — 擺脫單執行緒限制,以非同步/多進程架構處理多位長輩同時傳送藥單的併發請求。
  • Nginx 反向代理與安全標頭配置 — 作為系統對外的第一線閘道(Gateway),處理客戶端連線、請求轉發、靜態檔案快取與防衛牆標頭。
  • Production 級三層容器編排 (docker-compose.yml) — 整合 Nginx、Gunicorn (Flask) 與 Redis 服務。

一、Gunicorn + Nginx 生產環境架構的設計

在 Python Web 應用的生產環境最佳實踐中,Nginx + Gunicorn + Flask 是最經典且穩定高效的三層架構:

  • Nginx(前置反向代理):負責接收客戶端(Web 儀表板 / LINE Webhook)的 HTTP/HTTPS 請求,處理 SSL 憑證、保護後端 Gunicorn 不直接曝露於公網,並提供高效率的靜態檔案服務。
  • Gunicorn(WSGI 應用伺服器):負責管理多個 Python 工作進程(Worker Processes),將 Nginx 轉發過來的 HTTP 請求派發給 Flask 應用處理,發揮多核心 CPU 的效能。
  • Flask(後端應用邏輯):專注於處理業務邏輯、 Gemini VLM 呼叫、 Redis 快取與 SQLite 資料讀寫。

二、升級專案依賴與配置 Gunicorn(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/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.yml

1. 更新 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
  • 預期成果:
  1. 回傳 HTTP 200,Response Header 中包含 Server: nginx,代表請求已成功透過 Nginx 反向代理轉發給 Gunicorn。
  2. 觀察 Gunicorn 容器日誌,可以看到多個 Worker 進程並列運作,具備高併發處理能力。

六、版本控制與提交 GitHub

測試通過後,將 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 正式跨入公網營運!


上一篇
Day 22|自動化防線到位!實作 GitHub Actions CI/CD 流水線與自動化測試
下一篇
Day 24|公網營運安全第一線!雲端自動化部署腳本與 Let's Encrypt SSL/TLS 憑證實作
系列文
給藥袋裝一張嘴:30 天用 Android 與 Google VLM 實作高齡語音用藥助手 共 24 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言