想要為 Laravel 應用程式加入即時通訊功能,並確保在容器化環境中具備高效、可擴展的廣播機制?本文將帶你從理論基礎到實作細節,一步步在 Docker 環境裡整合 Laravel Reverb、Redis、WebSocket 及 Nginx,並補足常見的監控、疑難排解和擴展規劃。
目錄
- 背景與核心概念
- 為何選擇 Redis 作為廣播驅動
- 整體服務架構圖
- Docker Compose 設定詳解
- Laravel 環境變數與設定
- Nginx 反向代理設置
- 前端 JavaScript 與 Echo 配置
- 啟動與驗證服務
- 監控、疑難排解與最佳實踐
- 水平擴展與容器編排思考
- 結語與後續拓展
1. 背景與核心概念
在現代 Web 開發裡,即時通知和資料同步成了不可或缺的需求。Laravel Reverb 作為官方推出的 WebSocket 伺服器,結合 Laravel 的事件廣播機制,能讓我們以最熟悉的方式編寫即時功能。
當我們將這些服務搬到 Docker 中,配合 Redis Pub/Sub,便能:
- 將應用邏輯與即時通訊分離,易於維護
- 利用 Redis 低延遲特性,確保訊息快速下發
- 透過容器化實現規模彈性,支援水平擴展
2. 為何選擇 Redis 作為廣播驅動
Redis 在 Laravel 生態裡扮演多重角色,既能做快取、隊列,也能當事件廣播的中介。相較其他付費或第三方服務,Redis 具備:
| 比較項目 | Redis | Pusher / 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 服務:
- 使用共用映像,並掛載原始碼以便本地開發熱重載
- Laravel 的各項 driver 全指向 Redis
redis 服務:
- Alpine 映像快速輕量
- 對外開放 6379 埠口,方便本地監控
reverb 服務:
- 同 app 映像,減少重複建置
- 以 entrypoint 啟動
php artisan reverb:start - 綁定到 0.0.0.0 讓 Nginx 或其他客戶端能夠存取
nginx 服務:
- 掛載專案並載入自訂配置
- 將 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.php 在 connections.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驗證服務存活
- 建議在 Docker Compose 或編排工具中,設定
- 超時與資源限制:
- 在 Redis 容器上設定 maxmemory-policy 為
allkeys-lru,避免記憶體飽和 - 適當調整 Reverb 排程參數與 worker 數量,以符合併發連線需求
- 在 Redis 容器上設定 maxmemory-policy 為
- 常見誤區:
- 未將
REVERB_HOST設為0.0.0.0或 Proxy host - Nginx 條件過濾錯誤,導致非
/app/的 WebSocket 請求被拒
- 未將
10. 水平擴展與容器編排思考
當系統成長,單一主機無法負荷時,你可以:
- 多個 Reverb 實例,結合 Redis Cluster
- 使用 Kubernetes / Docker Swarm,針對 Reverb 與 App Pod 設定 HorizontalPodAutoscaler
- 在 Nginx 前層加入 Layer 7 Load Balancer(例如 Traefik、Envoy),動態管理 WebSocket 連線
- 持續整合監控堆疊(Prometheus + Grafana),收集每秒連線數、消息延遲與錯誤率
11. 結語與後續拓展
透過本文所述的 Docker 化部署,你能將 Laravel Reverb、Redis、WebSocket 與 Nginx 緊密整合,實現穩定、高效的即時通訊平台。接下來你可以:
- 探索 SSL/TLS 配置,打造安全的 wss 連線
- 整合前端框架(Vue、React)進一步封裝即時元件
- 利用 Redis Streams 或 Kafka 等技術,實現更複雜的訊息排程
沒有留言:
張貼留言