云原生架构下的 API 网关实践: Kong (二)

6,455 阅读12分钟

Kong 是 Mashape 开源的一款云原生架构下的分布式 API 网关,其性能和可扩展性在同类组件中,表现都很优异。Kong 官方提供了很多直接可用的插件,此外,Kong 还可以通过插件扩展已有功能。

本文的主要内容:

  • 什么是云原生网关?
  • Kong 介绍
  • Kong 的基本架构
  • 使用 Kong 构建服务网关
  • 几种常用插件应用
  • 自定义插件的实践

文章篇幅较长,后半部分内容将会在下一篇文章介绍,敬请关注。

什么是云原生网关

什么是云原生

本文的标题是:云原生架构下的 API 网关实践。首先谈谈关于云原生的具体定义,仁者见仁智者见智。

Pivotal 是云原生应用的提出者,并推出了 Pivotal Cloud Foundry 云原生应用平台和 Spring 开源 Java 开发框架,成为云原生应用架构中先驱者和探路者。Pivotal 公司的 Matt Stine 关于云原生应用架构的定义,提出来几个主要特征:

  • 符合12因素应用
  • 面向微服务架构
  • 自服务敏捷架构
  • 基于API的协作
  • 抗脆弱性

随着技术的发展,云原生的概念也在不断的完善。云原生的定义未来还会变,本文参考 CNCF V1.0 的定义:

云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式 API。

因此,云原生网关很重要的特性之一,就是能够快速集成到持续发布的云原生环境中。

为什么需要 API 网关?

当使用单体应用程序架构时,客户端(Web 或移动端)通过向后端应用程序发起一次 REST 调用来获取数据。负载均衡器将请求路由给 N 个相同的应用程序实例中的一个。然后应用程序会查询各种数据库表,并将响应返回给客户端。微服务架构下,单体应用被切割成多个微服务,如果将所有的微服务直接对外暴露,势必会出现安全方面的各种问题。

客户端可以直接向每个微服务发送请求,其问题主要如下:

  • 客户端需求和每个微服务暴露的细粒度 API 不匹配。
  • 部分服务使用的协议不是Web友好协议。可能使用 Thrift 二进制 RPC,也可能使用 AMQP 消息传递协议。
  • 微服务难以重构。如果合并两个服务,或者将一个服务拆分成两个或更多服务,这类重构就非常困难了。

服务端的各个服务直接暴露给客户端调用势必会引起各种问题。同时,服务端的各个服务可扩展和伸缩性很差。API 网关是微服务架构中的基础组件,位于接入层之下和业务服务层之上,如前所述的这些功能适合在 API 网关实现。

关于服务网关的开源组件,有 Netflix Zuul、Spring Cloud Gateway、Kong、Traefik、NGINX 和服务网关类型的 Envoy 等。在之前的文章已经介绍过可编程的新型网关:Spring Cloud Gateway,需要了解的读者可以查看 Spring Cloud Gateway。 本文主要介绍现代微服务网关 Kong,在 Kong 的官网介绍中,第一条特性便是 Kong 的云原生属性:与平台无关,Kong 可以从裸机运行到 Kubernetes。本文基于 Kong 1.2.1,自定义插件部分会涉及部分 Lua 编码,适合服务端开发和运维人员。

Kong 介绍

Mashape 开源的高性能高可用 API 网关和 API 服务管理层——KONG(基于NGINX)特点尤为突出,它可以通过插件扩展已有功能,这些插件(使用 lua 编写)在 API 请求响应循环的生命周期中被执行。与此同时,KONG 本身提供包括HTTP基本认证、密钥认证、CORS、TCP、UDP、文件日志、API请求限流、请求转发及NGINX监控等基本功能。目前,Kong 在 Mashape 管理了超过 15,000 个 API,为200,000开发者提供了每月数十亿的请求支持。

  1. 什么是 Kong
    当我们决定对应用进行微服务改造时,应用客户端如何与微服务交互的问题也随之而来,毕竟服务数量的增加会直接导致部署授权、负载均衡、通信管理、分析和改变的难度增加。

    面对以上问题,API GATEWAY是一个不错的解决方案,其所提供的访问限制、安全、流量控制、分析监控、日志、请求转发、合成和协议转换功能,可以解放开发者去把精力集中在具体逻辑的代码,而不是把时间花费在考虑如何解决应用和其他微服务链接的问题上。

  2. 为什么使用Kong
    在众多 API GATEWAY 框架中,Mashape 开源的高性能高可用API网关和API服务管理层——KONG(基于 NGINX)特点尤为突出,它可以通过插件扩展已有功能,这些插件(使用 lua 编写)在API请求响应循环的生命周期中被执行。于此同时,KONG本身提供包括 HTTP 基本认证、密钥认证、CORS、TCP、UDP、文件日志、API请求限流、请求转发及 NGINX 监控等基本功能。目前,Kong 在 Mashape 管理了超过 15,000 个 API,为 200,000 开发者提供了每月数十亿的请求支持。

Kong 的基本架构

Kong 是 Mashape 开源的高性能高可用 API 网关和 API 服务管理层,一款基于 Nginx_Lua 模块写的高可用服务网关,由于 Kong 是基于 Nginx 的,所以可以水平扩展多个 Kong 服务器。通过前置的负载均衡配置把请求均匀地分发到各个 Server,来应对大批量的网络请求。

图片来源 Kong 官网
图片来源 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。

术语

Kong 中常用的术语介绍,这些术语会在下面的实践中经常用到。

  • Route:请求的转发规则,按照 Hostname 和 PATH,将请求转发给 Service;
  • Services:多个 Upstream 的集合,是 Route 的转发目标;
  • Consumer:API 的用户,记录用户信息;
  • Plugin:插件,可以是全局的,也可以绑定到 Service、Router 或者 Consumer;
  • Certificate:https 配置的证书;
  • Sni:域名与 Certificate 的绑定,指定了一个域名对应的 https 证书;
  • Upstream:上游对象用来表示虚拟主机名,拥有多个服务(目标)时,会对请求进行负载均衡;
  • Target:最终处理请求的 Backend 服务。

使用 Kong 构建服务网关

客户端的请求将会首先经由微服务网关处理,一些通用的功能切面将会在网关生效,即 Kong 中的插件,之后才会将请求进行转发到对应的 Backend 服务,如下图所示。

图片来源 https://konghq.com/blog/kong-1-0-ga/
图片来源 https://konghq.com/blog/kong-1-0-ga/
在介绍了为什么需要微服务网关和 Kong 的相关概念之后,我们将会进行实战,使用 Kong 构建网关。

安装实践

目前 Kong 的最新版本 1.2,Kong 的安装支持多种方式。官方支持如下列出方式的安装:

图片来源 Kong 官网
图片来源 Kong 官网

除了官方提供的安装方式,还有社区提供的安装方式,详细了解参见:konghq.com/install/。

笔者为了方便,基于 docker 的方式安装。docker-compose.yml 中定义的镜像、依赖和参数如下所示:

version: "3.7"
services:
  kong:
    image: kong:1.1.2
    environment:
     - "KONG_DATABASE=postgres"
     - "KONG_PG_HOST=kong-database"
     - "KONG_CASSANDRA_CONTACT_POINTS=kong-database"
     - "KONG_PROXY_ACCESS_LOG=/dev/stdout"
     - "KONG_ADMIN_ACCESS_LOG=/dev/stdout"
     - "KONG_PROXY_ERROR_LOG=/dev/stderr"
     - "KONG_ADMIN_ERROR_LOG=/dev/stderr"
     - "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl"
    ports:
     - 8000:8000
     - 8443:8443
     - 8001:8001
     - 8444:8444
    networks:
     - kong-net
    depends_on:
      - kong-database
  konga:
    image: pantsel/konga
    environment:
     - "TOKEN_SECRET=blueskykong.com"
     - "NODE_ENV=production"
    ports:
     - 8080:1337
    networks:
     - kong-net

    depends_on:
      - kong-database
  kong-database:
    image: postgres:9.6
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_USER=kong
      - POSTGRES_DB=kong
    networks:
      - kong-net
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /data/data/postgresql:/var/lib/postgresql/data

networks:
  kong-net:
    external: true

如上的 docker-compose.yml 会启动三个容器服务:Kong、konga 和 kong-database。这三个容器之间的通信需要增加 network 段,把容器放在同一个网段内,相关链接修改为容器名称来访问:

docker network create kong-net

所启动的三个容器服务,除了 Kong 之外的两个服务:konga 是 Kong 的 Dashboard,基于 js 的客户端管理工具,对外暴露的端口为 8080;kong-database 是 Kong 的数据库服务,存储配置信息,这里使用的是 postgres。需要注意的是,在启动 Kong 容器之前,需要保持数据库的 Docker 容器在运行状态,并执行如下初始化数据库的操作:

docker run --rm \
     --network=kong-net \
     -e "KONG_DATABASE=postgres" \
     -e "KONG_PG_HOST=kong-database" \
     kong:latest kong migrations bootstrap

数据库初始化成功后,再次启动 docker-compose.yml 服务就可以了。我们看到 Kong 映射出多个端口,默认情况下,Kong 监听的端口为:

  • 8000:此端口是 Kong 用来监听来自客户端传入的 HTTP 请求,并将此请求转发到上有服务器;(Kong 根据配置的规则转发到真实的后台服务地址)
  • 8443:此端口是 Kong 用来监听来自客户端传入的HTTPS请求的。它跟8000端口的功能类似,转发 HTTPS 请求的。可以通过修改配置文件来禁止它;
  • 8001:Admin API,通过此端口,管理者可以对 Kong 的监听服务进行配置,插件设置、API 的增删改查、以及负载均衡等一系列的配置都是通过 8001 端口进行管理;
  • 8444:通过此端口,管理者可以对 HTTPS 请求进行监控。

容器都启动好之后,我们来验证一下:

curl -i http://localhost:8001/

HTTP/1.1 200 OK
Date: Sat, 20 Jul 2019 08:39:08 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Server: kong/1.1.2
Content-Length: 5785

...

如上的结果,表示安装正确,可以正常使用 Kong。访问 http://localhost:8080 访问 Konga 的管理界面,第一次登录使用需要创建管理员帐号和密码。

更多内容参照官网的安装文档。至此,Kong 以及管理工具都已安装完成,下面将进入 API Gateway 的具体实践。

创建服务

如我们在术语部分的介绍,服务是上游服务的抽象,可以是一个应用,或者具体某个接口。Kong 提供了管理接口,我们可以通过请求 8001 管理接口直接创建,也可以通过安装的管理界面,实现的效果是一样的。

curl -i -X POST \
--url http://localhost:8001/services/ \
--data 'name=aoho-blog' \
--data 'url=http://blueskykong.com/'

我们创建一个服务名为 aoho-blog,指定转发的地址为 http://blueskykong.com。可以在管理界面中看到如下的记录:

其中的一些参数,如 Retries、Connect timeout、Write/Read timeout 等参数。

创建路由

创建好服务之后,我们需要创建具体的 API 路由。路由是请求的转发规则,根据 Hostname 和 PATH,将请求转发。

curl -i -X POST \
--url http://localhost:8001/services/aoho-blog/routes \
--data 'hosts[]=blueskykong.com' \
--data 'paths[]=/api/blog'

如上在 aoho-blog 中创建了一个访问 /api/blog 的路由,在管理界面可以看到相应的记录:

创建好路由之后,我们就可以访问 /api/blog。

Kong 默认通过 8000 端口处理代理的请求。成功的响应意味着 Kong 将 http://localhost:8000 的请求转发到配置的 URL,并将响应转发给我们。需要注意的是,如果 API 暴露的地址与前面 Host 定义的地址(blueskykong.com)不一致,就需要在请求的 Headers 里面加入 Header,Kong 根据上面请求中定义的 Header:Host,执行此操作。

小结

本文主要介绍了云原生和云原生网关的相关概念,随后具体介绍了本文的主角 Kong 的特性和基本架构。重点介绍了如何使用 Kong 构建服务网关。Kong 官方和社区提供了很多插件,关于 Kong 中的常用插件使用,以及如何定制自己的 Kong 插件,将会在下文讲解。

推荐阅读

云原生架构下的 API 网关实践

订阅最新文章,欢迎关注我的公众号

微信公众号