这里提到的网关特指API网关。API网关是在微服务架构的演进过程当中产生的,其核心功能是聚合后端服务,为客户端调用提供统一的门户。因为网关的集中式管理,在其上又衍生了限流、负载、路由管理、安全防御等新的需求和功能。基于应用系统现状,咱们将网关进一步的细分为带有业务逻辑的业务网关和专一于服务聚合、路由的中台网关。具体来讲,业务网关通常是指某一个业务系统的网关,其除了聚合本系统的后端服务以外,还会额外承担一些业务逻辑,好比通用的用户鉴权、基于业务的路由规则等。中台网关,是跨系统的、是将已有的平台能力抽象、聚合,统一包装成API服务,以便各平台、业务复用;中台网关关注的重点是服务的路由、抽象,提供基本的身份认证、限流等功能便可,不会嵌入具体的业务逻辑。注意这里的身份认证和业务网关里的是不同的,业务网关身份认证通常是具体的终端用户,中台网关里的身份认证是对调用方的识别、鉴权,不涉及具体终端用户。
前端
目前比较流行的API网关主要分为三类:nginx
一、 基于NGINX的反向代理git
二、 基于网络编程框架(netty、socket)自开发github
三、 基于组件的API网关框架,主要有:spring cloud gateway、zuul一、zuul2web
基于网络编程框架的自开发不在咱们考虑范围内,主要缘由有:自开发周期长,未通过实战验证可靠性须要长时间的磨合,并且自开发性能不会比已有框架表现的更好。所以咱们不考虑此类状况。下面咱们将分析1和3两种状况。spring
nginx与spring cloud gateway、zuul对比docker
nginx由内核和模块组成,内核的设计很是微小和简洁,完成的工做也很是简单,仅仅经过查找配置文件与客户端请求进行URL匹配,而后启动不一样的模块去完成相应的工做。下图反映了HTTP请求处理的常规流程:
数据库
spring cloud gateway是在spring boot基础上构建的,用于快速构建分布式系统的通用模式的工具集。其核心也是基于filter的,能够实现相似于zuul的特性功能,可是使用spring cloud 开发的应用程序很是适合在Docker或者Paas上部署。
编程
zuul是Netflix开源的微服务网关组件,它能够和Euraka、Ribbon、Hystrix等组件配合使用。其核心是一系列的过滤器,经过这些过滤器咱们能够实现身份认证、审查、监控、动态路由、压力测试、负载分配、静态影响处理、多区域弹性等。
json
不难看出三者在处理请求的思想上是一致的,都是基于filter作逻辑嵌入和处理。
产品 | 模型 | 优点 | 劣势 |
---|---|---|---|
nginx | 基于进程,采用epoll_wait、select这样的I/O多路复用模型。采用了异步非阻塞的方式处理请求,理论上是能够同时处理成千上万个请求。 | 内核小巧,自身占用资源少,久经高并发考验,产品稳定、性能最好。 | 只有基本功能配置,额外的功能须要自开发插件,插件语言与通常企业开发人员差别较大,学习成本较高。 |
spring cloud gatway | spring本身的gateway,基于Spring Boot2.x响应式的、非阻塞的API,支持WebSocket等长链接,和Spring框架紧密集成;总体模型与Nginx相似 | spring组件,与传统业务开发组件能很好集成,易于添加定制化需求,周边扩展组件丰富,学习成本较低。 | 自身资源消耗较大,在资源有限的状况下(1核2G),性能较差。相同配置下,并发的天花板要比nginx低很多。属于技术组件、没有成熟的产品,须要自开发。 |
zuul 1 | 基于servlet框架,采用阻塞和多线程方式,存在内部延迟严重、设备故障较多状况下会引发存活链接增多和线程增长的状况发生。并且不支持如WebSocket之类的长链接 | 和其余几款相比,没有明显优点 | 这个没什么好说的,性能表现差、并发数小、且不支持长链接。 |
zuul 2 | 与1相比,最大的区别是它采用了异步和无阻塞框架,每一个CPU一个线程,总体模型与Nginx相似 | 有netflix的成套产品支持,经常使用功能容易实现,相对于nginx来讲更容易定制化开发。 | 总体缺点与spring cloud相似,自身资源占用较大、低配下表现差,且须要必定的定制化开发才能使用。 |
从上面对比能够看到,各种网关都有其自身的优劣势和适用场景。对于业务网关开发,spring cloud gateway 或许是个不错的选择。中台网关,对于定制化功能要求很少,对于性能和稳定性要求是第一位的,所以nginx内核网关是个不错的选择。
基于以上缘由咱们选择了基于nginx内核的kong做为中台网关基座。首先,kong的内核是基于nginx的,其性能和稳定性是有保障的,并且也通过了大厂的实践验证;其次,kong是一个完整的网关产品,能够开箱即用,而且提供了丰富的插件以及简单的插件扩展机制。所以不管从性能、稳定性仍是从时间成本上看,kong都是首选。
微服务五种开源API网关实现组件对比:http://www.javashuo.com/article/p-ndsazcux-gr.html
Kong是Mashape开源的高性能高可用API网关和API服务管理层,在Mashape 管理了超过15,000个API,为200,000开发者提供了每个月数十亿的请求支持。
在微服务架构之下,按照康威定律,咱们系统架构会拆的很散,系统由一堆服务组成,下降了耦合度的同时也给服务的统一管理增长了难度。 上图左边描述了在旧的服务治理体系之下,鉴权,限流,日志,监控等通用功能须要在每一个服务中单独实现,这使得系统维护者没有一个全局的视图来统一管理这些功能。 Kong致力于解决的问题即是为微服务纳管这些通用的功能,在此基础上提升系统的可扩展性。如右图所示,微服务搭配上 Kong,可使得服务自己更专一于本身的领域,很好地对服务调用者和服务提供者作了隔离。
网关所须要的基本特性,Kong 都如数支持:
- 云原生 : 与平台无关,Kong 能够从裸机运行到 Kubernetes
- 动态路由 :Kong 的背后是 OpenResty+Lua,因此从 OpenResty 继承了动态路由的特性
- 熔断
- 健康检查
- 日志 : 能够记录经过 Kong 的请求和响应。
- 鉴权 : 权限控制,IP 黑白名单
- 监控 : 提供了实时监控插件
- 认证 : 如数支持 HMAC, JWT, Basic, OAuth2.0 等经常使用协议
- 限流
- REST API: 经过 Rest API 进行配置管理,从繁琐的配置文件中解放
- 可用性 : 自然支持分布式
- 高性能 : 背靠非阻塞通讯的nginx,性能高
- 插件机制 : 提供众多开箱即用的插件,且有易于扩展的自定义插件接口,用户可使用 Lua 自行开发插件
Kong总体架构以下所示:
从技术的角度讲,Kong能够认为是一个OpenResty应用程序。 OpenResty 运行在 Nginx 之上,使用 Lua 扩展了 Nginx。 Lua 是一种很是容易使用的脚本语言,可让你在Nginx中编写一些能够执行的操做。
- Kong核心基于OpenResty、nginx构建,用来接收 API 请求;
- Kong插件拦截请求/响应,进行处理;
- 提供 restfull 方式管理 admin api;
- 数据库存储Kong集群节点信息、API、消费者、插件等信息,目前提供了PostgreSQL和Cassandra支持。
Kong 抽象了一些概念Route、Service、Upstream、Consumer等,他们之间的关系以下图所示 :
- Route 路由至关于nginx 配置中的location Route实体定义匹配客户端请求的规则. 每一个路由都与一个服务相关联,而服务可能有多个与之相关联的路由. 每个匹配给定路线的请求都将被提交给它的相关服务. 路由和服务的组合提供了强大的路由机制, 能够在Kong中定义细粒度的入口点,从而引导访问到不一样upstream服务
- service 是抽象层面的服务,他能够直接映射到一个物理服务 (host 指向 ip + port),也能够指向一个 upstream 来作到负载均衡,一个Service能够有不少Route,匹配到的Route就会转发到Service中
- upstream 是对上游服务器的抽象;target 表明了一个物理服务,是 ip + port 的抽象
- Consumer 对象表示服务的使用者或者用户。最简单的理解和配置consumer的方式是,将其于用户进行一一映射,即一个consumer表明一个用户(或应用),但若是你将几个应用定义统一个consumer,这些均可以。
openresty定义的请求生命周期以下:
Kong插件遵循严格的文件结构,即包命,类名,文件位置等组织代码的方式是固定的,详细的文件结构以下图所示:
Kong 提供了一个基类,容许开发者覆盖类中提供的方法,这些方法的本质是openresty定义的请求生命周期,能够在request/response 的生命周期中的几个入口点注入自定义逻辑。每个方法有一个config参数,这个参数即schema.lua 中声明的,在使用插件时的配置。详细的逻辑以下图所示:
Kong 默认自带的插件集,按照功能的不一样大体能够分为如下这些类:Authentication 认证、Security 安全、Serverless、Traffic Control 流量控制、Analytics & Monitoring 分析监控、Transformations 请求报文处理、Logging 日志等
咱们目前用到的插件以下:
类别 | 插件名 | 使用场景 |
---|---|---|
认证 | key-auth | 对于服务或者路由提供用关键字认证机制 |
认证 | jwt | 提供JWT(JSON WEB Token)的认证方式 |
安全 | acl | 经过ACL(Access Control List)的组名称对服务或者路由进行黑白名单的访问控制 |
日志 | tcp-log | 发送请求和响应日志到TCP服务器 |
流量控制 | rate-limiting | 提供对给定时间请求数目的控制功能 |
流量控制 | request-termination | 根据响应的状态码和信息,可中止对某个服务或者路由的流量 |
监控 | prometheus | 暴露kong的metric endpoint |
服务 | 配置说明 |
---|---|
SLB | 阿里云SLB,QPS:10000,IP:10.163.240.30 |
kong | 单节点独立部署,4核8G,IP:10.163.204.90 |
负载均衡 | compass负载均衡,IP:10.163.204.8 |
后端服务 | 容器化部署,0.3核,400m |
日志服务 | 1核,2G |
ES | ES集群,3台,16核64G |
后端服务是标准Spring Boot服务,部署在Compass平台,没有作额外业务逻辑,提供如下接口
- /api/v1/quick:直接返回计数,不错额外处理
- /api/v1/slown:直接返回计数,但会延迟3~10秒钟,该值为随机值
jmeter测试软件,进行吞吐量测试,测试样本为1000并发,1000次轮询,即100w次调用。如下是测试结果统计:
序号 | 测试用例 | 总耗时 | 最小耗时 | 最大耗时 | 平均耗时 | CPU_start | CPU_end | memory_start | memory_end | memory_max | 备注 |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 直连服务,不通过网关 | 161s | 1ms | 496ms | 156ms | - | - | - | - | - | - |
2 | 网关+服务+logstash日志服务 | 168s | 2ms | 6255ms | 161ms | 0.2 | 37.8 | 28.3 | 55.3 | 70.4 | 日志服务滞后服务吞吐量,日志写完约用时8分钟;且在日志写入期间网关内存持续上升 |
3 | 网关+服务+filebeat日志服务 | 163s | 2ms | 5286ms | 155ms | 0.2 | 44.9 | 10.8 | 11.2 | 11.2 | 日志滞后约1分钟,耗时3分半。无其余明显影响 |
4 | 网关+服务 | 161s | 2ms | 5134ms | 156ms | 0.2 | 34.8 | 8.9 | 9.2 | 9.2 | - |
5 | 短链接+https+网关+filebeat | 561s | 2ms | 255ms | 128ms | 0.2 | 25.1 | 9.3 | 9.1 | 9.3 | 在短连接状况下,吞吐量为2000/s因此耗时较长,可是每条的耗时并无受到太大影响 |
6 | 短链接+http+网关+filebeat | 160s | 2ms | 4988ms | 156ms | 0.2 | 44.4 | 11.2 | 10.8 | 11.2 | 关闭SLB的https协议转换以后,吞吐量明显提高,与上文长链接测试结果一致 |
从上图不难看出,在客户端访问结束(3.5分钟)时,CPU占用就开始明显降低,可是因为日志服务处理效率跟不上,网关内存却继续上升,最高占用70%左右,随后降低。从这里不难看出,logstash日志处理方案,在大吞吐量时会成为瓶颈,进而影响网关机器。
从上图看,filebeat对于网关内存几乎没有影响,实际测试中,filebeat日志吞吐量约为4200/s,滞后网关吞吐量,可是并不会形成额外的内存开销。
从上图不难看出,就网关自己的吞吐量看,三者基本是一致的。logstash日志服务,会有较大的额外内存开销和较小的CPU开销;filebeat几乎没有额外的内存开销,仅有少许的CPU开销。 综上在大吞吐量及日志需求下,filebeat是个不错的选择。
通过对比和统计测试数据,发现kong自己,在启用插件的状况下,额外的性能损耗约为0.11ms。
须要注意的是,因为咱们使用的是阿里云的SLB,在https和短链接并发的状况下,会带来比较严重的性能损失,所以在实际应用中,须要根据API安全级别去考虑策略。
一、测试方案
基本配置与吞吐量测试一致。资源所限,很难达到nginx的访问瓶颈(这也从侧面说明了nginx内核的强大).咱们修改了kong的nginx配置项,将链接上限改成100.
nginx_work_processes=1 nginx_events_work_connections=100
二、测试结论
咱们以100并发访问后端应用,后端应用耗时在3~10秒之间随机。测试中发现当并发数达到40左右就达到了上限。这时网关其余服务也不可用,范文均返回502;直至测试结束才逐步恢复。 所以能够推断出,在规模化场景中,低质的后端服务会对网关自身的运行形成影响,严重的状况下会是致命的。咱们在设计网关的高可用方案时要考虑此类状况。
参考《部署架构》章节,咱们采用集群模式部署。该模式容许咱们水平的扩展集群大小,以应对不一样的流量。从kong的设计上讲其水平扩展是平滑且简单的。惟一的影响就是,它是基于数据库作的一致性,为了提升效率,全部数据是缓存在内存中的,所以在一致性上会存在必定的延迟(5S左右)。集群前端咱们采用阿里云的SLB做为负载均衡,以保证整个集群的高可用。
结合prometheuse以及告警平台实现网关集群运行状态的监控。
具体来讲就是启用prometheuse插件,将Kong与上游服务的相关指标,以prometheuse exposition的形式公开。prometheuse集群会对这些指标进行抓取。主要指标包括:
- 节点内存占用状况
- API服务请求数
- API响应耗时
- 当前活跃链接数
- 数据存储是否可达
- 基于指标,指定相关告警规则,经过告警平台,实现集群运行状态监控。
上文提到了,上游低质服务会对网关自己的可用性形成影响,严重状况下会致使网关宕机。做为服务中枢的网关一旦宕机,后果将是灾难性的。所以对于上游服务的管理和监控是必要的。目前主要从如下三个方面着手:
咱们经过启用上游的健康检查,来实现对后端服务可用性的实时监测,以便kong及时发现异常服务,并终止到其的路由。kong提供两类健康检查:
1.主动健康检查(active)
主动健康检查是指,上游服务提供一个心跳接口,由空定时调用,当达到指定阈值时,就认定服务不可用;
同时根据设置的阈值,一旦服务达到健康阈值,kong会自动恢复对该服务的路由。
优势:与实际运行无关,由kong主动探查服务,能够及时发现异常,并能自动恢复。 缺点:该方案会对上游服务带来额外的流量消耗。
2.被动健康检查(passive)
被动健康检查是指,kong不会主动心跳上游服务,而是根据实际路由状况,结合设置的阈值来判断服务是否可用。
优势:不会对上游服务带来任何影响 缺点:一旦异常,服务不能自动恢复,并且异常的发现取决于实际的路由访问状况,不能及时发现
限流插件,顾名思义就是对后端服务的访问流量进行限制。kong提供了灵活的限流策略,他容许咱们对消费者访问某个服务、API进行限制。提供了多种级别的阈值设置。该插件能够有效的拦截恶意攻击请求。
咱们经过配置SLB策略,将低质服务所有负载到独立的网关集群,使其与其余服务在物理上隔离,以免其可能带来的雪崩。
Kong的日志插件中咱们选用http-log,原理是设置一个log-server地址,Kong会将日志经过post请求发送到设置的log-server,而后log-server把日志给沉淀下来。 这里的log-server咱们使用logstash实现,将收集到的日志发送到ES中。
日志收集流程以下:
logstash计划根据集群地域不一样分别部署,青岛集群共用一套,北京集群另外搭建。 青岛kong集群分为测试和生产环境,logstash将开放两个http服务端口,9000对应接收测试环境日志,9001对应接收生产环境日志。 根据端口数据来源不一样,logstash将日志存储到es的不一样索引上,用以区分环境信息。
logstash青岛集群服务部署在容器云内, 全部配置文件都使用配置文件挂载的形式,方便修改配置。
官方文档地址:https://docs.konghq.com/hub/kong-inc/http-log/
每次请求都会以JSON形式的内容记录,格式以下:
{ "request": { "method": "GET", "uri": "/get", "url": "http://httpbin.org:8000/get", "size": "75", "querystring": {}, "headers": { "accept": "*/*", "host": "httpbin.org", "user-agent": "curl/7.37.1" }, "tls": { "version": "TLSv1.2", "cipher": "ECDHE-RSA-AES256-GCM-SHA384", "supported_client_ciphers": "ECDHE-RSA-AES256-GCM-SHA384", "client_verify": "NONE" } }, "upstream_uri": "/", "response": { "status": 200, "size": "434", "headers": { "Content-Length": "197", "via": "kong/0.3.0", "Connection": "close", "access-control-allow-credentials": "true", "Content-Type": "application/json", "server": "nginx", "access-control-allow-origin": "*" } }, "tries": [ { "state": "next", "code": 502, "ip": "127.0.0.1", "port": 8000 }, { "ip": "127.0.0.1", "port": 8000 } ], "authenticated_entity": { "consumer_id": "80f74eef-31b8-45d5-c525-ae532297ea8e", "id": "eaa330c0-4cff-47f5-c79e-b2e4f355207e" }, "route": { "created_at": 1521555129, "hosts": null, "id": "75818c5f-202d-4b82-a553-6a46e7c9a19e", "methods": null, "paths": [ "/example-path" ], "preserve_host": false, "protocols": [ "http", "https" ], "regex_priority": 0, "service": { "id": "0590139e-7481-466c-bcdf-929adcaaf804" }, "strip_path": true, "updated_at": 1521555129 }, "service": { "connect_timeout": 60000, "created_at": 1521554518, "host": "example.com", "id": "0590139e-7481-466c-bcdf-929adcaaf804", "name": "myservice", "path": "/", "port": 80, "protocol": "http", "read_timeout": 60000, "retries": 5, "updated_at": 1521554518, "write_timeout": 60000 }, "workspaces": [ { "id":"b7cac81a-05dc-41f5-b6dc-b87e29b6c3a3", "name": "default" } ], "consumer": { "username": "demo", "created_at": 1491847011000, "id": "35b03bfc-7a5b-4a23-a594-aa350c585fa8" }, "latencies": { "proxy": 1430, "kong": 9, "request": 1921 }, "client_ip": "127.0.0.1", "started_at": 1433209822425 }
- request 包含客户端发送的请求内容
- response 包含发送到客户端的响应内容
- tries 包含负载均衡器为此请求进行的(从新)尝试(成功和失败)列表
- route 包含请求匹配的route信息
- service 包含请求匹配的service信息
- authenticated_entity 包含身份验证的凭据属性(若是已启用身份验证插件)
- workspaces 包含路由关联的工做空间的Kong属性(仅限Kong Enterprise版本> = 0.34)
- consumer 包含消费者认证信息(若是已启用身份验证插件)
- proxy 是最终服务处理请求所花费的时间
- kong 是运行全部插件所需的内部Kong延迟
- request 是从客户端读取的第一个字节之间以及最后一个字节发送到客户端之间通过的时间。用于检测慢速客户端
- client_ip 包含原始客户端IP地址
- started_at 包含开始处理请求的UTC时间戳
配置一个webhook,网关根据返回响应码决定是否继续执行路由。
经过发出如下请求在Service上配置次插件
$ curl -X POST http://kong:8001/services/{service}/plugins \ --data "name=pre-filter" \ --data "config.http_endpoint=http://mockbin.org/bin/:id" \ --data "config.header_names=headers" \ --data "config.timeout=1000" \ --data "config.keepalive=1000"
{service}是此插件配置将定位的Service的id或name
$ curl -X POST http://kong:8001/routes/{route}/plugins \ --data "name=pre-filter" \ --data "config.http_endpoint=http://mockbin.org/bin/:id" \ --data "config.header_names=headers" \ --data "config.timeout=1000" \ --data "config.keepalive=1000"
{route}是此插件配置将定位的Route的id或name
后面结合k8s进行演示
如下是此插件使用的参数列表
参数 | 默认值 | 说明 |
---|---|---|
name | 要启用的插件的名称,本例中为pre-filter | |
service_id | 此插件定位的Service的Id,能够为空 | |
route_id | 此插件定位的Route的ID,能够为空 | |
enabled | true | 是否应用此插件 |
config.http_endpoint | 将要调用的webhook地址,须要是GET请求 | |
config.timeout | 1000 | 调用服务的超时时间,默认是1000ms |
config.header_names | authorization | 须要转发的请求头信息 |
该插件处于路由转发的前置位置。在请求到来时,会根据header_names配置,从请求头中获取对应的信息,并封装到新的请求中,发送到指定的http_endpoint。根据返回状态码来判断是否继续执行。
- 200 表示经过,会继续执行后续操做
- 302 表示经过,会继续执行后续操做
- 大于等于400,表示不经过,会阻断请求,返回401到前端;注意若是http_endpoint出现异常,也会阻断请求。
kong 搭建手册
操做系统版本
lsb_release -a 内核版本 uname -a 记录好系统版本
在yum源配置完善的状况下能够直接执行 $ sudo yum install epel-release $ sudo yum install kong-2.0.2.el7.amd64.rpm --nogpgcheck 若是yum源配置有问题,能够手动指定远程资源安装 安装epel-release软件包,以便Kong能够获取全部必需的依赖项: $ EL_VERSION=`cat /etc/redhat-release | grep -oE '[0-9]+\.[0-9]+'` $ sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-${EL_VERSION%.*}.noarch.rpm 安装Kong 对应的packages能够从https://docs.konghq.com/install/centos/#packages 对照系统版本选择: $ sudo yum install -y https://bintray.com/kong/kong-rpm/download_file?file_path=centos/7/kong-2.0.2.el7.amd64.rpm --nogpgcheck
修改配置数据库 cp /etc/kong/kong.conf.default /etc/kong/kong.conf vi /etc/kong/kong.conf grep -E "pg|post" /etc/kong/kong.conf database = postgres # Determines which of PostgreSQL or Cassandra # Accepted values are `postgres`, pg_host = 127.0.0.1 # Host of the Postgres server. pg_port = 5432 # Port of the Postgres server. pg_timeout = 5000 # Defines the timeout (in ms), for connecting, pg_user = kong # Postgres user. pg_password = 123456 # Postgres user's password. pg_database = kong # The database name to connect to. 初始化数据库 kong migrations bootstrap #集群其中一个节点配置完成便可,其他节点无需重复执行 启动 kong start 检查状态 kong health
全部节点启动完成以后,能够自主部署nginx负载,至此集群部署完成。
组件 | 版本 |
---|---|
kubectl | 1.16.9 |
kong | 2.0 |
默认状况下,Kong Gateway在其配置的代理端口8000和8443上侦听流量。它评估传入的客户端API请求,并将其路由到适当的后端API。在路由请求和提供响应时,能够根据须要经过插件应用策略。
例如,在路由请求以前,可能须要客户端进行身份验证。这带来了许多好处,包括:
- 因为Kong Gateway正在处理身份验证,所以该服务不须要本身的身份验证逻辑。
- 该服务仅接收有效请求,所以不会浪费周期来处理无效请求。
- 记录全部请求以集中查看流量。
plantuml @startuml "API CLIENT" -> "KONG GATEWAY": REQUESTS activate "KONG GATEWAY" "KONG GATEWAY" -> "BACKEND API": REQUESTS "BACKEND API" -> "KONG GATEWAY": RESPONSES "KONG GATEWAY" -> "API CLIENT": RESPONSES deactivate "KONG GATEWAY" @enduml
kong中的插件
plantuml @startuml "API CLIENT" -> "KONG GATEWAY": REQUESTS activate "KONG GATEWAY" "KONG GATEWAY" -> "KONG GATEWAY": "forward-plugin" "KONG GATEWAY" -> "AUTH BACKEND SERVER": REQUEST "AUTH BACKEND SERVER" -> "KONG GATEWAY": RESPONSES "KONG GATEWAY" -> "KONG GATEWAY": "forward-plugin" "KONG GATEWAY" -> "BACKEND API": REQUESTS "BACKEND API" -> "KONG GATEWAY": RESPONSES "KONG GATEWAY" -> "API CLIENT": RESPONSES deactivate "KONG GATEWAY" @enduml
kubectl apply -k manifests/base
查看po状态
# kubectl get po -n kong NAME READY STATUS RESTARTS AGE ingress-kong-7f8f64c5fc-xrsbg 2/2 Running 1 17m
查看svc
# kubectl get svc -n kong NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kong-proxy LoadBalancer 10.96.178.210 <pending> 80:32724/TCP,443:31298/TCP,8100:32415/TCP 25m kong-validation-webhook ClusterIP 10.104.253.149 <none> 443/TCP 25m
运行如下命令
# export PROXY_IP=$(kubectl get -o jsonpath="{.spec.clusterIP}" service kong-proxy -n kong)
这个时候访问kong服务,响应头包含kong信息。
curl -i $PROXY_IP
以本demo为例,构建服务镜像
docker build -t kong-test-server apps/test/
docker build -t kong-auth-server apps/auth/
在kubernetes环境跑起来
kubectl apply -f apps/test/test.yaml kubectl apply -f apps/auth/auth.yaml
访问服务
能够看到结果以下,流量通过kong访问到了test和auth
curl -i $PROXY_IP/test/
curl -i $PROXY_IP/auth/
设置局部插件
- 注:设置在Ingress或Service,都能使插件生效。如下以Ingress为例,Service同。
查看Ingress资源,能够看到刚刚建立的两个Ingress资源
kubectl get ingress
声明官方插件
$ echo ' apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: name: add-response-header config: add: headers: - "demo: injected-by-kong" plugin: response-transformer ' | kubectl apply -f -
将官方插件与Ingress规则相关联
kubectl patch ingress kong-test-server -p '{"metadata":{"annotations":{"konghq.com/plugins":"add-response-header"}}}'
查看ingress信息
访问服务,能够看到响应头多了刚刚插件的信息
curl -i $PROXY_IP/test/
设置全局插件
$ echo " apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: name: global-rate-limit labels: global: \"true\" config: minute: 5 limit_by: consumer policy: local plugin: rate-limiting " | kubectl apply -f -
查看插件资源
kubectl get kp -A
再次访问服务,响应头多了全局插件信息(全局插件不须要在指定ingress或service配置注解)
curl -i $PROXY_IP/test/
本demo使用lua实现了两个自定义插件:
- my-custom-plugin:根据配置文件返回指定响应头
- request-uri-pass-auth:根据配置文件,配置路由白名单,对不符合路由白名单规则的请求做拦截
为插件代码建立ConfigMap
以ConfigMap的方式将插件加载进kong服务里
下面建立这2个自定义插件
kubectl create configmap kong-plugin-myheader --from-file=demo/custom-plugins/myheader -n kong kubectl create configmap kong-plugin-request-uri-pass-auth --from-file=demo/custom-plugins/request-uri-pass-auth -n kong
查看建立的configmap
kubectl get configmap -n kong
要使用自定义插件,须要新增自定义插件环境变量,而且将上述生成的插件代码以ConfigMap的方式映射到kong中。
apiVersion: apps/v1 kind: Deployment metadata: name: ingress-kong namespace: kong spec: template: spec: containers: - name: proxy env: - name: KONG_PLUGINS value: request-uri-pass-auth,myheader - name: KONG_LUA_PACKAGE_PATH value: "/opt/?.lua;;" volumeMounts: - name: plugin-request-uri-pass-auth mountPath: /opt/kong/plugins/request-uri-pass-auth - name: my-custom-plugin mountPath: /opt/kong/plugins/myheader volumes: - name: plugin-request-uri-pass-auth configMap: name: kong-plugin-request-uri-pass-auth - name: my-custom-plugin configMap: name: kong-plugin-myheader
更新kong Deployment资源
kubectl apply -k demo/custom-plugins/
建立Kong Plugin自定义资源
分别对刚刚2个插件建立Kong Plugin
myheader.yaml
apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: name: my-custom-plugin config: header_value: "my first plugin" plugin: myheader
request-uri-pass-auth.yaml
apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: name: request-uri-pass-auth config: prefixs: - "/open/" plugin: request-uri-pass-auth # kubectl apply -f demo/custom-plugins/myheader/myheader.yaml kongplugin.configuration.konghq.com/my-custom-plugin created # kubectl apply -f demo/custom-plugins/request-uri-pass-auth/request-uri-pass-auth.yaml kongplugin.configuration.konghq.com/request-uri-pass-auth created
能够看到官方的Kong Plugin和自定义Kong Plugin
kubectl get KongPlugin -A
注意!这里有一个坑!当使用自定义插件的时候。咱们须要声明KONG_PLUGINS环境变量,这会致使官方的插件失效。这个时候须要将官方插件也加入到声明的KONG_PLUGINS中。
官方插件失效后访问设置了官方插件注解的服务时返回如下结果
以本demo为例,完整的yaml应该为: custoem-plugin.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: ingress-kong namespace: kong spec: template: spec: containers: - name: proxy env: - name: KONG_PLUGINS value: request-uri-pass-auth,myheader,response-transformer,rate-limiting - name: KONG_LUA_PACKAGE_PATH value: "/opt/?.lua;;" volumeMounts: - name: plugin-request-uri-pass-auth mountPath: /opt/kong/plugins/request-uri-pass-auth - name: my-custom-plugin mountPath: /opt/kong/plugins/myheader volumes: - name: plugin-request-uri-pass-auth configMap: name: kong-plugin-request-uri-pass-auth - name: my-custom-plugin configMap: name: kong-plugin-myheader
更新kong Deployment资源
kubectl apply -k demo/custom-plugins/
测试自定义插件是否生效
为test服务添加request-uri-pass-auth插件
kubectl patch ingress kong-test-server -p '{"metadata":{"annotations":{"konghq.com/plugins":"request-uri-pass-auth"}}}'
为auth服务添加my-custom-plugin插件
kubectl patch ingress kong-auth-server -p '{"metadata":{"annotations":{"konghq.com/plugins":"my-custom-plugin"}}}'
测试自定义插件是否生效
访问test服务
curl -i $PROXY_IP/test/
能够看到/test/路由被"request-uri-pass-auth"插件拦截
curl -i $PROXY_IP/open/
能够看到,/open/路由没有被拦截,由于"request-uri-pass-auth"插件对/open/路由做了放行。而后还放回了全局插件"rate-limit"信息。自定义插件和官方对全局插件生效。
访问auth服务
curl -i $PROXY_IP/auth/
能够看到,返回了"my-custom-plugin"插件信息和"rate-limit"插件信息。自定义插件和官方全局插件生效。
注意!KongPlugin资源须要跟对应的svc或ingress处于同一个命名空间。本demo都是声明在default空间。
建立slb
修改manifests/base/service.yaml
... metadata: name: kong-proxy namespace: kong annotations: ## ALIYUN SLB service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id: lb-wxxxxxxxxxxxe service.beta.kubernetes.io/alicloud-loadbalancer-address-type: internet ...
综合demo/custom-plugins/README.md 以及manifests/base/kong-ingress-dbless.yaml和manifests/base/service.yaml