使用 Traefik 進行 HTTP 路由

引言

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

透過充當唯一的暴露服務,然後根據請求 URL(透過路徑或主機名)將請求路由到適當的服務,反向代理可以極大地簡化此設定。Traefik 是一個現代的雲原生反向代理和負載均衡器,它可以使開發和部署多服務應用程式變得更加容易。本指南將向您展示如何將 Traefik 與 Docker 配合使用來增強您的開發環境。

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

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

先決條件

按照本操作指南進行操作需要滿足以下先決條件

將 Traefik 與 Docker 配合使用

Traefik 的獨特功能之一是它可以透過多種方式進行配置。當使用 Docker 提供程式時,Traefik 使用 labels... 從其他正在執行的容器獲取其配置。Traefik 會監聽引擎事件(用於容器啟動和停止),提取 labels,並更新其配置。

雖然有 許多 Traefik 監控的 labels...,但最常用的兩個是

我們來快速演示如何啟動 Traefik,然後配置另外兩個容器,使其可以使用不同的主機名進行訪問。

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

    $ docker network create traefik-demo
    
  2. 使用以下命令啟動一個 Traefik 容器。該命令將 Traefik 暴露在埠 80,掛載 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 路由的 labels。請注意,此 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...。您應該會看到一個“歡迎使用 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. 客戶端服務具有以下配置,它將啟動容器併為其提供 labels,以便在 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 將優先於客戶端規則對其進行評估。

    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 命令更新為新增 file provider 並指向配置檔案的位置
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)。

頁面選項