Traefik 路由規則與負載均衡
Traefik 最強大的功能之一就是其靈活的路由系統。在 Docker 環境中,我們主要透過 Container Labels 來定義這些規則。
基本路由規則 (Matchers)
在深入各種匹配規則之前,我們先了解 Traefik 路由規則 (Rule) 的基本語法。
語法結構
Traefik 的路由規則是由 Matcher (匹配器) 和 Logical Operators (邏輯運算子) 組成的表達式:
- 基本格式:Matcher(`參數`)
- 例如:Host(`example.com`)
- 注意:參數建議使用 Backticks (反引號
`) 包裹,這在 TOML/YAML 設定檔中可以避免繁瑣的跳脫字元 (Escape) 問題。
- 邏輯運算:
&&(AND):同時符合。例如 Host(`example.com`) && PathPrefix(`/api`)||(OR):符合其中之一。例如 PathPrefix(`/api`) || PathPrefix(`/dashboard`)!(NOT):反向匹配。
- 優先級:使用括號
()來控制運算優先順序。- 例如:Host(`example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
Label 命名規則
除了規則內容的語法,我們也需要知道如何在 docker-compose.yml 的 labels 中定義它。Label 的 Key 遵循固定結構:
traefik.<protocol>.<type>.<name>.<property>
以 traefik.http.routers.my-app.rule 為例:
http: 協定。通常是http(HTTP/HTTPS) 或tcp。routers: 資源類型。常見的有routers(路由),services(服務),middlewares(中介軟體)。my-app: 資源名稱。這是由你自訂的 ID,但在同一類資源中必須是唯一的。rule: 屬性。這裡指我們要設定路由規則。
了解了這些語法後,我們來看最常用的幾種 Matcher。
Host 匹配 (Host)
除了我們看過的 Host(`example.com`),也支援萬用字元:
labels:
- 'traefik.http.routers.app.rule=Host(`*.example.com`)'
這會匹配 api.example.com, blog.example.com 等所有子網域。
路徑前綴匹配 (PathPrefix)
如果你希望根據網址的路徑來分流,例如 /api 給後端 A,/static 給後端 B:
# 服務 A
labels:
- "traefik.http.routers.service-a.rule=Host(`example.com`) && PathPrefix(`/api`)"
# 服務 B
labels:
- "traefik.http.routers.service-b.rule=Host(`example.com`) && PathPrefix(`/static`)"
注意:&& 代表 AND 邏輯運算。請求必須同時符合網域和路徑規則。
表頭匹配 (Headers)
你甚至可以根據 HTTP Header 來路由。這在做 API 版本控制或 A/B 測試時很有用。
labels:
- 'traefik.http.routers.app-v2.rule=Host(`api.example.com`) && Headers(`X-Api-Version`, `2`)'
這條規則只會匹配 X-Api-Version: 2 的請求。
負載平衡 (Load Balancing)
當你的後端服務需要擴展時,Traefik 會自動處理負載平衡。
自動發現副本 (Replicas)
如果你使用 Docker Compose 的 scale 指令擴展服務:
docker compose up -d --scale whoami=3
Traefik 會自動偵測到 whoami 服務現在有 3 個容器實例 (Container Instances),並自動將它們加入到 Load Balancer 的後端池中。
預設情況下,Traefik 使用 Weighted Round Robin (加權輪詢) 演算法。這意味著請求會依序分發給每個容器: 1 -> Container A 2 -> Container B 3 -> Container C 4 -> Container A ...
黏著會話 (Sticky Sessions)
有些應用程式 (例如舊版的 Java Web App 或依賴 PHP Session 的應用) 需要確保同一個使用者的請求總是連到同一個後端容器。這時你需要啟用 Sticky Session。
Traefik 使用 Cookie 來達成這個功能:
labels:
# 啟用 Sticky Session
- 'traefik.http.services.app.loadbalancer.sticky=true'
# 設定 Cookie 名稱
- 'traefik.http.services.app.loadbalancer.sticky.cookie.name=sticky_cookie'
# 設定 Cookie 安全屬性 (建議開啟 Secure 和 HTTPOnly)
- 'traefik.http.services.app.loadbalancer.sticky.cookie.secure=true'
- 'traefik.http.services.app.loadbalancer.sticky.cookie.httpOnly=true'
當啟用後,Traefik 會在第一個回應中寫入一個 Cookie,記錄這名使用者被分配到的容器 IP。後續帶有這個 Cookie 的請求都會被導向同一個容器。
權重 (Weights)
在 Docker Label 中設定權重比較少見,因為 Docker Compose 的副本通常是同質的。但在其他 Provider (如 File Provider) 中,你可以為不同的 Server 設定不同的權重,讓效能較好的伺服器處理更多請求。
# 在 File Provider 中設定權重範例 (非 Docker Label)
http:
services:
my-app:
loadBalancer:
servers:
- url: 'http://private-ip-server-1:80'
weight: 3 # 處理 3/4 的流量
- url: 'http://private-ip-server-2:80'
weight: 1 # 處理 1/4 的流量
掌握了這些路由技巧,你就能靈活地設計應用程式的流量入口。