聊一聊微服务网关 Kong

开发 架构
Kong 是由 Mashape 开发的并于2015年开源的一款API 网关,它是基于OpenResty(Nginx + Lua模块)和 Apache Cassandra/PostgreSQL 构建的,能提供易于使用的RESTful API来操作和配置API管理系统。Kong 可以水平扩展多个 Kong Server,通过前置的负载均衡配置把请求均匀地分发到各个Server,来应对大批量的网络请求。

[[324387]]

 Kong 是由 Mashape 开发的并于2015年开源的一款API 网关,它是基于OpenResty(Nginx + Lua模块)和 Apache Cassandra/PostgreSQL 构建的,能提供易于使用的RESTful API来操作和配置API管理系统。Kong 可以水平扩展多个 Kong Server,通过前置的负载均衡配置把请求均匀地分发到各个Server,来应对大批量的网络请求。

 

 

 

 

Kong 的扩展是通过插件机制进行的,并且也提供了插件的定制示例方法。插件定义了一个请求从进入到最后反馈到客户端的整个生命周期,所以可以满足大部分的定制需求,本身 Kong 也已经集成了相当多的插件,包括密钥认证、CORS、文件日志、API 请求限流、请求转发、健康检查、熔断等。官网地址:https://konghq.com/,代码托管地址:https://github.com/Kong/kong。

Nginx、Openresty和Kong三者紧密相连:

  • Nginx = Http Server + Reversed Proxy + Load Balancer
  • Openresty = Nginx + Lua-nginx-module,Openresty是寄生在 Nginx 上,暴露 Nginx 处理的各个阶段的钩子, 使用 Lua 扩展 Nginx
  • Kong = Openresty + Customized Framework,Kong作为 OpenResty 的一个应用程序

在使用Kong之前,最好新了解一下 OpenResty和Nginx

Kong 网关具有以下的特性:

  • 可扩展性: 通过简单地添加更多的服务器,可以轻松地进行横向扩展,这意味着您的平台可以在一个较低负载的情况下处理任何请求。
  • 模块化: 可以通过添加新的插件进行扩展,这些插件可以通过RESTful Admin API轻松配置。
  • 在任何基础架构上运行: Kong 网关可以在任何地方都能运行。可以在云或内部网络环境中部署 Kong,包括单个或多个数据中心设置,以及 public,private 或 invite-only APIs。

Kong的整体架构如下所示:

 

 

 

  • Kong Restful 管理API提供了API、API消费者、插件、upstreams、证书等管理。
  • Kong 插件拦截请求/响应,相当于 Servlet中的拦截器,实现请求的AOP处理。
  • 数据中心用于存储 Kong 集群节点信息、API、消费者、插件等信息,目前提供了PostgreSQL和Cassandra支持,如果需要高可用建议使用Cassandra。
  • Kong 集群中的节点通过 Gossip 协议自动发现其他节点,当通过一个 Kong 节点的管理 API 进行一些变更时也会通知其他节点。每个 Kong 节点的配置信息是会缓存的,如插件,那么当在某一个 Kong 节点修改了插件配置时,需要通知其他节点配置的变更。
  • Kong 核心基于 OpenResty,实现了请求/响应的 Lua 处理化。

Kong 网关的API接口的典型请求工作流程如下图所示:

 

 

 

当 Kong 运行时,每个对 API 的请求将先被 Kong 命中,然后这个请求将会被代理转发到最终的 API 接口。在请求(Requests)和响应(Responses)之间,Kong 将会执行已经事先安装和配置好的任何插件,授权 API 访问操作。Kong 是每个API请求的入口点(Endpoint)。

InstallKong

可运行在某些 Linux 发行版、Mac OS X 和 Docker 中,无论是本地机还是云端服务器皆可运行。除了免费的开源版本,Mashape 还提供了付费的企业版[1],其中包括技术支持、使用培训服务以及 API 分析插件。

 

 

 

为了演示方便,下面就以Docker环境中部署Kong为例来做相关讲解,内容参考官网:https://docs.konghq.com/install/docker/。Kong 安装有两种方式,一种是没有数据库依赖的DB-less 模式,另一种是with a Database 模式。我们这里使用第二种带Database的模式,因为这种模式功能更全。

1. 构建 Kong 的容器网络

首先我们创建一个 docker 自定义网络,以允许容器相互发现和通信。在下面的创建命令中 kong-net 是我们创建的Docker网络名称。

 

  1. $ docker network create kong-net 

2. 搭建数据库环境

Kong 目前使用 Cassandra 或者PostgreSQL,你可以执行以下命令中的一个来选择你的Database。请注意定义网络 --network=kong-net 。

使用Cassandra:

 

  1. docker run -d --name kong-database \ 
  2.               --network=kong-net \ 
  3.               -p 9042:9042 \ 
  4.               cassandra:3 

使用 PostgreSQL:

 

  1. $ docker run -d --name kong-database \ 
  2.               --network=kong-net \ 
  3.               -p 5432:5432 \ 
  4.               -e "POSTGRES_USER=kong" \ 
  5.               -e "POSTGRES_DB=kong" \ 
  6.               -e "POSTGRES_PASSWORD=kong" \ 
  7.               postgres:9.6 

3. 初始化或者迁移数据库

我们使用docker run --rm来初始化数据库,该命令执行后会退出容器而保留内部的数据卷(volume)。这个命令我们还是要注意的,一定要跟你声明的网络,数据库类型、host名称一致。同时注意Kong的版本号,注:当前 Kong 最新版本为 2.x,不过目前的kong-dashboard (Kong Admin UI) 尚未支持 2.x 版的Kong,为了方便后面的演示,这里以最新的 1.x 版的Kong作为演示。(截止2020-04-24时,Kong 最新版为1.5.1)

下面指定的数据库是 PostgreSQL,如果连接的是 Cassandra,可以将下面的 KONG_DATABASE 配置为 cassandra。

 

  1. $ docker run --rm \ 
  2.      --network=kong-net \ 
  3.      -e "KONG_DATABASE=postgres" \ 
  4.      -e "KONG_PG_HOST=kong-database" \ 
  5.      -e "KONG_PG_PASSWORD=kong" \ 
  6.      -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \ 
  7.      kong:1.5.1 kong migrations bootstrap 

4. 启动 Kong 容器

完成初始化或者迁移数据库后,我们就可以启动一个连接到数据库容器的 Kong 容器,请务必保证你的数据库容器启动状态,同时检查所有的环境参数 -e 是否是你定义的环境。

 

  1. $ docker run -d --name kong \ 
  2.     --network=kong-net \ 
  3.     -e "KONG_DATABASE=postgres" \ 
  4.     -e "KONG_PG_HOST=kong-database" \ 
  5.     -e "KONG_PG_PASSWORD=kong" \ 
  6.     -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \ 
  7.     -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \ 
  8.     -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \ 
  9.     -e "KONG_PROXY_ERROR_LOG=/dev/stderr" \ 
  10.     -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \ 
  11.     -e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" \ 
  12.     -p 8000:8000 \ 
  13.     -p 8443:8443 \ 
  14.     -p 8001:8001 \ 
  15.     -p 8444:8444 \ 
  16.     kong:1.5.1 

Kong 默认绑定4个端口:

  • 8000:用来接收客户端的 HTTP 请求,并转发到 upstream。
  • 8443:用来接收客户端的 HTTPS 请求,并转发到 upstream。
  • 8001:HTTP 监听的 API 管理接口。
  • 8444:HTTPS 监听的 API 管理接口。

到这里,Kong 已经安装完毕,我们可以使用 docker ps命令查看当前运行容器,正常情况下可以看到 Kong 和 PostgreSQL 的两个容器:

 

  1. $ docker ps 
  2. CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                                NAMES 
  3. a28160da4a9d        kong:latest         "/docker-entrypoint.…"   10 seconds ago      Up 9 seconds        0.0.0.0:8000-8001->8000-8001/tcp, 0.0.0.0:8443-8444->8443-8444/tcp   kong 
  4. 6c85a2e5491f        postgres:9.6        "docker-entrypoint.s…"   31 minutes ago      Up 31 minutes       0.0.0.0:5432->5432/tcp                                               kong-database 

我们可以通过 curl -i http://localhost:8001/ 来查看 Kong 是否运行完好。

Kong UI

Kong 企业版提供了管理UI,开源版本是没有的。但是有很多的开源的管理 UI ,其中比较 Fashion的有Kong Dashboard和 Konga。Kong Dashboard 当前最新版本(3.6.x)并不支持最新版本的 Kong,最后一次更新也要追溯到1年多以前了,选择 Konga 会更好一点。这里简单介绍一下Kong Dashboard和 Konga。

Kong Dashboard

Kong Dashboard的Github地址为:https://github.com/PGBI/kong-dashboard。docker 环境中安装运行如下:

 

  1. $ docker run --rm  \ 
  2. --network=kong-net \ 
  3. -p 8080:8080 \ 
  4. pgbi/kong-dashboard start \ 
  5. --kong-url http://kong:8001 

启动之后,可以在浏览器中输入 http://localhost:8080来访问 Kong Dashboard 管理界面。

 

 

 

Konga

Konga (官网地址:https://pantsel.github.io/konga/,Github地址:https://github.com/pantsel/konga)可以很好地通过UI观察到现在 Kong 的所有的配置,并且可以对于管理 Kong 节点情况进行查看、监控和预警。Konga 主要是用 AngularJS 写的,运行于nodejs服务端。具有以下特性:

  • 管理所有Kong Admin API对象。
  • 支持从远程源(数据库,文件,API等)导入使用者。
  • 管理多个Kong节点。使用快照备份,还原和迁移Kong节点。
  • 使用运行状况检查监视节点和API状态。
  • 支持电子邮件和闲置通知。
  • 支持多用户。
  • 易于数据库集成(MySQL,PostgresSQL,MongoDB,SQL Server)。

下面使用的 PostgresSQL 是和上面在docker环境中安装 Kong时的是一致的,注意用户名、密码、数据库名称等配置,docker环境安装启动 Konga:

 

  1. $ docker run  -d -p 1337:1337 \ 
  2.         --network kong-net \ 
  3.         --name konga \ 
  4.         -e "DB_ADAPTER=postgres" \ 
  5.         -e "DB_URI=postgresql://kong:kong@kong-database/kong" \ 
  6.         pantsel/konga 

如果Konga容器启动成功,可以通过 http://localhost:1337/访问管理界面。通过注册后进入,然后在 CONNECTIONS 中添加 Kong 服务的管理路径http://xxx.xxx.xxx.xxx:8001。Konga管理界面示例如下:

 

 

 

Kong Admin API

部署好 Kong 之后,则需要将我们自己的接口加入到 Kong 的中管理,Kong 提供了比较全面的RESTful API,每个版本会有所不同,详细可以参考官网:https://docs.konghq.com/2.0.x/admin-api/。Kong 管理API的端口是8001(8044),服务、路由、配置都是通过这个端口进行管理,所以部署好之后页面可以直接访问 http://localhost:8001。

这里我们先来了解一下如何使用 RESTful 管理接口来管理 Service (服务)、Route(路由)。

1. 添加一个Service

 

  1. $ curl -i -X POST http://localhost:8001/services \ 
  2. --data name=hello-service \ 
  3. --data url='http://xxx.xxx.xxx.xxx:8081/hello' 

这里的 'http://xxx.xxx.xxx.xxx:8081/hello' 是在《网关 Zuul 科普》中提及的一个简单的基础服务接口,调用这个接口会返回 Hello!。

客户端调用 Service 名称 hello-service 访问 'http://xxx.xxx.xxx.xxx:8081/hello'。添加成功后,系统将返回:

 

  1.   "host""xxx.xxx.xxx.xxx"
  2.   "created_at": 1587959433, 
  3.   "connect_timeout": 60000, 
  4.   "id""d96f418a-8158-4b1d-844d-ed994fdbcc2c"
  5.   "protocol""http"
  6.   "name""hello-service"
  7.   "read_timeout": 60000, 
  8.   "port": 8081, 
  9.   "path""\/hello"
  10.   "updated_at": 1587959433, 
  11.   "retries": 5, 
  12.   "write_timeout": 60000, 
  13.   "tags"null
  14.   "client_certificate"null 

2. 为 Service 添加一个 Route

 

  1. $ curl -i -X POST \ 
  2. --url http://localhost:8001/services/hello-service/routes \ 
  3. --data 'paths[]=/hello' \ 
  4. --data name=hello-route 

添加成功后,系统将返回:

 

  1.   "id""667bafde-7ca4-4fc4-b4f1-15c3cbec0b09"
  2.   "path_handling""v1"
  3.   "paths": [ 
  4.     "\/hello" 
  5.   ], 
  6.   "destinations"null
  7.   "headers"null
  8.   "protocols": [ 
  9.     "http"
  10.     "https" 
  11.   ], 
  12.   "methods"null
  13.   "snis"null
  14.   "service": { 
  15.     "id""d96f418a-8158-4b1d-844d-ed994fdbcc2c" 
  16.   }, 
  17.   "name": hello-route, 
  18.   "strip_path"true
  19.   "preserve_host"false
  20.   "regex_priority": 0, 
  21.   "updated_at": 1587959468, 
  22.   "sources"null
  23.   "hosts"null
  24.   "https_redirect_status_code": 426, 
  25.   "tags"null
  26.   "created_at": 1587959468 

3. 验证

我们可以通过访问 http://localhost:8000/hello 来验证一下配置是否正确。

前面的操作就等效于配置 nginx.conf:

 

  1. server { 
  2.   listen 8000; 
  3.   location /hello { 
  4.     proxy_pass http://xxx.xxx.xxx.xxx8081/hello; 
  5.   } 

不过,前面的配置操作都是动态的,无需像 Nginx一样需要重启。

Service是抽象层面的服务,它可以直接映射到一个物理服务,也可以指向一个Upstream(同Nginx中的Upstream,是对上游服务器的抽象)。Route是路由的抽象,它负责将实际的请求映射到 Service。除了Serivce、Route之外,还有 Tag、Consumer、Plugin、Certificate、SNI、Upstream、Target等,读者可以从官网的介绍文档[2]中了解全貌。

下面在演示一个例子,修改 Service,将其映射到一个 Upstream:

 

  1. # 添加 name为 hello-upstream 的 Upstream 
  2. $ curl -i -X POST http://localhost:8001/upstreams \ 
  3. --data name=hello-upstream 
  4.  
  5. # 为 mock-upstream 添加 Target,Target 代表了一个物理服务(IP地址/hostname + port的抽象),一个Upstream可以包含多个Targets 
  6. $ curl -i -X POST http://localhost:8001/upstreams/hello-upstream/targets \ 
  7. --data target="xxx.xxx.xxx.xxx:8081" 
  8.  
  9. # 修改  hello-service,为其配置 
  10. $ curl -i -X PATCH http://localhost:8001/services/hello-service \ 
  11. --data url='http://hello-upstream/hello' 

上面的配置等同于 Nginx 中的nginx.conf配置 :

 

  1. upstream hello-upstream{ 
  2.   server xxx.xxx.xxx.xxx:8081; 
  3.  
  4. server { 
  5.   listen 8000; 
  6.   location /hello { 
  7.     proxy_pass http://hello-upstream/hello; 
  8.   } 

当然,这里的配置我们也可以通过管理界面来操作。上面操作完之后,在Konga中也有相关信息展示出来:

 

 

 

 

 

 

 

Kong Plugins

Kong通过插件Plugins实现日志记录、安全检测、性能监控和负载均衡等功能。下面我将演示一个例子,通过启动 apikey 实现简单网关安全检验。

1. 配置 key-auth 插件

 

  1. $ curl -i -X POST http://localhost:8001/routes/hello-route/plugins \ 
  2. --data name=key-auth 

这个插件接收config.key_names定义参数,默认参数名称 ['apikey']。在HTTP请求中 header和params参数中包含apikey参数,参数值必须apikey密钥,Kong网关将坚持密钥,验证通过才可以访问后续服务。

此时我们使用 curl -i http://localhost:8000/hello 来验证一下是否生效,如果如下所示,访问失败(HTTP/1.1 401 Unauthorized,"No API key found in request" ),说明 Kong 安全机制生效了。

 

  1. HTTP/1.1 401 Unauthorized 
  2. Date: Mon, 27 Apr 2020 06:44:58 GMT 
  3. Content-Type: application/json; charset=utf-8 
  4. Connection: keep-alive 
  5. WWW-Authenticate: Key realm="kong" 
  6. Content-Length: 41 
  7. X-Kong-Response-Latency: 2 
  8. Server: kong/1.5.1 
  9.  
  10. {"message":"No API key found in request"

在Konga中我们也可以看到相关记录:

 

 

 

2. 为Service添加服务消费者(Consumer),定义消费者访问 API Key, 让他拥有访问hello-service的权限。

创建消费者 Hidden:

 

  1. $ curl -i -X POST http://localhost:8001/consumers/ \ 
  2. --data username=Hidden 

创建成功之后,返回:

 

  1.   "custom_id"null
  2.   "created_at": 1587970751, 
  3.   "id""95546c8f-248c-45c7-bce5-d972d3d9291a"
  4.   "tags"null
  5.   "username""Hidden" 
  6. 之后为消 

之后为消费者 Hidden 创建一个 api key,输入如下命令:

 

  1. $ curl -i -X POST http://localhost:8001/consumers/Hidden/key-auth/ \ 
  2. --data key=ENTER_KEY_HERE 

现在我们再来验证一下http://localhost:8000/hello:

 

  1. $ curl -i -X GET http://localhost:8000/hello \ 
  2. --header "apikey:ENTER_KEY_HERE" 

返回:

 

  1. HTTP/1.1 200 
  2. Content-Type: text/plain;charset=UTF-8 
  3. Content-Length: 7 
  4. Connection: keep-alive 
  5. Date: Mon, 27 Apr 2020 07:08:38 GMT 
  6. X-Kong-Upstream-Latency: 116 
  7. X-Kong-Proxy-Latency: 71 
  8. Via: kong/1.5.1 
  9.  
  10. Hello! 

Well done.

Kong 官网(https://docs.konghq.com/hub/)列出了已有的所有插件,如下图所示:

 

 

 

Kong 网关插件概括为如下:

  • 身份认证插件: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 作为API网关提供了API管理功能及围绕API管理实现了一些默认的插件,另外还具备集群水平扩展能力,从而提升整体吞吐量。Kong 本身是基于 OpenResty,可以在现有 Kong 的基础上进行一些扩展,从而实现更复杂的特性。虽然有一些特性 Kong 默认是缺失的,如API级别的超时、重试、fallback策略、缓存、API聚合、AB测试等,这些功能插件需要企业开发人员通过 Lua 语言进行定制和扩展。综上所述,Kong API 网关默认提供的插件比较丰富, 适应针对企业级的API网关定位。

References

  1. https://github.com/Kong/kong
  2. https://www.jianshu.com/p/a2e0bc8f4bfb
  3. https://docs.konghq.com/install/docker
  4. https://www.cnblogs.com/duanxz/p/9770645.html
  5. https://docs.konghq.com/2.0.x/admin-api/
  6. https://docs.konghq.com/hub/

参考资料

[1]企业版: http://getkong.org/enterprise/

[2]官网的介绍文档: https://docs.konghq.com/2.0.x/admin-api/

责任编辑:武晓燕 来源: 朱小厮的博客
相关推荐

2018-03-23 10:30:56

微网关服务啮合微服务

2017-10-21 23:02:49

微服务软件架构

2023-12-27 14:23:10

微服务数据存储

2018-06-07 13:17:12

契约测试单元测试API测试

2023-09-22 17:36:37

2021-01-28 22:31:33

分组密码算法

2020-05-22 08:16:07

PONGPONXG-PON

2022-09-01 08:17:15

Gateway微服务网关

2024-05-09 09:41:45

2020-03-06 15:11:21

进程线程Web

2020-09-08 06:54:29

Java Gradle语言

2021-01-01 09:01:05

前端组件化设计

2020-06-28 09:30:37

Linux内存操作系统

2020-08-12 08:34:16

开发安全We

2022-10-08 11:33:56

边缘计算云计算

2022-11-26 00:00:06

装饰者模式Component

2022-03-29 09:56:21

游戏版本运营

2018-01-10 14:13:04

测试矩阵API测试

2019-12-17 10:06:18

CDMA高通4G

2022-03-08 16:10:38

Redis事务机制
点赞
收藏

51CTO技术栈公众号