Yungen's blog

traefik tutorial

前言

當我們在架設後端 service 的時候很常會遇到要將 service A 和 service B 放在同一個伺服器中運行,這時候會遇到一個問題:要如何設置 Endpoint 讓使用者能分別使用 service A 與 service B 呢?

簡單介紹 traefik

在 traefik 的官網中是如此介紹 traefik 的

Traefik is an open-source Edge Router that makes publishing your services a fun and easy experience.

traefik 的功能其實不只有 reverse proxy 而已,還有 load balancing 、 api gateway …等功能,本篇文章將 focus 在 reverse proxy 上。

與其他 reverse proxy 的區別

traefik 與其他 reverse proxy 軟體(例如: Nginx、HAProxy、Caddy …)最大的區別在於 traefik 在設置上能與 docker 緊密結合(Label Based,接下來會仔細說明)也能與許多環境配合(kubernetes ,docker swarm…)。

traefik 設置的架構

Configuration Discovery

在我們一般的認知中當我們要設置軟體時,通常會想到透過更改 config file 或透過 command line argument 去更改軟體設定,但 traefik 的設定比較複雜。在 traefik 中有所謂的 provider (例如:Docker, Kubernetes IngressRoute…),traefik 會透過這些 provider 去拿到設置的詳細資訊(當然也可透過 config file 或 command line 設定)。以下以 docker-compose 舉例:

example-docker-compose.yaml

1version: "3.8"
2
3services:
4  whoami:
5    image: "containous/whoami"
6    labels:
7      - "traefik.enable=true" # <- 注意這裏

當我們設置 traefik 使用 Docker 作為 provider 時,traefik 就會從 docker 抓取 container 資料,以上述 docker-compose 為例,當 traefik 發現有 container 的 labels 為 traefik.enable=true 時,就會認定該 container 需要用到 traefik 的功能,並根據其設定為該 container 開啟 traefik 的功能。

Routing & Load Balancing

EntryPoints

在設定所有的 routing 之前,我們必須先設定 traefik 的 entrypoint 。所有的 request 都會從 entrypoint 進入,再由 traefik 轉送到指定的 service 。以下以 traefik 的 static config file 為例:

traefik.yaml

1entryPoints:
2  web: # <- 這邊為使用者自己定義的名稱
3    address: ":80"
4  web2:
5		address: ":8080"

以上述的 config file 為例,若我們要發送 request 到伺服器,就必須發送到 <伺服器 IP>:<80><伺服器 IP>:<8080>

Routers

當 request 由 entrypoint 進入後要如何決定將其轉發到哪一個 service 就需要透過設定 Routers 解決。在設定 Router 時需要考慮以下幾點:

  1. EntryPoint: traefik 預設 router 會監聽每一個 entryPoint ,但我們也可以設定成指監聽某幾個 entryPoint 。以下範例我們設置一個 Router 名稱為 “myrouter” 並指定其 entryPoint 為 web2

    example-docker-compose.yaml

    1version: "3.8"
    2
    3services:
    4  whoami:
    5    image: "containous/whoami"
    6    labels:
    7      - "traefik.enable=true"
    8			- - "traefik.http.routers.myrouter.entrypoints=web2" # <- "myrouter" 為使用者自己定義的名稱
    
  2. Rule: traefik 會根據使用者設定的 rule 決定 request 會到哪一個 router 。以下範例我們設置一個 rule 只讓 host 名稱為 myserverdomainname.com 的 request 進到此 router 。

    example-docker-compose.yaml

    1version: "3.8"
    2
    3services:
    4  whoami:
    5    image: "containous/whoami"
    6    labels:
    7      - "traefik.enable=true"
    8		  - "traefik.http.routers.myrouter.entrypoints=web2"
    9			- "traefik.http.routers.myrouter.rule=Host(`myserverdomainname.com`)"
    

    以上範例為使用 Host() 來設置 rule ,其實還有許多方法 Method()Path()…,更多方法可以參考 官網

  3. Priority: 在設置 rule 時可能發生 request 同時滿足兩個 router 的 rule,這時後需要設定 Priority 才能決定 request 要轉送到哪個 router 。

  4. Middlewares: 我們可以針對 route 設定 middleware ,在 request 轉送到 service 之前對其處理,詳細的設置內容會在下一個章節提到。

  5. Service: 每一個 route 必須指定一個 service 作為目標,當 request 進到該 router 後會轉送到目標 service 。這時候你可能會想:為什麼需要一個 service 呢?直接將 router 目標指向某個 後端應用程式的 url 就好了啊?原因是 traefik 除了提供 reverse proxy 以外還有 LoadBalancer 的功能,透過接下來的範例能更清楚了解。

    在 traefik 中需要另外設置 service ,我們先以 config file 的形式再以 docker-compose 的設定方式能更了解 traefik 的 service 是如何運作的。

    以下為 config file 形式的 service 設定,其中我們設置一個名稱為 my-service 的 service

    traefik.yaml

    1http:
    2  services:
    3    my-service:
    4      loadBalancer:
    5        servers:
    6        - url: "<http://private-ip-server-1/>"
    7        - url: "<http://private-ip-server-2/>"
    

    從以上的 config file 可以知道當 request 從某個 router 轉送到 “my-service” 時有可能被轉送到 “http://private-ip-server-1/” 以及 “http://private-ip-server-2/” 而會轉送到哪一個 url 是根據 Round-robin 演算法。

    以下為 docker-compose 的設定,其中我們設置一個名稱為 my-service 的 service ,而這個 service 會與 container 的 port 80 連結。

    example-docker-compose.yaml

     1version: "3.8"
     2
     3services:
     4  whoami:
     5    image: "containous/whoami"
     6    labels:
     7      - "traefik.enable=true"
     8		  - "traefik.http.routers.myrouter.entrypoints=web2"
     9			- "traefik.http.routers.myrouter.rule=Host(`myserverdomainname.com`)"
    10			- "traefik.http.services.my-service.loadbalancer.server.port=80"
    

    從以上 docker-compose 可發現若我們使用 labels 設定 service , traefik 會自動將該 container 與設定的 service 連結,我們不需要像 config file 那樣設置 “url” 。

    最後我們需要將該 router 指向一個 service 。在以下範例我們設置 Router 名稱為 myrouter 指向一個名稱為 my-service 的 service

    example-docker-compose.yaml

     1version: "3.8"
     2
     3services:
     4  whoami:
     5    image: "containous/whoami"
     6    labels:
     7      - "traefik.enable=true"
     8		  - "traefik.http.routers.myrouter.entrypoints=web2"
     9			- "traefik.http.routers.myrouter.rule=Host(`myserverdomainname.com`)"
    10			- "traefik.http.services.my-service.loadbalancer.server.port=80"
    11			- "traefik.http.routers.myrouter.service=my-service"
    
  6. TLS: traefik 的功能也包含處理 HTTPS 連線,此設定較為複雜,可參考另一篇文章(未完成)。

Middlewares

當 request 進入 router 後,我們可以設置 middlewares 對 request 進行處理,再送到 service 。

以下範例我們設置一個名稱為 mymiddleware 的 middleware 並使用 traefik 內建的 ratelimit ,最後我們將 mymiddleware 加到 myrouter 中。

example-docker-compose.yaml

 1version: "3.8"
 2
 3services:
 4  whoami:
 5    image: "containous/whoami"
 6    labels:
 7      - "traefik.enable=true"
 8		  - "traefik.http.routers.myrouter.entrypoints=web2"
 9			- "traefik.http.routers.myrouter.rule=Host(`myserverdomainname.com`)"
10			- "traefik.http.services.my-service.loadbalancer.server.port=80"
11			- "traefik.http.routers.myrouter.service=my-service"
12		  - "traefik.http.middlewares.mymiddleware.ratelimit.average=100"
13      - "traefik.http.middlewares.mymiddleware.ratelimit.burst=30"
14      - "traefik.http.routers.myrouter.middlewares=mymiddleware"

traefik 設定範例

以下文章將會實際設定 traefik 作為 reverse proxy ,並會使用 whoamipodinfo 作為示範 container。

在開始教學前,請先確認你的環境滿足以下條件

本教學的伺服器環境為 debian bullseye docker 版本為 20.10.12 、 domain name 為 ainimal.io

建立 directory

首先我們建立一個 directory ,接下來的設定檔案都會放在這個 directory 裡面。

1mkdir traefik-example
2cd traefik-example

docker 環境設定

在設定 traefik 前我們必須建立一個 docker network ,以下範例我們建立一個名稱為 mynetwork 的 docker network 。

1docker network create mynetwork

traefik 必需與 container 存在於同一個 docker network 才能順利運行,我們會將此 docker network 在接下來的 docker-compose 中設定為預設 network。

建立 docker-compose 環境變數

traefik-example 目錄下建立一個 .env 檔案,將所有 docker-compose 環境變數儲存在其中。此步驟並非必須,但之後若要更改 docker-compose 中的一些參數會較方便。

.env

1MY_DOMAIN=ainimal.io
2DEFAULT_NETWORK=mynetwork

Traefik static configuration

traefik-example 目錄下建立一個 traefik.yaml 檔案。

我們通常會在此設置較為“靜態”的設定,以下範例我們設定其 entryPoints 與 providers

traefik.yaml

1entryPoints:
2  web:
3    address: ":80"
4
5providers:
6  docker:
7    endpoint: "unix:///var/run/docker.sock"
8    exposedByDefault: false

注意 exposedByDefault 設定,因為這裏設置為 false 所以如果有 container 需要使用到 traefik 的功能就必須設定該 container 的 label 為 "traefik.enable=true"

Docker-compose 設定

#Posts