はじめに

こんにちは。WebikeでエンジニアをしているHidekiです。
以前コンテナ化されたLaravelアプリケーションをTraefik環境下にデプロイするという案件があったので、Traefikの使い方についてお話しようと思います。

Traefikとは

traefikとは動的な設定が可能な、エッジルーター(ロードバランサー&リバースプロキシ)です。
オープンソースでGo言語で開発されています。
Traefik Labsというフランスの企業で開発されています。
ACMEクライアントなので、Let’s Encryptの無料SSL証明書を容易に取得することが可能です。

画像引用元: https://traefik.io/

構築してみる

今回構築する構成は下図の通りです。

画像引用: https://github.com/hdk-t/traefik-example

  • コンテナ管理にDocker Composeを使用する
  • リクエストパスに応じて各コンテナにリバースプロキシさせる
  • 3台のNginxコンテナはラウンドロビンでロードバランシングさせる

環境

  • Docker 20.10.17
  • Docker Compose 1.29.2

ディレクトリ構造

traefik-example
┣ gateway
┃ ┣ traefik
┃ ┃┣ access.log
┃ ┃┗ traefik.yml
┃ ┗ docker-compose.yml
┗ web
   ┗ docker-compose.yml

Traefikの設定について

traefikの設定方法は大きく2種類あります

  • 静的設定(Static Configuration)
    • 設定ファイルはyaml記法または、toml記法で記述します
    • 静的設定の変更にはコンテナの再起動が必要です
  • 動的設定(Dynamic Configuration)
    • 動的設定をする方法はいくつか存在します(Docker,設定ファイル,k8s etc..)
    • 設定ファイルで設定する場合は静的設定と同様にyaml記法または、toml記法で記述します
    • 動的設定の変更はコンテナの再起動を必要としません

今回は静的設定にyamlファイル、動的設定の方法にDockerを使用します。
Dockerを使用した動的設定の方法は、コンテナのラベルにTraefikの属性を付与することで設定できます。
Traefikは常に同じdocker networkのコンテナを監視しており、それらの変更や追加を検知することで動的設定を実現させています。

Traefikの静的設定

./gateway/traefik/traefik.yml

providers:
  docker:
    exposedByDefault: false
    network: proxy
    watch: true
entrypoints:
  http:
    address: ":80"
    forwardedHeaders:
      insecure: true
      trustedIPs:
        - "127.0.0.1/32"
        - "172.0.0.1/8"
        - "192.168.0.0/16"
api:
  dashboard: true
  insecure: false
log:
  level: INFO
experimental:
  http3: true
global:
  sendAnonymousUsage: false
accessLog:
  filePath: "/var/logs/access.log"
  bufferingsize: 100
  filters:
    statuscodes: 
      - "100-599"
    retryattempts: true
    minduration: "100ms"
  fields:
    names:
      StartUTC: drop

設定内容を要点だけ簡単に説明すると

providers: docker

dashboard: true

  • Traefikのダッシュボードを有効化
  • ベーシック認証を設定できるが、今回は検証なので設定しません

entrypoints: http

  • 今回はhttpポートのみ開放
  • httpsにする場合は同様に設定が必要
  • httpにアクセスが来たらhttpsにリダイレクトさせる設定を入れることもできる

Traefikコンテナのdocker-compose.yml(動的設定)

./gateway/docker-compose.yml

version: '3'
networks:
  traefik_example_network:
    external: true
services:
  traefik:
    image: traefik:v2.6.1
    restart: always
    environment:
      - TZ=Japan
    ports:
      - target: 80
        published: 80
        protocol: tcp 
        mode: host
    security_opt:
      - no-new-privileges:true
    networks:
      - traefik_example_network
    volumes:
      - ./logs:/var/logs
      - ./traefik:/etc/traefik
      - /var/run/docker.sock:/var/run/docker.sock:ro,cached
    labels:
      ### traefik configration
      - traefik.enable=true
      - traefik.http.routers.dashboard.rule=(Host(`traefik.localhost`))
      - traefik.http.routers.dashboard.service=api@internal

traefik.http.routers.dashboard.rule=(Host(`traefik.localhost`))
traefik.localhost のドメインでアクセスしてきたら、Traefikのダッシュボードにプロキシさせます。

    Webサーバーのdocker-compose.yml(動的設定)

    ./web/docker-compose.yml

    version: '3'
    networks:
      traefik_example_network:
        external: true
    services:
      nginx:
        image: nginx
        restart: always
        networks: 
          - traefik_example_network
        labels:
          ### traefik configration
          - traefik.enable=true
          - traefik.http.routers.nginx.rule=PathPrefix(`/nginx`)
          - traefik.http.services.nginx.loadbalancer.server.port=80
          - traefik.http.middlewares.nginx-omitprefix.stripprefix.prefixes=/nginx
          - traefik.http.routers.nginx.middlewares=nginx-omitprefix
      apache:
        image: httpd
        restart: always
        networks:
          - traefik_example_network
        labels:
          ### traefik configration
          - traefik.enable=true
          - traefik.http.routers.apache.rule=PathPrefix(`/apache`)
          - traefik.http.services.apache.loadbalancer.server.port=80
          - traefik.http.middlewares.apache-omitprefix.stripprefix.prefixes=/apache
          - traefik.http.routers.apache.middlewares=apache-omitprefix

    traefik.http.routers.nginx.rule=PathPrefix(`/nginx`)
    traefik.http.routers.apache.rule=PathPrefix(`/apache`)
    NginxとApacheも同様にプロキシさせる条件を設定します。

    コンテナの起動とスケールアップ

    設定ファイルの記述が完了したら、docker networkを作成して、コンテナを立ち上げます。

    ネットワークを作成

    docker network create traefik_example_network

    Traefikコンテナを起動

    docker-compose -f ./gateway/docker-compose.yml up -d

    ApatchとNginxを起動

    docker-compose -f ./web/docker-compose.yml up -d

    この時点で下記にアクセスできるハズです。
    ※ hostsでループバックアドレスにlocalhostが設定されてる前提です
    127.0.0.1  localhost

    traefikのダッシュボード
    http://traefik.localhost

    Nginx
    http://localhost/nginx

    Apache
    http://localhost/apache

    上記が確認できたら、Nginxを3台にスケールアップしてみましょう。

    docker-compose -f ./web/docker-compose.yml scale nginx=3

    これで、構成図の状態になりました。

    docker ps

    access.logを見るとNginxへのアクセスはラウンドロビンでロードバランシングされている事が確認できます。

    ./traefik/acccess.log

    さいごに

    このようにTraefikを使用することで簡単にリクエストを捌くことができました。
    サブドメインで振り分けられるのがとても便利ですね。
    使いどころとしては、1つのホストに複数のサービスコンテナを稼働させる際に便利です。
    また、動的設定を使用すれば設定変更時に再起動が不要のため、他のサービスのダウンタイム無しで設定変更を行うことが可能です。

    弊社では一部業務Webアプリケーションのリバースプロキシとして使用しています。
    ニッチな技術なのでググっても参考文献が見つかりにくいところがデメリットです。