5-API 网关 kong 实战
原文:https://cloud.tencent.com/developer/article/1477672
1. 什么是Kong?
目前互联网后台架构一般是采用微服务,或者类似微服务的形式,应用的请求通常需要访问多个后台系统。如果让每一个后台系统都实现鉴权、限流、负载均衡、审计等基础功能是不合适的,通用的做法是把这些功能抽离出来放到网关层。Kong是目前最流行的网关平台。
Kong - The World’s Most Popular Open Source Microservice API Gateway and Platform.
- Nginx = Http Server + Reversed Proxy + Load Balancer
- Openresty = Nginx + Lua-nginx-module
- Kong = Openresty + Customized Framework
2. 概念介绍
kong的API使用Restful风格,每个对象都是一个Object,其中最重要的两个对象是:
- Service 代表一个后台服务
- Route 是一条规则,告诉kong怎么把网关收到的请求发送到某个特定的后台服务,一个Service可以有多个Routes。
例如:主流http server都能根据不同的主机名,端口号,路径等信息把请求转发给不同的后台服务
kong 默认绑定4个端口:
- :8000 用来接受用户的HTTP请求,并转发到后台系统
- :8443 用来接受用户的HTTPS请求,并转发到后台系统
- :8001 通过HTTP协议提供管理功能的API (Admin API)
- :8444 通过HTTPS协议提供管理功能的API
这些端口可以在**/etc/kong/kong.conf**中修改,:8000 和 :8443 默认绑定0.0.0.0;:8001 和 :8444 默认绑定 127.0.0.1
当然我们可以把Admin API作为一个服务通过kong的网关暴露出去,请参考[Kong API Loopback] (https://docs.konghq.com/1.1.x/secure-admin-api/#kong-api-loopback)不过要注意安全。
3. Cheat Sheet
3.1 文件路径
- 配置文件:/etc/kong/kong.conf
- 日志文件:/usr/local/kong/logs
3.2 基本启动停止
kong start [ -c /etc/kong/kong.conf ]
kong reload
kong stop
3.3 命令行参考
前面说过,Kong采用了Restful风格的API,所有对象都通过HTTP的不同方法去操作。比如 curl -X GET http://localhost:8111/{object}
其中/{object}
是某个对象的在Admin API中的路径,下面以services为例:
方法 |
作用 |
url 路径 |
---|---|---|
POST |
添加一个service |
/services |
GET |
查询service列表 |
/services |
GET |
查询某个特定service |
/services/{name or id} |
PATCH |
更新service配置 |
/services/{name or id} |
PUT |
添加或更新serivce配置 |
/services/{name or id} |
DELETE |
删除service |
/services/{name or id} |
4. 实战
下面的内容以一个nodejs的server [node-demo] (https://github.com/4179e1/node-demo)为例,介绍kong的使用。
下文的配置中禁用了HTTPS,:8081 用来接受HTTP请求,:8111提供Admin API
4.1 Node Demo
这个服务默认绑定8080端口,提供若干API
$ curl http://127.0.0.1:8080/api?pretty
{
"api": [
{
"method": "GET, POST",
"desc": "GET demo",
"url": "http://127.0.0.1:8080/api/demo/headers"
},
{
"method": "GET",
"desc": "GET demo",
"url": "http://127.0.0.1:8080/api/demo/demo"
},
{
"method": "PUT",
"desc": "PUT demo",
"url": "http://127.0.0.1:8080/api/demo/demo"
},
{
"method": "DELETE",
"desc": "DELETE demo",
"url": "http://127.0.0.1:8080/api/demo/demo"
},
{
"method": "POST",
"desc": "POST demo",
"url": "http://127.0.0.1:8080/api/demo/demo"
}
]
}
其中/api/api/demo/headers
会详细的打印请求参数
$ curl http://127.0.0.1:8080/api/demo/headers?pretty
{
"result": true,
"hostname": "localhost",
"headers": {
"host": "127.0.0.1:8080",
"user-agent": "curl/7.58.0",
"accept": "*/*"
},
"query": {
"pretty": ""
},
"body": {}
}
在下面的例子中,我们尝试把网关的/api转发到 nodedemo 的 /api,也就是访问网关地址http://127.0.0.1/api
的时候,把对应的请求转发到nodedemo 的http://127.0.0.1:8080/api
4.2 添加service 和 route
下面这条命令添加了nodedemo.service这个service,凡是访问这个服务的请求都会被反向代理到http://127.0.0.1:8080这个地址
curl -i -X POST -H 'Content-Type: application/json' --url http://localhost:8111/services/ --data '{"name": "nodedemo.service", "url" : "http://127.0.0.1:8080"}'
- 我习惯给object的名字带上类型(.service),这样交叉引用的时候不容易混淆
- kong的Admin API支持urlencode参数,但我更习惯使用json
定义service之后,我们还得声明路由,把哪些特定的请求发送到这个service,这里我们配置的规则是“所有以/api开始的路径都转发给nodedemo.servce
”:
curl -X POST -H 'Content-Type: application/json' http://localhost:8111/services/nodedemo.service/routes -d '{"name": "nodedemo.route", "paths" : ["/api"], "strip_path": false }'
其中strip_path: false
表示请求后端服务时,同时还会把/api 这个前缀带上,更多细节见后文[Tips]部分。
4.3 测试
可以看到这个请求已经转发给nodedemo,并且网关自动添加了几个headres
# curl http://127.0.0.1/api/demo/headers?pretty
{
"result": true,
"hostname": "localhost",
"headers": {
"host": "127.0.0.1:8080",
"connection": "keep-alive",
"x-forwarded-for": "127.0.0.1",
"x-forwarded-proto": "http",
"x-forwarded-host": "127.0.0.1",
"x-forwarded-port": "80",
"x-real-ip": "127.0.0.1",
"user-agent": "curl/7.58.0",
"accept": "*/*",
"proxy-connection": "Keep-Alive"
},
"query": {
"pretty": ""
},
"body": {}
}
4.4 负载均衡
我们知道,nginx是能通过upstream支持多个后端server的负载均衡的,kong中要怎么做呢?
4.4.1 创建一个upstream对象
下面创建一个叫nodedemo.upstream的对象
curl -X POST -H 'Content-Type: application/json' http://localhost:8111/upstreams -d '{"name":"nodedemo.upstream"}'
4.4.2 为upstream添加target
刚才创建的upstream对象是空的,还需要给他添加实际的后端server地址,kong中称为target,实际就是host:port的组合,其中weight用于round robin的加权平均。
为了看到负载均衡的效果,我们可以再起一个nodedmo运行在8088端口:PORT=8088 node server.js
下面把两个nodedemo添加到upstream中
curl -X POST -H 'Content-Type: application/json' http://localhost:8111/upstreams/nodedemo.upstream/targets -d '{"target": "127.0.0.1:8080", "weight": 100}'
curl -X POST -H 'Content-Type: application/json' http://localhost:8111/upstreams/nodedemo.upstream/targets -d '{"target": "127.0.0.1:8088", "weight": 100}'
4.4.3 把service的url指向upstream
我们创建nodedemo.service的时候,url是直接指向http://127.0.0.1:8080的后端地址,此时把它改为upstream即可
curl -X PATCH -H 'Content-Type: application/json' http://localhost:8111/services/nodedemo.service --data '{ "url": "http://nodedemo.upstream" }'
访问http://localhost/api/demo/headers 数次可以发现轮询了不同的后端。
4.5 插件
kong 自带了很多插件,我们让我们给nodedemo启用一个试试,request-transformer可以修改请求内容,这里我们给请求添加一个header Hello: world
curl -X POST -H 'Content-Type: application/json' http://localhost:8111/services/nodedemo.service/plugins -d '{"name":"request-transformer","config":{"add":{"headers":["Hello: world"]}}}'
再次请求api,可以发现这个header已经有了
# curl http://127.0.0.1/api/demo/headers?pretty
{
"result": true,
"hostname": "localhost",
"headers": {
"host": "127.0.0.1:8080",
"connection": "keep-alive",
"x-forwarded-for": "127.0.0.1",
"x-forwarded-proto": "http",
"x-forwarded-host": "127.0.0.1",
"x-forwarded-port": "80",
"x-real-ip": "127.0.0.1",
"user-agent": "curl/7.58.0",
"accept": "*/*",
"hello": "world" # <==== here
},
"query": {
"pretty": ""
},
"body": {}
}
plugins也可以是全局的,Admin API调用的时候地址改为 /plugins 即可,如果同一个插件在全局和某个单独的service都配置了,以service的为准。
5. Tips
5.1 静态文件要放哪里?
Q:呃……我想用kong来搭建一个前后端分离的网站,我的静态文件要放哪?
A: 尽管kong是基于nginx的,但是作为一个API 网关,它对静态文件的支持不是特别友好,有两种方式:
- 修改kong的配置模版,详情请参考[Serving both a website and your APIs from Kong] (https://docs.konghq.com/1.2.x/configuration/)
- 后端再起一个http server,把静态文件都放到这个http server中,并配置对应的路由。
5.2 好多对象都有跟path相关的参数,它们都是干什么的?
我用到的path有几个
- route中的paths参数,表示符合这些请求路径要发到route对应的service中
- route中的strip_path 参数,决定kong转发给后端的时候是否保留源请求用于路由匹配的路径
- service中的path参数,上面的例子没有配置,默认为null,kong转发请求时会把这个作为前缀加上
假设网关以/api
为路由把请求转发给nodedemo(即route.paths = ['/api']
),它们的组合关系如下:
strip_path |
service.path |
请求地址 |
网关实际访问后端地址 |
---|---|---|---|
true |
null 或者 / |
http://127.0.0.1/api/demo |
http://127.0.0.1:8080/demo |
true |
/test |
http://127.0.0.1/api/demo |
http://127.0.0.1:8080/test/demo |
false |
null 或者 / |
http://127.0.0.1/api/demo |
http://127.0.0.1:8080/api/demo |
false |
/test |
http://127.0.0.1/api/demo |
http://127.0.0.1:8080/test/api/demo |
以最后一行为例,相当于访问 http://127.0.0.1/api/demo 时,实际访问的是/test/api/demo
,也就是把 service.path (/test)跟实际请求的路径(/api/demo)拼接起来发给后端。
5.3 wildcard域名匹配
kong同样可以基于域名把请求转发到不同的服务,比如a.example.com
转发到服务A,b.example.com
转发到服务B;同时kong还支持通配域名,比如*.example.com
转发到服务C。
我遇到一个坑是这样的:在已经配置a.example.com
和b.example.com
这两个路由转发的前提下,我遇到的一个坑是这样的:我还有一个服务C,需要让*.example.com/c/
(包括a.example.com/c
和b.example.com/c
)都转发到服务C。略一思索,我给服务C的Hosts添加了一个通配地址*.example.com
,然而这并不work,a.example.com/c/
和b.example.com/c/
并不能匹配到这个路由,但是c.example.com/c/
等没有配置过路由的域名可以匹配。
最终解决方案是,需要同时添加a.example.com
,b.example.com
和*.example.com
三个域名,类似这样:
{
"hosts": [
"a.example.com",
"b.example.com",
"*.example.com"
],
}
我估计这不是kong的问题,大概nginx本来就是这样的,未验证
5.4 Log rotate
网关访问量太大,日志要把硬盘写满了怎么办?上logroate,添加一个配置文件/etc/logroate.d/kong,内容如下:
/usr/local/kong/logs/*.log {
daily
missingok
rotate 3
compress
delaycompress
notifempty
create 640 root root
sharedscripts
postrotate
[ -f /usr/local/kong/pids/nginx.pid ] && kill -USR1 `cat /usr/local/kong/pids/nginx.pid`
endscript
}
这个文件是从CentOS自带的/etc/logrotate.d/nginx 修改而来的,保留最近3天的日志(rotate 3)
5.5 kong有GUI吗?
kong 社区版没有GUI组件,但是有一个第三方的[konga] (https://github.com/pantsel/konga)。
6. Reference
- [微服务与API网关(上): 为什么需要API网关?] (http://blog.didispace.com/hzf-ms-apigateway-1/)
- [ 微服务与API 网关(下)- Kong能为我们做什么?] (http://blog.didispace.com/hzf-ms-apigateway-2/)
- [Documentation for Kong] (https://docs.konghq.com/)
5-API 网关 kong 实战的更多相关文章
- API 网关 Kong
什么是 API 网关? 所谓网关,主要作用就是连接两个不同网络的设备,而今天所讲的 API 网关是指承接和分发客户端所有请求的网关层. 为什么需要网关层?最初是单体服务时,客户端发起的所有请求都可以直 ...
- Api网关Kong集成Consul做服务发现及在Asp.Net Core中的使用
写在前面 Api网关我们之前是用 .netcore写的 Ocelot的,使用后并没有完全达到我们的预期,花了些时间了解后觉得kong可能是个更合适的选择. 简单说下kong对比ocelot打动我的 ...
- API网关Kong系列(一)初识
最近工作需要,加上国内Kong的文章相对缺乏(搜来搜去就那么两篇文章),而且官方文档在某些demo上也有一些过时的地方,遂提笔记录下这些,希望能有帮助. 先随大流介绍下KONG(主要参考官网): 官方 ...
- API网关--Kong的实践
1. 什么是Kong 目前互联网后台架构一般是采用微服务,或者类似微服务的形式,应用的请求通常需要访问多个后台系统.如果让每一个后台系统都实现鉴权.限流.负载均衡.审计等基础功能是不合适的,通用的做法 ...
- API网关Kong系列(三)添加服务
进入之前部署好的kong-ui,默认第一次登陆需要配置kong服务的地址 进入API菜单,点击+号 按照要求填入相关信息 至此完成,可以使用诸如 https://your.domain.com:208 ...
- API网关Kong系列(二)部署
部署环境: [OS] centos 6.8(如果是centos6.5,请自行先升级到6.8,否则不支持docker) [Docker] Client version: 1.7.1 Client API ...
- API网关Kong部署和使用文档
KONG安装使用说明 系统版本:ubuntu14 1.下载安装包 $ wget https://github.com/Mashape/kong/releases/download/0.8.3/kong ...
- API网关——Kong实践分享
概述 01 什么是Kong Kong是一个在Nginx中运行的Lua应用程序,可以通过lua-nginx模块实现,Kong不是用这个模块编译Nginx,而是与OpenRestry一起发布,OpenRe ...
- API网关Kong系列(四)认证配置
目前根据业务需要先介绍2种认证插件:Key Authentication 及 HMAC-SHA1 认证 Key Authentication 向API添加密钥身份验证(也称为API密钥). 然后,消 ...
随机推荐
- C++入门到理解阶段二基础篇(8)——C++指针
1.什么是指针? 为了更加清楚的了解什么是指针?我们首先看下变量和内存的关系,当我们定义了int a=10之后.相当于在内存之中找了块4个字节大小的空间,并且存储10,要想操作这块空间,就通过a这个变 ...
- redis 事务(悲观锁和乐观锁)
MULTI 开启事务,后续的命令会被加入到同一个事务中 事务中的操作会发送给客服端,但是不会立即执行,而是将操作放到了该事务对应的一个队列中,服务端返回QUEQUD EXEC 执行EXEC后,事务中的 ...
- Difference between JDK, JRE and JVM
With Java programming language, the three terms i.e. JDK, JRE and JVM will always be there to unders ...
- [算法]PriorityQueue的应用
1. 数据流中的第K大元素 题目 设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组 ...
- Spring Boot 2.2.2.RELEASE 版本中文参考文档
写在前面 在我初次接触MongoDB的时候,是为了做一个监控系统和日志分析系统.当时在用Java操作MongoDB数据里的数据的时候,都是在网上查找Demo示例然后完成的功能,相信大家也同样的体会,网 ...
- 首个企业架构TOGAF角色扮演案例培训的诞生
BangEA企业架构系列在不同机构做了不少TOGAF认证课,自己都觉得有点枯燥了,我在想我们IT帮2020年第一期的认证课是不是该换种授课方式呢?想到就做......TOGAF认证培训,最早主要就是讲 ...
- 应用Tomcat进行多端口域名访问,并配置开启gzip压缩方法
1.除了默认的8080端口以外,我们尝试应用9090端口进行域名访问,打开server.xml 如图: 2.在代码里面进行添加如下9090下面的代码: 如图: 3.用9090端口进行访问 如图: 4. ...
- 038.[转] JVM启动过程与类加载
From: https://blog.csdn.net/luanlouis/article/details/40043991 Step 1.根据JVM内存配置要求,为JVM申请特定大小的内存空间 ? ...
- Playbook剧本小结
1.Playbook剧本小结 1.什么是playbook,playbook翻译过来就是"剧本",那playbook组成如下 play: 定义的是主机的角色task: 定义的是具体执 ...
- Scrum会议(十周)
1.任务分配 2.会议内容探讨了本次取得的重大突破和后续要继续开展的工作.分析了自己在前端开发遇到的问题,以及如何优化自己的前端界面.然后分工,每人都去优化一部分界面,比如段祥负责个人中心的优化,程吉 ...