什么是API网关?

API 网关并非一个新兴的概念,在十几年前就已经存在了,它的作用主要是作为流量的入口,统一的处理和业务相关的请求,让请求更加安全、快速和准确的得到处理。

它有以下传统的功能:

  1. 反向代理和负载均衡,这和 Nginx 的定位和功能是一致的;

  2. 动态上游、动态 SSL 证书和动态限流限速等运行时的动态功能,这是开源版本 Nginx并不具备的功能;

  3. 上游的主动和被动健康检查,以及服务熔断;

  4. 在 API 网关的基础之上进行扩展,成为全生命周期的 API 管理平台。

Kong简介

Kong基于Nginx,利用了其稳定性和高效率。Kong是Mashape开源的高性能高可用API网关和API服务管理层。

Kong是一个在Nginx中运行的Lua应用程序,并且可以通过lua-nginx模块实现。Kong不是用这个模块编译Nginx,而是与OpenResty一起分发,OpenResty已经包含了lua-nginx-module。OpenResty不是Nginx的分支,而是一组扩展其功能的模块。Kong基于OpenResty,进行API管理,并提供了插件实现API的AOP。

这为可插拔架构奠定了基础,可以在运行时启用和执行Lua脚本(称为“插件”)。 因此,我们认为Kong是微服务架构的典范:它的核心是实现数据库抽象,路由和插件管理。 插件可以存在于单独的代码库中,并且可以在几行代码中注入到请求生命周期的任何位置。

目前互联网后台架构一般是采用微服务,或者类似微服务的形式,应用的请求通常需要访问多个后台系统。如果让每一个后台系统都实现鉴权、限流、负载均衡、审计等基础功能是不合适的,通用的做法是把这些功能抽离出来放到网关层。Kong是目前最流行的网关平台。

Kong的基本架构

view

Kong 默认绑定4个端口

  • :8000 用来接受用户的HTTP请求,并转发到后台系统
  • :8443 用来接受用户的HTTPS请求,并转发到后台系统
  • :8001 通过HTTP协议提供管理功能的API (Admin API)
  • :8444 通过HTTPS协议提供管理功能的API

这些端口可以在**/etc/kong/kong.conf**中修改,当然我们可以把Admin API作为一个服务通过kong的网关暴露出去。

Kong 主要有三个组件

  • Kong Server :基于nginx的服务器,用来接收 API 请求。
  • Apache Cassandra/PostgreSQL:用来存储操作数据。
  • Kong dashboard:官方推荐 UI 管理工具,当然,也可以使用 restfull 方式管理 admin api。

Kong 采用插件机制进行功能定制,插件集(可以是 0 或 N 个)在 API 请求响应循环的生命周期中被执行。插件使用 Lua 编写,基础功能包括:HTTP 基本认证、密钥认证、CORS(Cross-Origin Resource Sharing,跨域资源共享)、TCP、UDP、文件日志、API 请求限流、请求转发以及 Nginx 监控等。

Kong 网关具有以下的特性

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

相关术语

  • Route:是请求的转发规则,按照Hostname和PATH,将请求转发给Service。路由是定义对这个服务暴露给客户端的请求路径及请求方式。服务与路由是1对多的关系,一个服务可以以多种路由方式暴露给前端访问,该服务对应的上游服务就是1个API。 告诉Kong怎么把网关收到的请求发送到某个特定的后台服务。

  • Services:是多个Upstream的集合,是Route的转发目标。不要把Services当作后端的具体API,要把它当作一个大的服务,该服务下面有多个API(endpoint or route)

  • Consumer:是API的用户,里面记录用户的一些信息。

  • Plugin:是插件,plugin可以是全局的,绑定到Service,绑定到Router,绑定到Consumer。

  • Certificate:是https证书。

  • Sni:是域名与Certificate的绑定,指定了一个域名对应的https证书。

  • Upstream:表示虚拟主机名,可用于通过多个服务(目标)对传入请求进行负载均衡。例如:service.v1.xyz 为Service对象命名的上游host是service.v1.xyz对此服务的请求将代理到上游定义的目标。

  • Target:目标IP地址/主机名,其端口表示后端服务的实例,是最终处理请求的Backend服务。每个上游都可以有多个target,并且可以动态添加Target。 由于Upstream维护Target的更改历史记录,因此无法删除或者修改Target。要禁用目标,请发布一个新的Target weight=0,或者使用DELETE来完成相同的操作。

Kong插件的格式

一个完整的插件目录结构应该像下面这样:

image-20200831151628965

各个模块的功能:

模块名 描述 是否必需
api.lua 插件需要向 Admin API 暴露接口时使用 N
daos.lua 数据层相关,当插件需要访问数据库时配置 N
handler.lua 插件的主要逻辑,这个将会被 Kong 在不同阶段执行其对应的 handler Y
migrations / *.lua 插件依赖的数据表结构,启用了 daos.lua 时需要定义 N
schema.lua 插件的配置参数定义,主要用于 Kong 参数验证 Y

其中 handler.lua 和 schema.lua 是必需的(rbac_charing下也是只有这两个),上面提到的插件需要暴露出来的方法就定义在 handler.lua 中。

kong插件主要有三个文件

handler.lua 是包含插件逻辑处理相关代码。 schema.lua 包含插件的配置文件。 rockspec 文件是通过luarock安装时用的配置文件。

逻辑处理的代码根据openResty的不同处理阶段分成了不同的函数,根据插件的功能只需要在不同的函数中添加自己的业务逻辑。

跟路径(path)有关的参数

  1. route中的paths参数,表示符合这些请求路径要发到route对应的service中
  2. route中的strip_path 参数,决定kong转发给后端的时候是否保留源请求用于路由匹配的路径
  3. 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)拼接起来发给后端。

配置route时候:这里的 Path 就是具体业务API的路径(endpoint)。Hosts不设置会默认采用Services里的Host,但是一旦设置了,客户端请求该route的时候必须带上设置的host,且必须一致。

如果Strip path设置为YES,这里的 Path 可以加一个前缀,如:/passport/users,但最终会映射到后端真实的API /users。Kong转发到后端服务的时候会把前缀/passport部分去掉。客户端调用API必须和Routes里的Path一致才行(/passport/users),否则会得到404,无法匹配。用户的请求是先匹配route,然后转发到service。

参考链接

微服务与API 网关(下)- Kong能为我们做什么?

企业级API网关Kong系列

Kong 插件加载机制概述

Kong-负载均衡参考

Kong负载均衡的实现

upstream和target详解