使用 Traefik 進行 HTTP 路由

簡介

在本地開發期間,經常需要執行多個 HTTP 服務。您可能同時擁有 API 和前端應用程式、用於模擬資料端點的 WireMock 服務,或是資料庫視覺化工具(例如 phpMyAdmin 或 pgAdmin)。在許多開發環境中,這些服務會暴露在不同的連接埠上,這不僅要求您記住哪個服務在哪個連接埠,還可能引入其他問題(例如 CORS)。

反向代理可以將此設定大幅簡化,它作為單一暴露服務,並根據請求 URL(按路徑或主機名稱)將請求路由到適當的服務。Traefik 是一個現代化的雲端原生反向代理和負載平衡器,讓多服務應用程式的開發與部署變得更簡單。本指南將向您展示如何將 Traefik 與 Docker 搭配使用,以提升您的開發環境。

在本指南中,您將學習如何:

  1. 使用 Docker 啟動 Traefik
  2. 設定路由規則以在兩個容器之間分配流量
  3. 在容器化開發環境中使用 Traefik
  4. 使用 Traefik 將請求發送到非容器化工作負載

先決條件

若要跟隨本操作指南,需要具備以下先決條件:

在 Docker 中使用 Traefik

Traefik 的獨特功能之一是其多樣化的配置方式。當使用 Docker 提供者時,Traefik 會透過標籤 (labels) 從其他執行中的容器獲取設定。Traefik 會監控引擎事件(容器的啟動與停止),提取標籤,並更新其配置。

雖然有許多 Traefik 監控的標籤,但最常用的兩個是:

讓我們快速示範如何啟動 Traefik,然後配置兩個額外的容器,使其能夠使用不同的主機名稱進行存取。

  1. 為了讓兩個容器能夠互相通訊,它們需要位於同一個網路中。請使用 docker network create 指令建立一個名為 traefik-demo 的網路

    $ docker network create traefik-demo
    
  2. 使用下列指令啟動 Traefik 容器。該指令會在 80 埠暴露 Traefik,掛載 Docker socket(用於監控容器以更新配置),並傳遞 --providers.docker 參數來配置 Traefik 使用 Docker 提供者。

    $ docker run -d --network=traefik-demo -p 80:80 -v /var/run/docker.sock:/var/run/docker.sock traefik:v3.1.2 --providers.docker
    
  3. 現在,啟動一個簡單的 Nginx 容器,並定義 Traefik 要監控的標籤以配置 HTTP 路由。請注意,Nginx 容器沒有暴露任何連接埠。

    $ docker run -d --network=traefik-demo --label 'traefik.http.routers.nginx.rule=Host(`nginx.localhost`)' nginx
    

    容器啟動後,請在瀏覽器開啟 http://nginx.localhost 查看應用程式(所有基於 Chromium 的瀏覽器都會在本地路由 *.localhost 請求,無需額外設定)。

  4. 啟動第二個將使用不同主機名稱的應用程式。

    $ docker run -d --network=traefik-demo --label 'traefik.http.routers.welcome.rule=Host(`welcome.localhost`)' docker/welcome-to-docker
    

    容器啟動後,請在瀏覽器開啟 http://welcome.localhost。您應該會看到一個「Welcome to Docker」網站。

在開發環境中使用 Traefik

現在您已經體驗過 Traefik,是時候嘗試在開發環境中使用它了。在這個範例中,您將使用一個具有分離前端與後端的範例應用程式。此應用程式堆疊具有以下配置:

  1. 所有對 /api 的請求都轉發到 API 服務
  2. 所有對 localhost 的其他請求都轉發到前端用戶端
  3. 由於應用程式使用 MySQL,db.localhost 應提供 phpMyAdmin,以便在開發期間輕鬆存取資料庫
Architecture diagram showing Traefik routing requests to other containers based on the path of the request

該應用程式可在 GitHub 上存取:dockersamples/easy-http-routing-with-traefik

  1. compose.yaml 檔案中,Traefik 使用了以下配置:

    services:
      proxy:
        image: traefik:v3.1.2
        command: --providers.docker
        ports:
          - 80:80
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock

    請注意,這基本上與之前使用的配置相同,但現在改用了 Compose 語法。

  2. client 服務具有以下配置,它將啟動容器並為其提供標籤,以在 localhost 接收請求。

    services:
      # …
      client:
        image: nginx:alpine
        volumes:
          - "./client:/usr/share/nginx/html"
        labels:
          traefik.http.routers.client.rule: "Host(`localhost`)"
  3. api 服務具有類似的配置,但您會注意到路由規則有兩個條件:主機必須是「localhost」,且 URL 路徑必須有「/api」前綴。由於此規則更具體,Traefik 會優先於 client 規則進行評估。

    services:
      # …
      api:
        build: ./dev/api
        volumes:
          - "./api:/var/www/html/api"
        labels:
          traefik.http.routers.api.rule: "Host(`localhost`) && PathPrefix(`/api`)"
  4. 最後,phpmyadmin 服務配置為接收主機名稱「db.localhost」的請求。該服務還定義了環境變數以自動登入,使存取應用程式變得稍微簡單一些。

    services:
      # …
      phpmyadmin:
        image: phpmyadmin:5.2.1
        labels:
          traefik.http.routers.db.rule: "Host(`db.localhost`)"
        environment:
          PMA_USER: root
          PMA_PASSWORD: password
  5. 在啟動堆疊之前,如果 Nginx 容器仍在執行,請先將其停止。

就這麼簡單。現在,您只需要使用 docker compose up 啟動 Compose 堆疊,所有的服務與應用程式就已準備好進行開發了。

將流量發送到非容器化工作負載

在某些情況下,您可能希望將請求轉發到未在容器中執行的應用程式。在下方的架構圖中,使用了與之前相同的應用程式,但 API 和 React 應用程式現在是在主機上原生執行。

An architecture diagram showing several components and the routing between them. Traefik is able to send requests to both non-containerized and containerized workloads

為實現這一點,Traefik 需要使用另一種方法來進行自我配置。檔案提供者 (File provider) 允許您在 YAML 文件中定義路由規則。這是一個範例檔案:

http:
  routers:
    native-api:
      rule: "Host(`localhost`) && PathPrefix(`/api`)"
      service: native-api
    native-client:
      rule: "Host(`localhost`)"
      service: native-client

  services:
    native-api:
      loadBalancer:
        servers:
          - url: "http://host.docker.internal:3000/"
    native-client:
      loadBalancer:
        servers:
          - url: "http://host.docker.internal:5173/"

此配置表示對 localhost/api 的請求將被轉發到名為 native-api 的服務,然後該服務會將請求轉發到 http://host.docker.internal:3000。主機名稱 host.docker.internal 是 Docker Desktop 提供的一個名稱,用於將請求發送到主機。

有了這個檔案,唯一的更改是 Traefik 的 Compose 配置。具體有兩處變動:

  1. 配置文件被掛載到 Traefik 容器中(確切的目標路徑由您決定)
  2. command 已更新,加入了檔案提供者並指向配置文件的位置
services:
  proxy:
    image: traefik:v3.1.2
    command: --providers.docker --providers.file.filename=/config/traefik-config.yaml --api.insecure
    ports:
      - 80:80
      - 8080:8080
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./dev/traefik-config.yaml:/config/traefik-config.yaml

啟動範例應用程式

要執行將請求從 Traefik 轉發到原生執行應用程式的範例應用程式,請依照下列步驟操作:

  1. 如果您還有正在執行的 Compose 堆疊,請使用以下指令停止它:

    $ docker compose down
    
  2. 使用提供的 compose-native.yaml 檔案啟動應用程式:

    $ docker compose -f compose-native.yaml up
    

    開啟 https:// 將會回傳 502 Bad Gateway,因為其他應用程式尚未執行。

  3. 透過執行下列步驟啟動 API:

    cd api
    yarn install
    yarn dev
    
  4. 在新的終端機中(從專案根目錄開始)執行下列步驟以啟動前端:

    cd client
    yarn install
    yarn dev
    
  5. https:// 開啟應用程式。您應該會看到一個應用程式,它從 https:///api/messages 獲取訊息。您也可以開啟 http://db.localhost 直接從 Mongo 資料庫檢視或調整可用的訊息。Traefik 將確保請求正確地路由到適當的容器或應用程式。

  6. 完成後,執行 docker compose down 停止容器,並按下 ctrl+c 停止 Yarn 應用程式。

重點回顧

執行多個服務不需要複雜的連接埠配置和良好的記憶力。有了像 Traefik 這樣的工具,無論是應用程式本身(如前端和後端)還是額外的開發工具(如 phpMyAdmin),都可以輕鬆啟動並方便地存取。

© . This site is unofficial and not affiliated with Kubernetes or Docker Inc.