原文地址:https://www.douyacun.com/article/881acc2a7bfb34da960af55e7ddb0d23
这篇文章目的
nginx_http_
会注入到 http
块下面
nginx_proxy_
注入到kong 代理端口 server
块下面
server {
server_name kong;
listen 0.0.0.0:8000 reuseport backlog=16384;
listen 0.0.0.0:8443 ssl http2 reuseport backlog=16384;
# ...
# injected nginx_proxy_* directives
real_ip_header X-Real-IP;
real_ip_recursive off;
# ...
}
nginx_admin_
注入到kong 管理端口 server
块下面
server {
server_name kong_admin;
listen 127.0.0.1:8001 reuseport backlog=16384;
listen 127.0.0.1:8444 ssl http2 reuseport backlog=16384;
# ...
# injected nginx_admin_* directives
location / {
default_type application/json;
content_by_lua_block {
Kong.admin_content()
}
header_filter_by_lua_block {
Kong.admin_header_filter()
}
}
# ...
}
新增配置文件
server {
listen 2112;
location / {
# ...more settings...
return 200;
}
}
kong.conf
nginx_http_include
引入此配置文件
nginx_http_include = /path/to/your/my-server.kong.conf
极少用到
/usr/local/kong
├── nginx-kong.conf
└── nginx.conf
重启命令
kong start -c kong.conf --nginx-conf custom_nginx.template
kong下的文件,kong是openresty的插件,索引如果线上已经有openresty在运行的话,可以无缝衔接
[root@ali conf]# ll /usr/local/kong/
total 292
drwxr-xr-x 2 root root 4096 May 28 14:31 bin
drwx------ 2 nobody root 4096 May 28 15:30 client_body_temp
-rw-r--r-- 1 root root 234703 Apr 25 00:45 COPYRIGHT
drwx------ 2 nobody root 4096 May 28 15:30 fastcgi_temp
drwxr-xr-x 3 root root 4096 May 28 14:31 include
drwxr-xr-x 4 root root 4096 May 28 14:31 lib
drwxr-xr-x 2 root root 4096 May 28 15:30 logs
-rw-r--r-- 1 root root 297 Jun 1 19:18 nginx.conf
-rw-r--r-- 1 root root 7807 Jun 1 19:18 nginx-kong.conf
-rw-r--r-- 1 root root 1821 Jun 1 19:18 nginx-kong-stream.conf
drwxr-xr-x 2 root root 4096 Jun 4 15:25 pids
drwx------ 2 nobody root 4096 May 28 15:30 proxy_temp
drwx------ 2 nobody root 4096 May 28 15:30 scgi_temp
drwxr-xr-x 2 root root 4096 May 28 15:30 ssl
drwx------ 2 nobody root 4096 May 28 15:30 uwsgi_temp
启动方式:
$ /usr/local/openresty/nginx/sbin/nginx -p /usr/local/kong -c /usr/local/kong/nginx.conf
service/route/plugins
可以通过rest api创建一个service,url指向服务
curl -i -X POST http://localhost:8001/services/ \
-d 'name=foo-service' \
-d 'url=http://foo-service.com'
url会自动解析:
重试机制:
超时时间:
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"]
}
以下可以命中路由, host、path、method 均可以匹配到
GET /foo/hello/world HTTP/1.1
Host: example.com
GET /bar HTTP/1.1
Host: foo-service.com
GET /foo HTTP/1.1
Host: example.com
以下无法命中路由
# path没有命中
GET / HTTP/1.1
Host: example.com
# method没有命中
POST /foo HTTP/1.1
Host: example.com
# host没有命中
GET /foo HTTP/1.1
Host: foo.com
指定多个host
json
curl -i -X POST http://localhost:8001/routes/ \
-H 'Content-Type: application/json' \
-d '{"hosts":["example.com", "foo-service.com"]}'
form
curl -i -X POST http://localhost:8001/routes/ \
-d 'hosts[]=example.com' \
-d 'hosts[]=foo-service.com'
通配符
只能使用1个*,在左边或最右边
{
"hosts": ["*.example.com", "service.*"]
}
preserve_host
kong默认会把请求host替换成upstream的host
upstream target host
{
"created_at": 1591585408.555,
"upstream": {
"id": "6baccef1-2b15-44b8-b1a5-49fce6452487"
},
"id": "5b4c2ac4-27c5-42bb-9ec2-41ed6c3c3e75",
"target": "docker.for.mac.host.internal:9003",
"weight": 100,
"health": "HEALTHY"
}
打印一下请求头(其他无关请求头忽略)
{
"code": 0,
"message": "success",
"data": {
"header": {
"X-Forwarded-For": [
"172.21.0.1"
],
"X-Forwarded-Host": [
"douyacun.io"
],
"X-Forwarded-Port": [
"8000"
],
"X-Forwarded-Proto": [
"http"
],
"X-Real-Ip": [
"172.21.0.1"
]
},
"host": "docker.for.mac.host.internal:9003"
}
}
关闭preserve_host
{
"code": 0,
"message": "success",
"data": {
"header": {
"X-Forwarded-For": [
"172.21.0.1"
],
"X-Forwarded-Host": [
"douyacun.io"
],
"X-Forwarded-Port": [
"8000"
],
"X-Forwarded-Proto": [
"http"
],
"X-Real-Ip": [
"172.21.0.1"
]
},
"host": "douyacun.io:8000"
}
}
kong支持通过header来匹配路由
header中需要添加version:v1
, 才可以匹配到路由
GET /api/kong/preserve_host HTTP/1.1
version: v1
否则:
An invalid response was received from the upstream server
kong url path 匹配必须符合前缀匹配
{
"paths": ["/api"]
}
以下是可以匹配到路由的
GET /api/kong/preserve_host HTTP/1.1
Host: douyacun.io
默认情况下,kong代理到upstream不会改变url path
正则路径
kong支持正则路径和前缀路径匹配
{
"paths": ["/users/\d+/profile", "/following"]
}
GET /users/123/profile HTTP/1.1
Host: ...
优先级
正则匹配可以使用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
strip path
像nginx alias的用法, 去掉前缀路由发送给upstram, 默认是启用状态
service
{
"path": "/",
}
path 是 /api
, 这个path是作为路由前缀的
route
{
"paths": [
"/api"
]
}
strip path 开启状态
GET /api/articles HTTP/1.1
Host: ...
404 page not found
upstream 接收到的请求
GET /articles HTTP/1.1
Host: ...
method
通过请求方法发送过滤路由
GET
POST
HEAD
PUT
source
通过请求涞源ip/port过滤路由
10.1.0.0/16
流程:
主要用于自定义请求行为,为安卓/iOS创建一个consumer, 或者每个版本、每个平台创建一个consumer。这是一个不透明的概念,所以称为consumer而不是用户
匿名访问和鉴权访问同时存在
对匿名访问进行 低频 限流,对授权用户有 高频限流
流程:
创建service
创建route
创建key-auth plugin
curl -i -X POST \
--url http://localhost:8001/services/douyacun/plugins/ \
--data 'name=key-auth'
创建anonymous Consumer
curl -i -X POST \
--url http://localhost:8001/consumers/ \
--data "username=anonymous_users"
HTTP/1.1 201 Created
Content-Type: application/json
Connection: keep-alive
{
"username": "anonymous_users",
"created_at": 1428555626000,
"id": "bbdf1c48-19dc-4ab7-cae0-ff4f59d87dc9"
}
允许anonymous Consumer访问
curl -i -X PATCH \
--url http://localhost:8001/plugins/<your-plugin-id> \
--data "config.anonymous=<上一步anonymous Consumer生成的id>"
最终结果,原本需要授权的url现在不授权也可以访问了, 授权的consumer也可以正常访问
6 . 针对匿名consumer创建rate limit plugin, 针对授权consumer创建rate limit plugin
curl -i -X POST \
--url http://localhost:8001/services/douyacun/plugins/ \
--data 'name=rate-limiting'
--data 'config.minute=5'
--data 'consumer.id=<匿名账户id>'
{
"message": "API rate limit exceeded"
}
DNS-based loadbalancing/ring-balancer
DNS负载均衡,节点不是向kong注册服务,而是向DNS服务器提供注册,kong使用域名就可以了,
DNS各级都有缓存,缓存时间难以把控,不方便做健康检测移除不可用节点 (不推荐使用)
使用ring-balancer,需要向kong进行服务注册, 使用http注册以后可以立即获取流量
upstream: 虚拟hostname,route可以使用upstream name当作hostname
target: ip/port 每个node 都会有weight权重,决定承担多少流量
修改target的成本较小,修改upstram的成本较大
slots: 根据最多设置多少个target算出,假设设置10个target,那么slot就是 10 * 100
, 用于负载均衡算法,(todo:令牌?)
target只支持创建/删除,不支持修改,如果要改权重,删除之前的taget然后新创建一个target
target自动清理,不活跃target比活跃target多10个时会自动清理不活跃target
hash_on
none: 加权轮询
consumer: 按照consumer id hash,负载到不同的机器
ip:按照 ip hash
header:按照指定header hash
hash_on_header
指定headerhash_fallback_header
:hash_on_header
缺失时,替补cookie: 按cookie hash
hash_on_cookie
: 指定cookie namehash_on_cookie_path
: 指定cookie pathhash_fallback
hash_on
返回的hash值为空,hash_fallback指定替代品
一个是当前运行的生产环境,接收所有的用户流量(称之为蓝)。另一个是它的副本,但是闲置(称之为绿)。两者使用相同的数据库后端和应用配置
应用的新版本部署在绿色版本环境中,进行功能和性能测试。一旦测试通过,应用的流量从蓝色版本路由到绿色版本。然后绿色版本变成新的生产环境。
过程:
和蓝绿部署很像,区别在于可以阶段性进行,不用一次性全切流量
金丝雀部署可以在生产环境中基础设施小范围部署新的应用代码,一旦应用部署发布,只有少数用户被路由到,最大程度降低影响
kong的实现方式使用通过设置target权重来分配流量
# first target at 900
$ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
--data "target=192.168.34.17:80"
--data "weight=900"
# second target at 100
$ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
--data "target=192.168.34.18:80"
--data "weight=100"
kong支持2种健康检测,可以单独使用也可以结合使用:
每一个target都有独自的健康检测
健康检测的规则
Success
计数,重置其他计数TCP failures
计数,重置Success
计数timeouts
计数,重置Success
计数Http Failures
计数,重置success
计数如果TCP failures
/ timeouts
/ Http Failures
次数达到配置的阀值,target会被标记为unhealthy
如果Success
次数达到配置阀值后,target会被重新标记为healthy
healthchecks.active.http_path
: 设置target 健康检测接, 默认/
,常用ping
healthchecks.active.healthy.interval
: 健康target间隔多少秒进行一次检测,0不检测
healthchecks.active.unhealthy.interval
:非健康target间隔多少进行一次检测
healthchecks.active.type
: 指定协议http/https
healthchecks.active.timeout
: 连接超时时间,默认1s
healthchecks.active.concurrency
: 一次请求多少个target
healthchecks.active.healthy.successes
: 健康检测成功多少次认为是健康
healthchecks.active.unhealthy.tcp_failures
: 连接失败多少次判定target非健康
healthchecks.active.unhealthy.timeouts
: 请求超时次数判定target非健康
healthchecks.active.unhealthy.http_failures
: 非 (healthchecks.active.unhealthy.http_statuses
定义的状态码) 响应多少次判定target非健康
healthchecks.passive.healthy.successes
: 非健康节点检测
healthchecks.active.unhealthy.tcp_failures
: 连接失败多少次判定target非健康
healthchecks.active.unhealthy.timeouts
: 请求超时次数判定target非健康
healthchecks.active.unhealthy.http_failures
: 非 (healthchecks.active.unhealthy.http_statuses
定义的状态码) 响应多少次判定target非健康
设置间隔时间为0就关闭检测healthchecks.active.healthy.interval
/ healthchecks.active.unhealthy.interval