1、简介
在本文中,我们将通过详细解释Kong的路由功能和内部工作机制来介绍它的代理功能。
可以通过修改Kong的两个配置来处理它暴露的接口:
- proxy_listen:定义一个地址/端口列表,Kong将在这些地址/端口上接受来自客户端的公共流量,并将其代理到您的上游服务(默认为8000个)。
- admin_listen:定义了地址和端口的列表,但是这些应该被限制为只能由管理员访问,因为它们暴露了Kong的配置功能:Admin API(默认为8001)。
2、术语
- client:请求访问Kong的代理端口的下游客户端。
- upstream service:Kong后端的API或service,提供给client访问。
- Service:对upstream service的抽象。
- Route:对应Kong中的Route组件。是kong的访问的,匹配改Route规则的请求将被路由到后端的Service。
- Plugin:对应Kong中的Plugin组件,属于业务逻辑的一部分将运行在整个代理过程的生命周期中。
3、如何配置service(回顾)
在Kong中注册服务需要使用Admin API进行处理,及访问8001端口的RestFul接口。
3.1、创建服务
curl -i -X POST http://localhost:8001/services/ \
-d 'name=foo-service' \
-d 'url=http://foo-service.com'
3.2、配置路由
curl -i -X POST http://localhost:8001/routes/ \
-d 'hosts[]=example.com' \
-d 'paths[]=/foo' \
-d 'service.id=d54da06c-d69f-4910-8896-915c63c270cd' # 上一条命令执行之后访问的服务的id
4、路由和匹配能力
Kong支持Http/https、TCL/TLS和GRPC/GRPCS协议的代理;每种协议具有不同的路由属性:
- http: methods, hosts, headers, paths (and snis, if https)
- tcp: sources, destinations (and snis, if tls)
- grpc: hosts, headers, paths (and snis, if grpcs)
以上三个属性都是可选的,但是至少需要设置一个属性。
路由匹配规则:
- 请求必须包含在添加路由时设置的所有属性
- 请求中所包含的属性值至少得有一个和配置得属性值相同,如果请求中包含所有配置得属性则必须和配置得属性值相同才标识为匹配上。
如:
- 定义一个路由
{
"hosts": ["example.com", "foo-service.com"],
"paths": ["/foo", "/bar"],
"methods": ["GET"]
}
- 匹配的请求
# 携带有所有配置的属性,则值必须和对应的属性匹配上才能说明满足该Route
GET /foo HTTP/1.1
Host: example.com
- 不匹配的请求
POST /foo HTTP/1.1 # 请求的类型不匹配
Host: example.com
4.1、路由匹配模式
- 请求头
从1.3开始,kong提供了对任意Http请求头的支持。不过一般都是使用Host请求头进行处理。通过Kong提供的hosts属性可以轻松的实现使用基于Host请求头的路由配置。
hosts属性可以接受多个值,多个值采用","分隔,如下使用Admin API来进行配置:
curl -i -X POST http://localhost:8001/routes/ \
-H 'Content-Type: application/json' \
-d '{"hosts":["example.com", "foo-service.com"]}'
或者采用表单的方式:
curl -i -X POST http://localhost:8001/routes/ \
-d 'hosts[]=example.com' \
-d 'hosts[]=foo-service.com'
除了使用确定的值进行配置意外,Kong还提供了使用通配符的方式进行配置,通配符主机名在域的最左边或最右边的标签上只能包含一个星号。例子:
- *.example.com:即以example.com结尾的host都将匹配该路由
- example.*:即以example开头的都将匹配该路由
- 路径
kong也支持通过请求路由的匹配规则,即请求路径的前缀必须至少一个匹配添加路由时设置的paths属性值。例子:
{
"paths": ["/service", "/hello/world"]
}
# 请求的前缀为/service,匹配
GET /service/resource?param=value HTTP/1.1
Host: example.com
# 请求的前缀为/hello,不匹配
GET /hello/world/resource HTTP/1.1
Host: anything.com
除了等值的匹配意外,基于path的模式也支持正则表达式的方式,例子:
{
"paths": ["/users/\d+/profile", "/following"] # \d+ 标识匹配一个或多个数字
}
GET /users/123/profile HTTP/1.1
Host: ...
基于请求前缀的匹配模式,Kong通过前缀的长度来处理匹配的优先级:即长度越长的先进行匹配。并且也可以在添加路由的时候通过设置regex_priority属性来设置优先级(数字越大优先级越高),同时正则表达的优先级高于前缀。例子:
[
{
"paths": ["/status/\d+"],
"regex_priority": 0
},
{
"paths": ["/version/\d+/status/\d+"],
"regex_priority": 6
},
{
"paths": ["/version"],
},
{
"paths": ["/version/any/"],
}
]
匹配顺序:
- /version/\d+/status/\d+
- /status/\d+
- /version/any/
- /version
4.2、优先级
路由可以根据其标头、主机、路径和方法(加上安全路由的snis——“https”、“grpcs”、“tls”)字段定义匹配规则。要使传入请求与路由匹配,必须满足所有现有字段。但是,Kong允许使用包含相同值的字段来配置两个或多个路由,从而提供了相当大的灵活性——在这种情况下,Kong应用优先级规则。
- 在评估请求时,Kong将首先尝试匹配具有最多规则的路由,例子:
{
"hosts": ["example.com"],
"service": {
"id": "..."
}
},
{
"hosts": ["example.com"],
"methods": ["POST"],
"service": {
"id": "..."
}
}
因为第二个路由的规则比较多,所有kong优先选择该路由进行匹配。
- 加入两个路由的规则数量相同,满足一下规则是将优先选择A:
- A只有“普通”主机报头,B有一个或多个“通配符”主机报头
- A的非主机头信息比B多
- A至少有一个“regex”路径,而B只有“plain”路径。
- A的路径比B的路径长
- A.created_at < B.created_at