2025年8月28日 星期四

在 Docker 中整合 Laravel Reverb、WebSocket、Redis 與 Nginx 的全方位指南

想要為 Laravel 應用程式加入即時通訊功能,並確保在容器化環境中具備高效、可擴展的廣播機制?本文將帶你從理論基礎到實作細節,一步步在 Docker 環境裡整合 Laravel Reverb、Redis、WebSocket 及 Nginx,並補足常見的監控、疑難排解和擴展規劃。


目錄

  1. 背景與核心概念
  2. 為何選擇 Redis 作為廣播驅動
  3. 整體服務架構圖
  4. Docker Compose 設定詳解
  5. Laravel 環境變數與設定
  6. Nginx 反向代理設置
  7. 前端 JavaScript 與 Echo 配置
  8. 啟動與驗證服務
  9. 監控、疑難排解與最佳實踐
  10. 水平擴展與容器編排思考
  11. 結語與後續拓展

1. 背景與核心概念

在現代 Web 開發裡,即時通知和資料同步成了不可或缺的需求。Laravel Reverb 作為官方推出的 WebSocket 伺服器,結合 Laravel 的事件廣播機制,能讓我們以最熟悉的方式編寫即時功能。

當我們將這些服務搬到 Docker 中,配合 Redis Pub/Sub,便能:

  • 將應用邏輯與即時通訊分離,易於維護
  • 利用 Redis 低延遲特性,確保訊息快速下發
  • 透過容器化實現規模彈性,支援水平擴展

2. 為何選擇 Redis 作為廣播驅動

Redis 在 Laravel 生態裡扮演多重角色,既能做快取、隊列,也能當事件廣播的中介。相較其他付費或第三方服務,Redis 具備:

比較項目RedisPusher / Ably 等第三方服務
延遲極低(記憶體內運算)取決網路與第三方伺服器負載
成本開源免費、資源自控依流量付費
容器友善官方輕量映像、快速啟動需額外設定憑證與金鑰管理
自主維運彈性調整叢集配置需信任第三方營運商
  • 高效能:Pub/Sub 機制原生支援即時廣播
  • 容器化:官方 Alpine 映像小巧、安全
  • 經濟實惠:無需支付額外流量費用

3. 整體服務架構圖

以下示意架構能幫助你完整理解各服務間的資料流向:

┌───────────┐      ┌───────────┐      ┌───────────┐
│  Client   │ <--> │   Nginx   │ <--> │   Reverb  │
│ (Browser) │      │  (Proxy)  │      │(WebSocket)│
└───────────┘      └───────────┘      └───────────┘
                                    ▲         │
                                    │         │ Redis Pub/Sub
                                    ▼         │
                              ┌───────────┐    │
                              │   Redis   │◀───┘
                              └───────────┘
                                    ▲
                                    │
                                    ▼
                              ┌───────────┐
                              │   App     │
                              │(PHP-FPM)  │
                              └───────────┘

4. Docker Compose 設定詳解

在專案根目錄新增 docker-compose.yml,如下所示。建議先建立對應的 Dockerfile 與 Nginx 設定,再一起啟動。

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: laravel-app:latest
    container_name: laravel-app
    restart: unless-stopped
    volumes:
      - .:/var/www/html
    environment:
      - APP_ENV=local
      - APP_URL=http://localhost
      - APP_KEY=${APP_KEY}
      - BROADCAST_CONNECTION=redis
      - CACHE_DRIVER=redis
      - QUEUE_CONNECTION=redis
      - SESSION_DRIVER=redis
      - REDIS_HOST=redis
      - REVERB_APP_KEY=${REVERB_APP_KEY}
      - REVERB_HOST=0.0.0.0
    depends_on:
      - redis
      - reverb

  redis:
    image: redis:alpine
    container_name: redis
    restart: unless-stopped
    ports:
      - "6379:6379"

  reverb:
    image: laravel-app:latest
    container_name: laravel-reverb
    restart: unless-stopped
    entrypoint:
      - /usr/local/bin/php
      - artisan
      - reverb:start
      - --host=0.0.0.0
    environment:
      - APP_ENV=local
      - APP_KEY=${APP_KEY}
      - REVERB_APP_KEY=${REVERB_APP_KEY}
      - REVERB_HOST=0.0.0.0
      - REDIS_HOST=redis
      - BROADCAST_CONNECTION=redis
    ports:
      - "9000:9000"
    depends_on:
      - redis
      - app

  nginx:
    image: nginx:alpine
    container_name: nginx
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - .:/var/www/html
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app

重點解析

  • app 服務:

    1. 使用共用映像,並掛載原始碼以便本地開發熱重載
    2. Laravel 的各項 driver 全指向 Redis
  • redis 服務:

    1. Alpine 映像快速輕量
    2. 對外開放 6379 埠口,方便本地監控
  • reverb 服務:

    1. 同 app 映像,減少重複建置
    2. 以 entrypoint 啟動 php artisan reverb:start
    3. 綁定到 0.0.0.0 讓 Nginx 或其他客戶端能夠存取
  • nginx 服務:

    1. 掛載專案並載入自訂配置
    2. 將 HTTP 與 WebSocket 代理到對應後端

5. Laravel 環境變數與設定

在專案根目錄的 .env 檔案中,加入/調整以下內容:

APP_ENV=local
APP_URL=http://localhost

BROADCAST_CONNECTION=redis
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis

REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379

REVERB_APP_KEY=your_reverb_app_key
REVERB_HOST=0.0.0.0
REVERB_PORT=9000
REVERB_SCHEME=http

再確認 config/broadcasting.phpconnections.reverb 區段中正確取用上述變數。


6. Nginx 反向代理設置

建立 docker/nginx/default.conf,並填入以下範本:

server {
    listen 80;
    server_name localhost;
    root /var/www/html/public;
    index index.php index.html;

    # WebSocket 反向代理至 Reverb
    location /app/ {
        proxy_pass http://reverb:9000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        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_read_timeout 86400s;
    }

    # PHP-FPM 處理所有 PHP 請求
    location ~ \.php$ {
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

7. 前端 JavaScript 與 Echo 配置

在前端程式碼中(例如使用 Vite 或 Mix),設定 Laravel Echo 與 Reverb 連線:

import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST,
    wsPort: import.meta.env.VITE_REVERB_PORT,
    wssPort: import.meta.env.VITE_REVERB_PORT,
    forceTLS: false,
    disableStats: true,
    enabledTransports: ['ws', 'wss'],
});

請在對應的 .env(前端用)或 .env.local 中,設置 VITE_REVERB_* 變數為 localhost 及實際埠號。


8. 啟動與驗證服務

在終端機執行:

docker-compose up -d --build
  • 使用 docker-compose ps 確認各服務狀態
  • 透過瀏覽器開啟 http://localhost
  • 在開發者工具的 Network → WS 面板檢查是否成功建立 ws://localhost/app/... 連線
  • 在 Laravel Tinker 或測試程式碼中,觸發事件廣播並檢視前端是否即時接收

9. 監控、疑難排解與最佳實踐

  • 日誌蒐集:
    • 使用 docker logs laravel-reverb 查看 Reverb 啟動訊息
    • 在 Laravel 中加上 Channel log,監控事件是否正常推送
  • 健康檢查:
    • 建議在 Docker Compose 或編排工具中,設定 healthcheck,定期以 curl http://reverb:9000/health 驗證服務存活
  • 超時與資源限制:
    • 在 Redis 容器上設定 maxmemory-policy 為 allkeys-lru,避免記憶體飽和
    • 適當調整 Reverb 排程參數與 worker 數量,以符合併發連線需求
  • 常見誤區:
    • 未將 REVERB_HOST 設為 0.0.0.0 或 Proxy host
    • Nginx 條件過濾錯誤,導致非 /app/ 的 WebSocket 請求被拒

10. 水平擴展與容器編排思考

當系統成長,單一主機無法負荷時,你可以:

  1. 多個 Reverb 實例,結合 Redis Cluster
  2. 使用 Kubernetes / Docker Swarm,針對 Reverb 與 App Pod 設定 HorizontalPodAutoscaler
  3. 在 Nginx 前層加入 Layer 7 Load Balancer(例如 Traefik、Envoy),動態管理 WebSocket 連線
  4. 持續整合監控堆疊(Prometheus + Grafana),收集每秒連線數、消息延遲與錯誤率

11. 結語與後續拓展

透過本文所述的 Docker 化部署,你能將 Laravel Reverb、Redis、WebSocket 與 Nginx 緊密整合,實現穩定、高效的即時通訊平台。接下來你可以:

  • 探索 SSL/TLS 配置,打造安全的 wss 連線
  • 整合前端框架(Vue、React)進一步封裝即時元件
  • 利用 Redis Streams 或 Kafka 等技術,實現更複雜的訊息排程

沒有留言:

張貼留言

📦 LogiFlow WMS:打造 SaaS 多租戶倉儲管理系統的技術實踐

📦 LogiFlow WMS:打造 SaaS 多租戶倉儲管理系統的技術實踐 在企業數位化的浪潮下,倉儲管理系統 (WMS) 不再只是單一公司的內部工具,而是需要支援 多租戶 (Multi-Tenant) 的 SaaS 架構。這意味著系統必須在共享基礎設施的同時,保有嚴格的資...