Understand file provider in Traefik 2

自从开始上传视频就不断有朋友让我综合的讲一下Traefik 2的各种设置。作为一个普通用户,由于不确定自己理解的是否正确我不太愿意去总结性的谈论这个产品,毕竟我的理解很有可能是错的。露怯还是次要,主要怕误导了别人就不好了。但是问的人多了我也就有了更想要了解一下这个产品的想法,最近小有心得,跟大家分享一下。

看过我之前视频的朋友可能还记得在我的静态设置traefik.yml的provider部分,我是这么写的。

1
2
3
4
5
6
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
file:
filename: /configurations/dynamic.yml

我的设置里使用docker和label来定义服务的routerservice,用file来定义middleware,两者结合相结合的方法来做设置。在官方的文档里面用户可以把routerservice以及middleare完全用docker或者file来实现。我个人认为如果全部使用docker的lable来设置,整个设置看起来比较杂乱。因此我的配置思路 一直是想方设法减少label的使用。使用file provider来定义routerservice以及middleare正好可以达到这个目的。

使用File provider之后大部分配置都是动态的。本文关注的点在于这些配置如何工作,也就不对配置本身做过多的讲解。本文的配置大部分需要各位根据自身需要补全才能使用。

下面开始:

配置准备

Static Configuration 的设置

在Static Configuration里面,我们需要定义entryPointsproviderentryPoints的设置可以参考我的配置provider方面,根据官方文档,我们可以使用单个文件或者在某个文件夹里面的多个配置文件。

Single File

1
2
3
4
providers:
file:
filename: /path/to/config/dynamic_conf.yml
watch: true

Directory

1
2
3
4
providers:
file:
directory: /path/to/config
watch: true

Dynamic configuration 的设置

接下来就让我们看看如何定义动态配置以取代label。

Single File

顾名思义就是把所有的配置都放在同一个文件里面。下面这个example我是在middleware官方页面找到的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# As YAML Configuration File
http:
routers:
router1:
service: myService
middlewares:
- "foo-add-prefix"
rule: "Host(`example.com`)"

middlewares:
foo-add-prefix:
addPrefix:
prefix: "/foo"

services:
service1:
loadBalancer:
servers:
- url: "http://127.0.0.1:80"

这个文件还是比较直观的,简单来说就是用户前往example.com的请求会连接到myService这个服务去,同时加上了foo-add-prefix这个middleware。

Directory

如果选择挂载directory,你可以使用多个文件分别对应不同的设置。比如说一个router.yml专门用来放router,一个middleware.yml专门放middleware等等。目录形式可以如下

1
2
3
4
5
6
7
8
9
|-- data
| |-- configurations
| | |-- middlewares.yml
| | |-- tls.yml
| | |-- router.yml
| | `-- services.yml
| |-- acme.json
| `-- traefik.yml
`-- docker-compose.yml

对于小网站来说,单个文件足以放下所有的内容。如果你有特别多的东西需要设置,还是建议把设置分开为不同的文件,这样查找起来比较方便。

配置实战

用file provider之后我们可以用docker把服务先运行起来,然后根据自己的需求动态地调整自己想使用的域名和middleware连接到服务。下面用一个Nginx的实例来讲解

Docker-Compose

可以看到我这里完全没有加任何的label。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
version: '3.7'

services:
nginx:
image: nginx:alpine
container_name: nginx
restart: always
volumes:
- ./public:/usr/share/nginx/html:ro
networks:
- proxy

networks:
proxy:
external: true

运行docker-compose up -d把container先生成,然后我们进行下一步。

Router

官方文档把router的rule讲解的非常清楚了。大部分时候我们用Host(`example.com`, ...)即可。如果需要指定服务到具体某个文件夹也可以写作Host(`example.com`, ...) && Path(`/traefik`)

1
2
3
4
5
6
7
http:
routers:
dashboard:
service: nginx-service
entryPoints:
- "websecure"
rule: "Host(`nginx.yourdomain`)"

对比一下我们原本用的label,我个人觉得上面的写法要更清楚一点。

1
2
3
4
5
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.nginx-secure.entrypoints=websecure"
- "traefik.http.routers.nginx-secure.rule=Host(`nginx.yourdomain`)"

Middleware

middleware在我之前文章和视频里面都着重使用过。无论是全局的secureHeaders,Bitwarden的bw-stripPrefix还是Traefik Dashboard的basicAuth我都是在文件里定义,然后拿来用即可。各位可能也注意到,我们在label里面使用文件定义的middleware的时候需要写成middleware名字@file这样的形式。在动态配置文件里使用middleware并不需要加上@file因为我们本来就在使用file provider。这里把我正在用的middleware贴出来各位自取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
http:
middlewares:
# 强制使用https,我加它只是为了ssllabs的A+ rating
secureHeaders:
headers:
sslRedirect: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
# Traefik Dashboard 需要的基本认证
# Username: Admin
# Password: qwer1234
user-auth:
basicAuth:
users:
- "admin:$apr1$tm53ra6x$FntXd6jcvxYM/YH0P2hcc1"
# 把根域名的traffic转到www
www-redirect:
redirectRegex:
regex: "^https://yourdomain/(.*)"
replacement: "https://www.yourdomain/${1}"
permanent: true

# 搭配Bitwarden Websocket使用
bw-stripPrefix:
stripPrefix:
prefixes:
- "/notifications/hub"
forceSlash: false

Service

service当初卡了我挺久,我一直没搞明白官方文档这里用的URL到底从哪儿来的。在使用label定义服务的时候,用户并不需要知道后台的url是多少,添加好label,traefik就会自动找到服务和我们router连在一起。

1
2
- "traefik.http.routers.nginx-secure.service=nginx-service"
- "traefik.http.services.nginx-service.loadbalancer.server.port=80"

甚至官方自己也说了:

In general when configuring a Traefik provider, a service assigned to one (or several) router(s) must be defined as well for the routing to be functional.
There are, however, exceptions when using label-based configurations:

  1. If a label defines a router (e.g. through a router Rule) and a label defines a service (e.g. implicitly through a loadbalancer server port value), but the router does not specify any service, then that service is automatically assigned to the router.
  2. If a label defines a router (e.g. through a router Rule) but no service is defined, then a service is automatically created and assigned to the router.

也就是说上面这两个label即使不加traefik也能创建并找到对应的服务。

那么在使用file provider的时候,我们应该如何找到服务对应的url(internal ip address)以及端口呢?我找到两个方法,第二个方法官方论坛不推荐,我写出来给作参考。

Docker Inspect

在我们开始了一个container之后,可以使用docker inspect <container_id>的方法看到这个container的ip地址是是多少。

  1. 我们先用docker ps查看所有运行的container。例如我们要看的Nginx的container id是41fb11d0047c

  2. 运行docker inspect 41fb11d0047c,可以看到一大堆的信息。我们看最后NetworkSettings这里。(一些多余的信息我就过滤掉了)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
          "NetworkSettings": {
    ...
    "Ports": {
    "80/tcp": null
    },
    ...
    "IPAddress": "192.168.48.4",
    ...
    }
    }
    }

    可以看到这个container的ip地址是192.168.48.4,端口是80,于是我们在file provider里面就可以把这个服务写成

    1
    2
    3
    4
    5
    6
    http:
    services:
    nginx-service:
    loadBalancer:
    servers:
    - url: "http://192.168.96.4:80"

    Add Docker as provider

    这个方法官方不推荐

  3. traefik.yml添加docker作为provider。(这就跟我之前的配置文件一致)

    1
    2
    3
    4
    5
    6
    providers:
    docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
    file:
    filename: /configurations/dynamic.yml
  4. 在Traefik Dashboard里面会自动监测生成的服务。这样我们就可以知道这个服务的ip地址了,如下图:
    nginx-service

我终于把我对使用file provider的浅薄理解写完了。各位有兴趣的可以尝试一下把自己的配置转成用file provider来写看看能不能成功。

接下来我需要找时间把对应的视频做出来,毕竟看视频比看文字直观多了。

咱们下期再会