Open6

traefik の tips

kiaikiai

traefik

Traefik is an open-source Edge Router that makes publishing your services a fun and easy experience. It receives requests on behalf of your system and finds out which components are responsible for handling them.

Nginx や Apache2 の集合知・暗黙知的な堆積にほとほと嫌気が差した.きちんとドキュメントが整備されているOSSこそ広く使われるべきである.

kiaikiai

traefik が向かない環境はある

自分の環境が特殊だからかも知れないが,

  1. 80番ポートが既に埋まっている
  2. 別のリバースプロキシの下流に置く
  3. traefik からみた上流がサブドメインではなく「メインドメインのパス」になっている

上記の場合は採用を避けたほうが無難であると思う.どうにかしようと5日ほど頑張ってみたが,今の私の経験ではうまくいかなかった.

上記の条件があるとき,ルーティングのルールを工夫したり,ミドルウェアを定義して適宜調整したりする必要が増える.これは traefik の手軽さを自ら殺す行為であり,まず触ってみようという段階で手を出すべきではない(心が折れるので).

traefik が向いている環境もある

全部自分で管理できる環境であれば,積極的に採用すべきと思う.すなわち 80番を traefik に割り当てることが出来て,大元のリバースプロキシは traefik が担い,メインドメインをそのまま使えるのなら,ということである.

これは単に個人のVPS環境ということだけでなく,ローカル環境の開発でもっとも生きるということである.例えばルーティングのルールを Host(`subdomain.${HOSTNAME}`) にして,環境変数に HOSTNAME=localhost としておけば,http://subdomain.localhost でアクセスできるようになる.いちいちポート番号を打ち込む必要はないし,server.loadbalancer=${POST_NUMBER} とすればポート番号も環境変数経由で外部から決定することが出来る.もちろんプロダクション環境においては,この HOSTNAME を置き換えればいいだけである.

kiaikiai

PathPrefix solution

docker-compose.yml
labels:
    - traefik.http.middlewares.strip-prefix.chain.middlewares=strip-prefix-1,strip-prefix-2
    - traefik.http.middlewares.strip-prefix-1.redirectregex.regex=^(https?://[^/]+/[a-z0-9_]+)$$
    - traefik.http.middlewares.strip-prefix-1.redirectregex.replacement=$${1}/
    - traefik.http.middlewares.strip-prefix-1.redirectregex.permanent=true
    - traefik.http.middlewares.strip-prefix-2.stripprefixregex.regex=/[a-z0-9_]+

cf. 【魚拓】Middleware to add the "/" if needed - Traefik / Traefik v2 - Traefik Labs Community Forum

補足

ルーティングの rulePathPrefix にしている際に,末尾のスラッシュ(trailing slash)を落とすとコンテナに繋がらないことがある.これを繋がるはずのパスへリダイレクトさせて解決する(strip-prefix-1).また,コンテナ内ではルートパス / を期待しているのに,実際には /router-x のようなパスで降ってくることになる.よってこれを取り除いてからコンテナ内部とつなぐ(strip-prefix-2).

上記の工程は EntryPoint で受け取ってからコンテナに渡すまでの中間的な処理であるが,これを担うのが middlewares である.特に今回のように複数個のミドルウェアを使用する場合には,chain という処理も走ることになる.

kiaikiai

traefik の使い方 in Docker

  1. traefik コンテナを用意する(Nginxコンテナのようにリバースプロキシとしてつかう)
  2. コンテナ内に traefik.toml を用意して,「プロバイダとしてDockerを使う」という設定を仕込む(静的設定)
  3. ルーティングしたいアプリケーションコンテナにラベルを付ける(動的設定)

Configuration IntroductionConfiguration in Traefik can refer to two different things

Docker-compose basic example

以下のサンプルのように,実は静的設定として traefik.toml をマウントする必要はないのだが,そうすると代わりに docker-compose.yml に長々とラベルを付けることになってしまう.動的に変更されないものはなるべく静的設定として traefik.toml に書いたほうがいいように思う.

cf. https://doc.traefik.io/traefik/user-guides/docker-compose/basic-example/

docker-compose.yml
version: "3.3"

services:

  traefik:
    image: "traefik:v2.4"
    container_name: "traefik"
    command:
      #- "--log.level=DEBUG"
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"

  whoami:
    image: "traefik/whoami"
    container_name: "simple-service"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
      - "traefik.http.routers.whoami.entrypoints=web"
kiaikiai

ルーティングに関する tips

許されるならば,各アプリケーションコンテナごとに新たなサブドメインを割り振ってやるのがよい.これはローカルで開発する際に ttp://traefik.localhost のように簡単にアクセスできるようになることを意味する.アドレスバーにポート番号を打ち込む時代は終わったってワケ(笑)

基本的には,

  1. エントリーポイント=コンテナ外部からアクセスするときのポート番号を定義する
  2. コンテナ内の何番ポートとつなぐのか traefik コンテナ(ロードバランサ)に伝える
  3. どのようなルーティングにするのかルールを決める

だけラベル付けしてやればよい.

labels:
      - "traefik.enable=true" # due to `exposedByDefault=false`
      - "traefik.http.routers.my-service.entrypoints=web"                           # 1. define EntryPoint
      - "traefik.http.services.my-service.loadbalancer.server.port=${PORT_NUMBER}"  # 2. define server port
      - "traefik.http.routers.my-service.rule=Host(`traefik.${HOSTNAME}`)"          # 3. define routing

ここで my-service とは,docker-compose.yml のトップレベルでも定義されている services 以下の名前である(e.g. db, app, redis etc.).