大家好,又见面了,我是你们的朋友风君子。
kong笔记 目录导航
背景
最近公司打算重构API网关,给定的硬性条件是支持lua脚本,kubernetes可部署,可解析lua,另外需要支持身份认证,IP黑白名单,限流,负载均衡等一些功能,为此,在技术选型上锁定了kong以及APISIX,最终选择了kong。
为什么选择kong
其原因如下:
-
社区活跃度高,遇到问题可以及时解决(github目前已经30.2k star了);
-
成熟度,性能好(kong是基于nginx衍生出的一个openResty应用)
-
拓展性好,功能相对齐全,耦合低
- 以lua插件的方式进行业务功能拓展;
- 自身支持API网关的基本特性(权限控制,安全,负载均衡,请求分发,监控等等),无需重新开发
- 一个独立的应用,与框架无耦合
举一个例子:Zuul,其自身只提供基本的路由功能,如果想使用其他功能,就需自研,而这些成本是很高的,另外,他与spring cloud深度集成,就需要引入其他的框架;
另外,附一个性能测试链接:Kong1.4 vs SC Gateway2.2 vs Zuul1.3 性能测试
目前市面上的开源的API网关除了kong还有:
-
Traefik
Traefik 是一个现代 HTTP 反向代理和负载均衡器,可以轻松部署微服务,Traeffik 可以与您现有的组件(Docker、Swarm,Kubernetes,Marathon,Consul,Etcd,…)集成,并自动动态配置。
-
Ambassador
Ambassador 是一个开源的微服务 API 网关,建立在 Envoy 代理之上,为用户的多个团队快速发布,监控和更新提供支持,支持处理 Kubernetes ingress controller 和负载均衡等功能,可以与 Istio 无缝集成。
-
Tyk
Tyk是一个开源的、轻量级的、快速可伸缩的 API 网关,支持配额和速度限制,支持认证和数据分析,支持多用户多组织,提供全 RESTful API。基于 go 编写。
-
Zuul
Zuul 是一种提供动态路由、监视、弹性、安全性等功能的边缘服务。Zuul 是 Netflix 出品的一个基于 JVM 路由和服务端的负载均衡器。
其对比如下:
Kong | Traefik | Ambassador | Tyk | Zuul | |
---|---|---|---|---|---|
基本 | |||||
主要用途 | 企业级API管理 | 微服务网关 | 微服务网关 | 微服务网关 | 微服务网关 |
学习曲线 | 适中 | simple | simple | 适中 | simple |
成本 | 开源/企业版 | 开源 | 开源/pro | 开源/企业版 | 开源 |
社区star | 20742 | 21194 | 1719 | 4299 | 7186 |
配置 | |||||
配置语言 | Admin Rest api, Text file(nginx.conf 等) | TOML | YAML(kubernetes annotation) | Tyk REST API | REST API,YAML静态配置 |
配置端点类型 | 命令式 | 声明式 | 声明式 | 命令式 | 命令式 |
拖拽配置 | yes | no | no | no | no |
管理模式 | configurable | decentralised, self-service | decentralised, self-service | decentralised, self-service | decentralised, self-service |
部署 | |||||
kubernetes | 适中(k8s yaml,helm chart) | easy | easy | 适中(k8s yaml,helm chart) | 适中(k8s yaml,helm chart) |
Cloud IAAS | high | easy | N/A | easy | easy |
Private Data Center | high | easy | N/A | easy | easy |
部署模式 | 金丝雀(企业版) | 金丝雀 | 金丝雀,shadow | 金丝雀 | 金丝雀 |
state | postgres,cassandra | kubernetes | kubernetes | redis | 内存文件 |
可扩展性 | |||||
扩展功能 | 插件 | 自己实现 | 插件 | 插件 | 自己实现 |
扩展方法 | 水平 | 水平 | 水平 | 水平 | 水平 |
功能 | |||||
服务发现 | 动态 | 动态 | 动态 | 动态 | 动态 |
协议 | http,https,websocket | http,https,grpc,websocket | http,https,grpc,websocket | http,https,grpc,websocket | http,https |
基于 | kong+nginx | traefik | envoy | tyk | zuul |
ssl 终止 | yes | yes | yes | yes | no |
websocket | yes | yes | yes | yes | no |
routing | host,path,method | host,path | host,path,header | host,path | |
限流 | yes | no | yes | yes | 需要开发 |
熔断 | yes | yes | no | yes | 需要其他组件 |
重试 | yes | yes | no | yes | yes |
健康检查 | yes | no | no | yes | yes |
负载均衡算法 | 轮询,哈希 | 轮询,加权轮询 | 加权轮询 | 轮询 | 轮询,随机,加权轮询,自定义 |
权限 | Basic Auth, HMAC, JWT, Key, LDAP, OAuth 2.0, PASETO, plus paid Kong Enterprise options like OpenID Connect | basic | yes | HMAC,JWT,Mutual TLS,OpenID Connect,基本身份验证,LDAP,社交OAuth(例如GPlus,Twitter,Github)和传统基本身份验证提供程序 | 开发实现 |
tracing | yes | yes | yes | yes | 需要其他组件 |
istio集成 | no | no | yes | no | no |
dashboard | yes | yes | grafana,Prometheus | yes | no |
引用链接:微服务五种开源API网关实现组件对比
什么是kong
Kong 由Mashape公司开源,是一个在 Nginx 中运行的Lua应用程序,并且可以通过lua-nginx模块实现,Kong不是用这个模块编译Nginx,而是与 OpenResty 一起发布,OpenResty已经包含了 lua-nginx-module, OpenResty 不是 Nginx 的分支,而是一组扩展其功能的模块。
三者的关系如下:
- Nginx是模块化设计的反向代理软件,C语言开发:
- OpenResty是以Nginx为核心的Web开发平台,可以解析执行Lua脚本
- Kong是OpenResty的一个应用,是一个API网关,具有API管理和请求代理的功能
核心思想
实现数据库抽象,路由和插件管理,插件可以存在于单独的代码库中,并且可以在几行代码中注入到请求生命周期的任何位置。
由于Kong是运行在OpenResty,我们先来看一下OpenResty执行流程:
图出处:OpenResty 执行流程阶段
- init_by_lua: master进程启动后的回调。
- init_worker_by_lua:nginx worker进程启动后的回调。
- rewrite_by_lua:request进来后首先经过rewrite,可以改写URL等。
- access_by_lua:request路由完成之后,进一步处理之前,可以修改request。
- header_filter_by_lua:response准备返回之前,可以修改header。
- body_filter_by_lua:response准备返回之前,可以修改body。
- log_by_lua:用于请求的日志记录。
Kong通过在 openresty 各个阶段加入了lua代码来实现插件的注入和执行,Kong 的 nginx 配置:
init_by_lua_block {
kong = require 'kong'
kong.init() // 完成 Kong 的初始化,路由创建,插件预加载等
}
init_worker_by_lua_block {
kong.init_worker() // 初始化 Kong 事件, worker 之间的事件,由 worker_events 来处理, cluster 节点之间的事件,由 cluster_events 来处理,缓存机制
}
upstream kong_upstream {
server 0.0.0.1;
balancer_by_lua_block {
kong.balancer() //负载均衡
}
keepalive 60;
}
server {
server_name kong;
listen 0.0.0.0:8000 reuseport backlog=16384;
listen 0.0.0.0:8443 ssl http2 reuseport backlog=16384;
rewrite_by_lua_block {
kong.rewrite() //插件生效策略的筛选,并执行对应的操作,只能处理全局插件(kong插件级别,全局(作用于所有请求),route(作用于当前路由),service(作用于匹配到当前service的所有请求)),路由匹配未开始。
}
access_by_lua_block {
kong.access() //1.完成路由匹配,2.确认加载的插件(并加入缓存) 3.进入balancer阶段
}
header_filter_by_lua_block {
kong.header_filter() //遍历在缓存中的插件列表,并执行
}
body_filter_by_lua_block {
kong.body_filter() //遍历在缓存中的插件列表,并执行
}
log_by_lua_block {
kong.log() //遍历在缓存中的插件列表,并执行
}
location / {
proxy_pass $upstream_scheme://kong_upstream$upstream_uri;
}
}
函数名 | LUA-NGINX-MODULE Context | 描述 |
---|---|---|
:init_worker() |
init_worker_by_lua | 在每个 Nginx 工作进程启动时执行 |
:certificate() |
ssl_certificate_by_lua | 在SSL握手阶段的SSL证书服务阶段执行 |
:rewrite() |
rewrite_by_lua | 从客户端接收作为重写阶段处理程序的每个请求执行。在这个阶段,无论是API还是消费者都没有被识别,因此这个处理器只在插件被配置为全局插件时执行 |
:access() |
access_by_lua | 为客户的每一个请求而执行,并在它被代理到上游服务之前执行(路由) |
:header_filter() |
header_filter_by_lua | 从上游服务接收到所有响应头字节时执行 |
:body_filter() |
body_filter_by_lua | 从上游服务接收的响应体的每个块时执行。由于响应流回客户端,它可以超过缓冲区大小,因此,如果响应较大,该方法可以被多次调用 |
:log() |
log_by_lua | 当最后一个响应字节已经发送到客户端时执行 |
部署
对于kong的部署,由于它是基于Nginx的,所以只需要添加多台服务器就可以配置成一个集群,通过前置的负载均衡配置把请求均匀地分发到各个 Server,来应对大批量的网络请求。
组件
共分为3大块:
- kong server : 基于nginx的服务器,用来接收API请求。
- Apache Cassandra/PostgreSQL :用来存储操作数据。
- Kong dashboard:官方推荐UI管理工具(缺点是仅仅可以集成kong2.0版本一下,不支持最新的kong版本!!),当然,也可以使用 restfull 方式 管理admin api。Konga另一款经典用于UI管理工具(可支持最新的kong版本)。
特性
- 可扩展: 通过简单地添加更多的机器,可以轻松地平行扩展,这意味着您的平台可以在一个较低负载的情况下处理任何请求。
- 模块化: 可以通过添加新的插件进行扩展,这些插件可以通过RESTful Admin API轻松配置。
- 在任何基础架构上运行: Kong可以在任何地方都能运行。您可以在云或内部部署环境中部署Kong,包括单个或多个数据中心设置,以及public,private 或invite-only APIs。
- Kong核心基于OpenResty构建,实现了请求/响应的Lua处理化;
- Kong插件拦截请求/响应,如果接触过Java Servlet,等价于拦截器,实现请求/响应的AOP处理;
- Kong Restful 管理API提供了API/API消费者/插件的管理;
- 数据中心用于存储Kong集群节点信息、API、消费者、插件等信息,目前提供了PostgreSQL和Cassandra支持,如果需要高可用建议使用Cassandra;
- Kong集群中的节点通过gossip协议自动发现其他节点,当通过一个Kong节点的管理API进行一些变更时也会通知其他节点。每个Kong节点的配置信息是会缓存的,如插件,那么当在某一个Kong节点修改了插件配置时,需要通知其他节点配置的变更。
具体如下:
- 云原生: 与平台无关,Kong可以从裸机运行到Kubernetes
- 动态路由:Kong 的背后是 OpenResty+Lua,所以从 OpenResty 继承了动态路由的特性
- 基于hash的负载均衡:基于hashing/sticky session的负载均衡
- 断路器:能追踪不健康的upstream services
- 健康检测:对upstream services进行主动或者被动地监控
- 服务发现:可结合consul提供服务注册等功能
- WebSockets:通过WebSockets和upstream service进行通信
- OAuth2.0:可对API方便地添加OAuth2.0进行授权
- 日志:通过HTTP/TCP/UDP等方式进行日志相关操作
- 安全:ACL,机器人检测,黑白名单IP等
- 系统日志:日志可输入到系统日志中
- 监控:提供实时监控功能
- 认证:HMAC/JWT以及基本认证方式
- 限流(Rate-Limiting):基于多变量对请求进行阻塞或者限制
- 转换:对TTP请求和相应进行添加/删除/操纵等操作
- 缓存:在代理层进行缓存和响应处理
- CLI:通过命令行对kong的集群进行控制
- REST API:可灵活地通过RESTful API对kong进行操作
- 失败检测与恢复:Cassandra某一节点停止也不会影响kong的功能
- 集群:所有的kong节点都能自动加入集群,并保证配置在整个节点间得到更新
- 可扩展性:kong可以通过添加节点很容易地实现横向扩展
- 性能:使用nginx作为内核,kong具有nginx的高性能
- plugin:可以对kong和API进行扩展
插件
目前已经提供的插件有:
- 身份认证插件:Kong提供了Basic Authentication、Key authentication、OAuth2.0 authentication、HMAC authentication、JWT、LDAP authentication认证实现。
- 安全控制插件:ACL(访问控制)、CORS(跨域资源共享)、动态SSL、IP限制、爬虫检测实现。
- 流量控制插件:请求限流(基于请求计数限流)、上游响应限流(根据upstream响应计数限流)、请求大小限制。限流支持本地、Redis和集群限流模式。
- 分析监控插件:Galileo(记录请求和响应数据,实现API分析)、Datadog(记录API Metric如请求次数、请求大小、响应状态和延迟,可视化API Metric)、Runscope(记录请求和响应数据,实现API性能测试和监控)。
- 协议转换插件:请求转换(在转发到upstream之前修改请求)、响应转换(在upstream响应返回给客户端之前修改响应)。
- 日志应用插件:TCP、UDP、HTTP、File、Syslog、StatsD、Loggly等。
kong目前提供了37个插件,其中商业收费7个,30个开源免费的插件,可以设定到api/服务/路由粒度上,详情如下:
类别 | 免费/收费 | name | 插件名 | 使用场景 |
---|---|---|---|---|
认证 | 免费 | basic-auth | Basic Authentication | 对于服务或者路由提供用户名/密码基本认证机制 |
认证 | 免费 | key-auth | Key Authentication | 对于服务或者路由提供用关键字认证机制 |
认证 | 收费 | – | OpenID Connect | 提供与三方OpenID的集成方式 |
认证 | 免费 | oauth2 | OAuth 2.0 Authentication | 添加OAuth 2.0认证 |
认证 | 收费 | – | OAuth 2.0 Introspection | 提供与三方OAuth 2.0认证服务器的集成方式 |
认证 | 免费 | hmac-auth | HMAC Authentication | 提供HMAC(Hashed Message Authentication Code)签名认证方式 |
认证 | 免费 | jwt | JWT | 提供JWT(JSON WEB Token)的认证方式 |
认证 | 免费 | ldap-auth | LDAP Authentication | 提供了与LDAP认证服务器的集成方式 |
安全 | 免费 | acl | ACL | 通过ACL(Access Control List)的组名称对服务或者路由进行黑白名单的访问控制 |
安全 | 免费 | cors | CORS | 对服务或者路由提供CORS支持 |
安全 | 免费 | ip-restriction | IP Restriction | 通过IP地址对服务或者路由进行黑白名单的访问控制 |
安全 | 免费 | bot-detection | Bot Detection | 对服务或者路由提供机器人检出并能进行黑白名单的设定 |
安全 | 免费 | ssl | Dynamic SSL | 对路由或者API提供ssl支持 |
流量控制 | 收费 | – | EE Canary Release | 提供金丝雀发布支持 |
流量控制 | 收费 | – | EE Forward Proxy | 提供企业内网中前向代理的支持 |
流量控制 | 收费 | – | EE Proxy Caching | 提供代理缓存的加速功能 |
流量控制 | 免费 | request-size-limiting | Request Size Limiting | 可以对请求的body的size进行限制 |
流量控制 | 免费 | rate-limiting | Rate Limiting | 提供对给定时间段HTTP请求数目的控制功能 |
流量控制 | 收费 | – | EE Rate Limiting | CE版本Rate Limiting的强化 |
流量控制 | 免费 | response-ratelimiting | Response Rate Limiting | 基于用户响应Header的信息,提供对HTTP请求数目的控制功能 |
流量控制 | 免费 | request-termination | Request Termination | 根据响应的状态码和信息,可停止对某个服务或者路由的流量 |
Serverless | 免费 | aws-lambda | AWS Lambda | 调用和管理AWS Lambda函数 |
Serverless | 免费 | openwhisk | Apache OpenWhisk | 调用和管理OpenWhisk |
分析&监控 | 免费 | zipkin | Zipkin | 提供兼容zipkin的方式对用户请求进行追踪 |
分析&监控 | 免费 | datadog | Datadog | 可将API的指标信息在datadog上进行可视化地展示 |
分析&监控 | 免费 | runscope | Runscope | 结合runscope进行API性能测试和监控 |
转换 | 免费 | request-transformer | Request Transformer | 通过kong对请求进行转换 |
转换 | 收费 | – | EE request Transformer | request Transformer的强化版 |
转换 | 免费 | response-transformer | Response Transformer | 通过kong对响应进行转换 |
转换 | 免费 | correlation-id | Correlation ID | 通过kong实现请求和响应之间的关联 |
日志 | 免费 | tcp-log | TCP | 发送请求和响应日志到TCP服务器 |
日志 | 免费 | udp-log | UDP | 发送请求和响应日志到UDP服务器 |
日志 | 免费 | http-log | HTTP | 发送请求和响应日志到HTTP服务器 |
日志 | 免费 | file-log | File | 发送请求和响应日志到磁盘的文件中 |
日志 | 免费 | statsd | StatsD | 发送请求和响应日志到StatsD服务器 |
日志 | 免费 | syslog | Syslog | 发送请求和响应日志到syslog中 |
日志 | 免费 | syslog | Loggly | 发送请求和响应日志到Loggly服务器 |
kong的架构
从技术的角度讲,Kong 可以认为是一个 OpenResty 应用程序。 OpenResty 运行在 Nginx 之上,使用 Lua 扩展了 Nginx。 Lua 是一种非常容易使用的脚本语言,可以让你在 Nginx 中编写一些逻辑操作。之前我们提到过一个概念 Kong = OpenResty + Nginx + Lua,但想要从全局视角了解 Kong 的工作原理,还是直接看源码比较直接。我们定位到本地的 Kong 文件夹,按照上图中的目录层级来识识 Kong 的庐山真面目。
- Kong 文件下包含了全部源码和必要组件,分析他们,我们便得到了 Kong 的架构。0.13.x 是目前 Kong 的最新版本。
- 从 2 号块中可以看到 nginx.conf ,这其实便是一个标准的 Nginx 目录结构,这也揭示了 Kong 其实就是运行在 Nginx 的基础之上,而进行的二次封装。由 share 文件夹向下展开下一次分析。
- share 文件夹中包含了 OpenResty 的相关内容,其实背后就是一堆 Lua 脚本,例如 lapis 包含了数据库操作,Nginx 生命周期,缓存控制等必要的 Lua 脚本,logging 包含了日志相关的 Lua 脚本,resty 包含了 dns,健康检查等相关功能的 Lua 脚本…而其中的 kong 目录值得我们重点分析,他包含了 Kong 的核心对象。
- api 和 core 文件夹,封装了 Kong 对 service,route,upstream,target 等核心对象的操作代码(这四个核心对象将会在下面的小节重点介绍),而 plugins 文件夹则是 Kong 高可扩展性的根源,存放了 kong 的诸多扩展功能。
- plugins 文件夹包含了上一节提到的 Kong 的诸多插件功能,如权限控制插件,跨域插件,jwt 插件,oauth2 插件…如果需要自定义插件,则需要将代码置于此处。
从上述文件夹浏览下来,大概可以看到它和 Nginx 的相似之处,并在此基础之上借助于 Lua 对自身的功能进行了拓展,除了 nginx.conf 中的配置,和相对固定的文件层级,Kong 还需要连接一个数据库来管理路由配置,服务配置,upstream 配置等信息,是的,由于 Kong 支持动态路由的特性,所以几乎所有动态的配置都不是配置在文件中,而是借助于 Postgres 或者 Cassandra 进行管理。
Kong 对外暴露了 Restful API,最终的配置便是落地在了数据库之中。
引用链接:https://mp.weixin.qq.com/s/CWGy6cwy6QGLvwByurEGbw
kong的应用
API 网关可以通过实现一些中间件来解决一些问题,这些中间件的功能你就不用再到每个service中实现了。你也是知道的,不同的团队使用不同的方式来实现了不同的微服务。
如果你不去做一些中心化和抽象化的事情,你将会死于不同的认证方式以及不同的速率限制实现,五花八门。你肯定希望避免这样的糟糕局面。
API网关不仅可以帮你解决API的管理部分,而且还可以解决下面两件事情:
- 分析(Analytics) – API网关可以和你的分析基础设施保持透明的交互和通信,因为API网关是每个请求(request)的入口,必经地。API网关可以看到所有的数据,可以知道经过你的service的流量。这就相当于你有一个集中的地方,你可以把所有的这些信息push到你的监控或分析工具,比如Kibana或者Splunk。
- 自动化(Automation) –网关还有助于自动化部署,还可以帮助你实现自动化登入验证(on boarding)。 什么是登入(on boarding)呢? 如果你有API,并且你希望有身份验证,你可能需要一些功能可以允许用户为该API创建登入凭据(credentials)然后开始使用(消费)API。 开发人员门户网站或你的文档中心等都可以与网关集成来配置这些凭据(credentials),这样你就不用从头开始构建一些功能了。
Kong作为API网关提供了API管理功能,及围绕API管理实现了一些默认的插件,另外还具备集群水平扩展能力,从而提升整体吞吐量。Kong本身是基于OpenResty,可以在现有Kong的基础上进行一些扩展,从而实现更复杂的特性。
虽然有一些特性Kong默认是缺失的,如API级别的超时、重试、fallback策略、缓存、API聚合、AB测试等,这些功能插件需要企业开发人员通过Lua语言进行定制和扩展。
拓展
为什么需要API网关
传统方式的四大痛点:
痛点 | 说明 |
---|---|
重复多 | 在多个微服务中,共通的功能重复,比如认证或者日志相关共通模块 |
巨石化 | 单个服务仍然后变成尾大不掉的巨石应用的趋势 |
影响大 | 影响较大,很难做到扩展功能而能不影响其他服务 |
效率低 | 由于系统限制,导致生产性低下 |
加了网关之后:
如何选择微服务 API 网关:对比 Kong、APISIX、Tyk、Apigee 和其他网关: 主要说明了API网关的作用,以及API网关在选型上的注意点是什么
总结
kong作为一款API网关的应用实现,其优点很明显:
- 自带一些API网关的基本特性,无需再次开发,即开箱即用;
- 基于nginx开发,性能好;
- 拓展性好,如果自带的插件不满足生产,可自行开发插件,不过需要会lua语法;
- 有可视化的dashboard,方便查看。