Traefik v2 + Docker でサブディレクトリによるリバースプロキシを構成する例

#概要
Traefik v2で受けたリクエストを各Dockerコンテナにリバースプロキシする設定の例です。
URLのサブディレクトリに当たる部分を見て各コンテナにリクエストを振り分けます。

# Docker Composeファイル
```yaml
version: '3.7'
services:
  traefik:
    image: traefik:v2.0.6
    ports:
      - "${FRONT_HTTP_PORT:-80}:80"
      # - "${TRAEFIK_PORT:-8080}:8080"
    environment: 
      # - TRAEFIK_LOG_LEVEL=DEBUG
      - TRAEFIK_PROVIDERS_DOCKER_EXPOSEDBYDEFAULT=false
      - TRAEFIK_PROVIDERS_DOCKER=true
      - TRAEFIK_PROVIDERS_DOCKER_NETWORK=traefik01
      # - TRAEFIK_API_INSECURE=true
      - TRAEFIK_ENTRYPOINTS_FRONT=true
      - TRAEFIK_ENTRYPOINTS_FRONT_ADDRESS=:${FRONT_HTTP_PORT:-80}
    networks:
      - traefik01
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    security_opt:
      - label:type:docker_t
  app1:
    image: nginx:1.17.6-alpine
    expose:
      - 80
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app1.entrypoints=front"
      - "traefik.http.routers.app1.rule=PathPrefix(`/app1{regex:$$|/.*}`)"
      - "traefik.http.routers.app1.middlewares=app1-stripprefix"
      - "traefik.http.middlewares.app1-stripprefix.stripprefix.prefixes=/app1"
    networks:
      - traefik01
  app2:
    image: httpd:2.4.41-alpine
    expose:
      - 80
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.app2.entrypoints=front"
      - "traefik.http.routers.app2.rule=PathPrefix(`/app2{regex:$$|/.*}`)"
      - "traefik.http.routers.app2.middlewares=app2-stripprefix"
      - "traefik.http.middlewares.app2-stripprefix.stripprefix.prefixes=/app2"
    networks:
      - traefik01
networks:
  traefik01:
    driver: bridge
```

# 説明

以下、大雑把な説明です。

## 処理の流れ
Trafikでは通常 エントリーポイント -> ルーター -> ミドルウェア -> サービス の順でリクエストが処理されてゆきます。

## 構成要素

- エントリーポイント: Traefikへの入り口。アドレスとポート番号を設定します。ここではポート番号のみ指定しています。
- ルーター: 条件に従ってリクエストを各サービスに振り分けます。
- ミドルウェア: バックエンドサービスにリクエストを渡す前にリクエストの編集等(例: パスの書き換え)を行います。
- サービス: バックエンドのサービスです。ここでは各Dockerコンテナがそれです。

## エントリーポイントの設定

```yaml
TRAEFIK_ENTRYPOINTS_FRONT_ADDRESS=:${FRONT_HTTP_PORT:-80}
```
上の行は、frontと言う名前のエントリーポイントを定義し、80番ポートをリッスンするように指定しています。
なお、環境変数で定義する際は大文字でFRONTと書きますが、Traefik上は小文字のfrontとして扱われるようです。

## ルーターの設定


```yaml
- "traefik.http.routers.app1.entrypoints=front"
```

上の行は、ルーターをapp1と言う名前で定義し、エントリーポイントとルーターを関連付けています。

```yaml
- "traefik.http.routers.app1.rule=PathPrefix(`/app1{regex:$$|/.*}`)"
```
上の行は、ルーターをapp1と言う名前で定義し、リクエストパスの先頭が/app1, app1/, app1/〇〇の場合マッチするように指定しています。
マッチした場合、そのルールが書かれているコンテナにルーティングされます。

## ミドルウェアの設定
```yaml
- "traefik.http.middlewares.app1-stripprefix.stripprefix.prefixes=/app1"
```
上の行は、stripprefixと言うミドルウェアをapp1-stripprefixと言う名前で定義し、バックエンドのサービスにリクエストを行う前にリクエストパスの先頭の/app1を取り除くように指定しています。

## ルーターとミドルウェアの接続
```yaml
- "traefik.http.routers.app1.middlewares=app1-stripprefix"
```
上の行は、ルーターapp1とミドルウェア app1-stripprefix を接続するように指定しています。

# 動作確認
## コンテナの起動

コンテナを起動します。

```console
$ cd /path/to/compose-file
$ docker-compose up --detach
$ docker-compose ps
```
## ウェブブラウザでアクセス

### app1
    
ウェブブラウザで http://0.0.0.0:80/app1 にアクセスし、以下のように表示されればOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260137/dc36d392-f37f-1ca3-ef6c-9d2539f2d82c.png)


### app2

ウェブブラウザで http://0.0.0.0:80/app2 にアクセスし、以下のように表示されればOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260137/a61850b2-8ce3-8fd0-847f-77d8dfd83f24.png)

# 参考
Traefik公式サイト: https://docs.traefik.io/