概念
让我们回顾一下在 概览 举的例子:
假设你已经在你的基础设施上部署了一堆微服务。你可能使用了一个服务发现系统(例如 etcd 或 consul)或者一个资源管理框架(swarm,Mesos/Marathon)来管理所有这些服务。 如果你想让你的用户去从互联网访问你的某些微服务, 你就必需使用虚拟hosts或前缀路径来配置一个反向代理:
- 域名
api.domain.com
将指向你的私有网络中的微服务api
- 路径
domain.com/web
将指向你的私有网络中的微服务web
- 域名
backoffice.domain.com
将指向你的私有网络中的微服务backoffice
,在你的多台实例之间负载均衡
我们将Træfɪk放大,一起看看它内部的结构:
- 请求在入口点处结束, 顾名思义, 它们是Træfɪk的网络入口(监听端口, SSL, 流量重定向...)。
- 之后流量会导向一个匹配的前端。 前端是定义入口点 到 后端之间的路由的地方。
路由是通过请求字段(
Host
,Path
,Headers
...) 来定义的,它可以匹配或否定一个请求。 - 前端 将会把请求发送到 后端。后端可以由一台或一个通过负载均衡策略配置后的多台服务器组成。
- 最后, 服务器 将转发请求到对应私有网络的微服务当中去。
入口点
入口点是是Træfɪk的网络入口。 它们可以通过以下方式来定义:
- 一个端口 (80, 443...)
- SSL (证书, 密钥, 由受信任的CA签名的客户端证书的身份验证...)
- 重定向到其他的入口点 (重定向
HTTP
到HTTPS
)
这里有一个入口点定义的例子:
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
[[entryPoints.https.tls.certificates]]
certFile = "tests/traefik.crt"
keyFile = "tests/traefik.key"
- 这里定义了两个入口点,
http
和https
. http
监听80
端口,https
监听443
端口- 我们通过提供一个证书和一个密钥在
https
中开启SSL。 - 并且我们转发所有的
http
入口点请求到https
入口点。
这里还有一个证书身份验证的例子:
[entryPoints]
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]
clientCAFiles = ["tests/clientca1.crt", "tests/clientca2.crt"]
[[entryPoints.https.tls.certificates]]
certFile = "tests/traefik.crt"
keyFile = "tests/traefik.key"
- 我们通过提供一个证书和一个密钥在
https
中开启SSL。 - 添加了一个或多个包含证书身份验证的PEM格式文件
- 多个CA签名仔同一个文件或多个独立文件都是允许的。
前端
前端是入口流量从入口点转发到后端的一组规则。 前端可以通过以下规则定义:
Headers: Content-Type, application/json
: 通过 Headers 可以添加一个匹配规则来匹配请求头部包含的值。它接受要匹配的键/值对序列。HeadersRegexp: Content-Type, application/(text|json)
: 也可以在 Headers 中使用正则表达式。它接受要匹配的键/值对序列,序列内容解析是通过正则匹配的。Host: traefik.io, www.traefik.io
: 匹配请求 Host 必需在给定域名列表内。HostRegexp: traefik.io, {subdomain:[a-z]+}.traefik.io
: 添加匹配请求 Host 的正则表达式。 它接受一个以{}
包括起来的为空或更多url变量的模版。变量的值可以以一个可选的正则表达式来匹配。Method: GET, POST, PUT
: Method 可以添加一个HTTP请求方法的匹配。它接受要匹配的一个或多个请求方法序列。Path: /products/, /articles/{category}/{id:[0-9]+}
: Path 可以添加一个URL路径的匹配。它接受一个以{}
包括起来的为空或更多url变量的模版。PathStrip
: 和Path
相同,但从请求的URL路径中去掉的给定的前缀。PathPrefix
: PathPrefix 可以添加一个URL路径前缀的匹配。它匹配给定模版中的完整URL路径前缀。PathPrefixStrip
: 和PathPrefix
相同,但从请求的URL路径中去掉的给定的前缀。AddPrefix
: 为请求URL路径天假前缀。
你可以为一条规则添加多个值,通过用 ,
分隔开。
你可以使用多条规则,通过用 ;
分隔开。
你可以选择启用 passHostHeader
来转发客户端请求Header中的 Host
字段到后端
这里有一个前端定义的例子:
[frontends]
[frontends.frontend1]
backend = "backend2"
[frontends.frontend1.routes.test_1]
rule = "Host:test.localhost,test2.localhost"
[frontends.frontend2]
backend = "backend1"
passHostHeader = true
priority = 10
entrypoints = ["https"] # overrides defaultEntryPoints
[frontends.frontend2.routes.test_1]
rule = "HostRegexp:localhost,{subdomain:[a-z]+}.localhost"
[frontends.frontend3]
backend = "backend2"
[frontends.frontend3.routes.test_1]
rule = "Host:test3.localhost;Path:/test"
- 这里定义了3个前端:
frontend1
,frontend2
和frontend3
- 当规则
Host:test.localhost,test2.localhost
匹配时frontend1
将把流量转发到backend2
- 当规则
Host:localhost,{subdomain:[a-z]+}.localhost
匹配时frontend2
将把流量转发到backend1
(转发客户端Header中的Host
字段到后端) - 当规则
Host:test3.localhost
与Path:/test
同时匹配时frontend3
将把流量转发到backend2
合并多条规则
正如上面例子中所展示的,你可以合并多条规则。 在TOML文件中,你可以使用多条路由:
[frontends.frontend3]
backend = "backend2"
[frontends.frontend3.routes.test_1]
rule = "Host:test3.localhost"
[frontends.frontend3.routes.test_2]
rule = "Path:/test"
这里,当规则Host:test3.localhost
与 Path:/test
同时匹配时 frontend3
将把流量转发到 backend2
。
或者你也可以使用 ;
符号来分隔,结果是相同的:
[frontends.frontend3]
backend = "backend2"
[frontends.frontend3.routes.test_1]
rule = "Host:test3.localhost;Path:/test"
最后,你可以使用 ,
符号分隔规则,为一个前端创建一个规则来绑定多个域名或路径:
[frontends.frontend2]
[frontends.frontend2.routes.test_1]
rule = "Host:test1.localhost,test2.localhost"
[frontends.frontend3]
backend = "backend2"
[frontends.frontend3.routes.test_1]
rule = "Path:/test1,/test2"
优先级
默认情况下,路由会以规则长度(为了防止部分重叠情况)被排序(倒序):
PathPrefix:/12345
将会比 PathPrefix:/1234
优先被匹配到,最后才会匹配到 PathPrefix:/1
。
你可以在前端自定义优先级:
[frontends]
[frontends.frontend1]
backend = "backend1"
priority = 10
passHostHeader = true
[frontends.frontend1.routes.test_1]
rule = "PathPrefix:/to"
[frontends.frontend2]
priority = 5
backend = "backend2"
passHostHeader = true
[frontends.frontend2.routes.test_1]
rule = "PathPrefix:/toto"
这里,frontend1
将会比 frontend2
优先被匹配(因为10 > 5
).
后端
后端用来负责将来自一个或多个前端的流量负载均衡到一组http服务器上。 这里支持多种负载均衡方法:
wrr
: 加权轮询drr
: 动态轮询: 这会为表现比其他服务器好的服务器增加权重。当服务器表现有变化的时,它也会会退到正常权重。
断路器也可以应用到后端,用于防止故障服务器上的高负载。 初始化状态是Standby。断路器只观察统计信息但并不修改请求。 当断路条件匹配时,断路器进入Tripped状态,它会返回与定义的http状态码或转发到其他前端。 一旦Tripped状态计时器超时,断路器会进入Recovering状态并重置所有统计数据。 当短路条件不匹配并且Recovery状态计时器超时时,断路器进入Standby状态。
它可以通过配置:
- 方法:
LatencyAtQuantileMS
,NetworkErrorRatio
,ResponseCodeRatio
- 操作符:
AND
,OR
,EQ
,NEQ
,LT
,LE
,GT
,GE
举个例子:
NetworkErrorRatio() > 0.5
: 监控网络故障率大于0.5超过10秒后,为这个前端平滑切换,断路条件匹配LatencyAtQuantileMS(50.0) > 50
: 监控延迟超过50ms时断路条件匹配ResponseCodeRatio(500, 600, 0, 600) > 0.5
: 监控返回HTTP状态码在[500-600]之间的数量/HTTP状态码在[0-600]之间的数量
的比例大于0.5时,断路条件匹配
为了主动防治后端被高负载压垮,可以为每个后端设置最大连接数限制。
最大连接数限制可以通过为maxconn.amount
配置一个整型值,同时
maxconn.extractorfunc
是用来配置通过什么样的维度来统计最大连接数。"例如下面例子中通过请求中host来统计连接数"
例如:
[backends]
[backends.backend1]
[backends.backend1.maxconn]
amount = 10
extractorfunc = "request.host"
- 当已经有10个请求是同一个Host Header时,下一个请求
backend1
将返回HTTP code 429 Too Many Requests
。 - 另外一个可可行的
extractorfunc
维度配置是client.ip
,它将通过统计客户端请求IP来统计连接数。 - 其实
extractorfunc
可以设置request.header.ANY_HEADER
中的任意维度,它将以你提供的ANY_HEADER
任意维度来统计连接数。
所有的负载平衡器都支持粘滞会话(sticky sessions)。当粘滞会话被开启时,会有一个名称叫做_TRAEFIK_BACKEND
的cookie在请求被初始化时被设置在请求初始化时。在随后的请求中,客户端会被直接转发到这个cookie中存储的后端(当然它要是健康可用的),如果这个后端不可用,将会指定一个新的后端。
例如:
[backends]
[backends.backend1]
[backends.backend1.loadbalancer]
sticky = true
服务器健康检查也是可配置的,当Traefik定期执行HTTP GET请求到后端时,后端返回的HTTP状态码不是200 OK,那么这个后端将被从负载均衡轮询列表中移除。健康检查可以以一个在后端URL后附加路径的路径地址与一个时间间隔 (以 time.ParseDuration 所识别的格式给出) specifying how 配置多久健康检查应该执行一次 (默认30秒). 每个后端必需在5秒内回应健康检查。
当一个后端重新返回HTTP状态码200 OK时,将被重新添加回负载均衡轮询列表。
例如:
[backends]
[backends.backend1]
[backends.backend1.healthcheck]
path = "/health"
interval = "10s"
服务器
服务器可以简单的被定义为URL
。你也可以设置一个自定义的 weight
给每个服务器(这个weight
将会被用于负载均衡)。
这里有一个关于后端和服务器的定义的例子:
[backends]
[backends.backend1]
[backends.backend1.circuitbreaker]
expression = "NetworkErrorRatio() > 0.5"
[backends.backend1.servers.server1]
url = "http://172.17.0.2:80"
weight = 10
[backends.backend1.servers.server2]
url = "http://172.17.0.3:80"
weight = 1
[backends.backend2]
[backends.backend2.LoadBalancer]
method = "drr"
[backends.backend2.servers.server1]
url = "http://172.17.0.4:80"
weight = 1
[backends.backend2.servers.server2]
url = "http://172.17.0.5:80"
weight = 2
- 定义了两个后端:
backend1
andbackend2
backend1
将把流量转发到两台服务器:http://172.17.0.2:80"
权重10
与http://172.17.0.3:80
权重1
并使用默认的wrr
负载均衡策略。backend2
将把流量转发到两台服务器:http://172.17.0.4:80"
权重1
与http://172.17.0.5:80
权重2
并使用drr
负载均衡策略。- 一个断路器被添加到
backend1
使用NetworkErrorRatio() > 0.5
表达式:监控网络故障率大于0.5超过10秒为这个前端平滑切换,断路条件匹配
配置文件
Træfɪk的配置文件分为两部分:
- 静态 Træfɪk 配置 ,仅在启动时被加载。
- 动态 Træfɪk 配置 ,可被热更新(无需重启进程)。
静态 Træfɪk 配置
静态配置文件是一种全局配置文件,用来配置后端和入口点的连接。
可以通过许多方式配置Træfɪk,以下是各种配置方式的生效优先级。 上面的项目优先级大于下面的项目:
- Key-value 存储
- 参数
- 配置文件
- 默认
这代表着参数会覆盖配置文件,Key-value存储会覆盖参数。
配置文件
在默认情况下, Træfɪk 会在以下几个地方寻找 traefik.toml
文件:
/etc/traefik/
$HOME/.traefik/
.
工作目录
你可以通过设置configFile
参数来覆盖这种默认情况:
$ traefik --configFile=foo/bar/myconfigfile.toml
请转到 全局配置 部分获取详细文档。
参数
每个参数(命令)在帮助部分都有定义:
$ traefik --help
需要注意的是,所有默认值也会一同被展示出来。
Key-value 存储
Træfɪk 支持多种 Key-value 存储方式:
请转到 用户手册 Key-value 存储配置 部分获取详细文档。
动态 Træfɪk 配置
动态配置请关注:
Træfɪk 可以将多个配置后端的规则热更新。
我们只需要开启watch
选项来让 Træfɪk 监听配置文件变化并自动生成配置。
指向服务的路由在监测到任何变化时直接被创建或更新。
请转到后端配置 部分获取详细文档。
命令
使用方法: traefik [command] [--flag=flag_argument]
列出了所有Træfɪk可用的命令与命令描述:
version
: 打印版本号storeconfig
: 将静态traefik配置存入Key-value存储。请转到存储 Træfɪk 配置 部分获取详细文档。
每个命令都可能包含相关的标志。 所有相关的标志都会显示在:
$ traefik [command] --help
需要注意的是,每个命令描述是在帮助的开始部分:
$ traefik --help