Kong 是 Mashape 开源的一款云原生架构下的分布式 API 网关,其性能和可扩展性在同类组件中,表现都很优异。Kong 官方提供了很多直接可用的插件,此外,Kong 还可以通过插件扩展已有功能。
本文的主要内容:
在介绍云原生网关的概念之前,首先谈谈关于云原生的具体定义。关于云原生的定义,仁者见仁智者见智。
Pivotal 是云原生应用的提出者,并推出了 Pivotal Cloud Foundry 云原生应用平台和 Spring 开源 Java 开发框架,成为云原生应用架构中先驱者和探路者。Pivotal 公司的 Matt Stine 关于云原生应用架构的定义,提出来几个主要特征:
随着技术的发展,云原生的概念也在不断的完善。云原生的定义未来还会变,本文参考 CNCF V1.0 的定义:
云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式 API。
因此,云原生网关很重要的特性之一,就是能够快速集成到持续发布的云原生环境中。
当使用单体应用程序架构时,客户端(Web 或移动端)通过向后端应用程序发起一次 REST 调用来获取数据。负载均衡器将请求路由给 N 个相同的应用程序实例中的一个。然后应用程序会查询各种数据库表,并将响应返回给客户端。微服务架构下,单体应用被切割成多个微服务,如果将所有的微服务直接对外暴露,势必会出现安全方面的各种问题。
客户端可以直接向每个微服务发送请求,其问题主要如下:
服务端的各个服务直接暴露给客户端调用势必会引起各种问题。同时,服务端的各个服务可扩展和伸缩性很差。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 编码,适合服务端开发和运维人员。
Mashape 开源的高性能高可用 API 网关和 API 服务管理层——KONG(基于NGINX)特点尤为突出,它可以通过插件扩展已有功能,这些插件(使用 lua 编写)在 API 请求响应循环的生命周期中被执行。与此同时,KONG 本身提供包括HTTP基本认证、密钥认证、CORS、TCP、UDP、文件日志、API请求限流、请求转发及NGINX监控等基本功能。目前,Kong 在 Mashape 管理了超过 15,000 个 API,为200,000开发者提供了每月数十亿的请求支持。
Kong 是 Mashape 开源的高性能高可用 API 网关和 API 服务管理层,一款基于 Nginx_Lua 模块写的高可用服务网关,由于 Kong 是基于 Nginx 的,所以可以水平扩展多个 Kong 服务器。通过前置的负载均衡配置把请求均匀地分发到各个 Server,来应对大批量的网络请求。
图片来源 Kong 官网
Kong 主要有三个组件:
Kong 采用插件机制进行功能定制,插件集(可以是 0 或 N 个)在 API 请求响应循环的生命周期中被执行。插件使用 Lua 编写,基础功能包括:HTTP 基本认证、密钥认证、CORS(Cross-Origin Resource Sharing,跨域资源共享)、TCP、UDP、文件日志、API 请求限流、请求转发以及 Nginx 监控等。
Kong 网关具有以下的特性:
Kong 中常用的术语介绍,这些术语会在下面的实践中经常用到。
客户端的请求将会首先经由微服务网关处理,一些通用的功能切面将会在网关生效,即 Kong 中的插件,之后才会将请求进行转发到对应的 Backend 服务,如下图所示。
图片来源 https://konghq.com/blog/kong-1-0-ga/
在介绍了为什么需要微服务网关和 Kong 的相关概念之后,我们将会进行实战,使用 Kong 构建网关。
目前 Kong 的最新版本 1.2,Kong 的安装支持多种方式。官方支持如下列出方式的安装:
图片来源 Kong 官网
除了官方提供的安装方式,还有社区提供的安装方式,详细了解参见:https://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 监听的端口为:
容器都启动好之后,我们来验证一下:
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 插件,将会在下文讲解。