云计算与云原生 — 微服务架构 Kong APIGW 完全解析

网友投稿 971 2022-05-30

目录

文章目录

目录

微服务架构中的 API 问题

微服务架构 APIGW

APIGW 的功能清单

API 的分组聚合

OpenResty

为何 OpenResty 适合用于 APIGW 开发?

Lua Nginx Module

Kong APIGW

Kong 的软件架构

Kong 的安装部署

安装 Kong Server

安装 Kong Dashboard

配置 Kong Server

Kong Admin API 的核心逻辑对象

Service(服务)

Route(路由)

Upstream(上游)

Target(目标)

Consumer(消费者)

Plugins(插件)

CA Certificate(CA 证书)

Certificate 与 SNI

Certificate(证书)

SNI(Server Name Indication,服务器名称指示)

Kong 的基本使用

非安全访问

创建 Service

创建 Route

创建 Upstream

创建 Targets

调用测试

Front-End 安全访问,Backend 非安全访问

使用默认 Kong Proxy API Domain Name 的 TLS 证书

创建 Service

创建 Route

创建 Upstream

测试验证

使用用户自定义的 Domain Name 的 TLS 证书

创建 Certificate

创建 Service

创建 Route

创建 Upstream

调用测试

Front-End 安全访问,Backend 安全访问

微服务架构中的 API 问题

根据 Gartner 对微服务的定义:“微服务是范围狭窄、封装紧密、松散耦合、可独立部署且可独立伸缩的应用程序组件。”

与将模块高度耦合并部署为一个大的应用程序相比,微服务的目标是将应用程序充分分解或者解耦为松散耦合的许多微服务或者模块,这样做对下面几点有很大帮助:

每个微服务都可以独立于应用程序中的同级服务进行部署、升级、扩展、维护和重新启动。

通过自治的跨职能团队进行敏捷开发和敏捷部署。

运用技术时具备灵活性和可扩展性。

在微服务架构中,我们根据各自的特定需求部署不同的松耦合服务,其中每个服务都有其更细粒度的 API 模型,用以服务于不同的客户端(Web,移动和第三方 API)。

在考虑客户端与每个已部署的微服务直接通信的问题时,应考虑以下挑战:

如果微服务向客户端公开了细粒度的 API,则客户端应向每个微服务发出请求。在典型的单页中,可能需要进行多次服务器往返,才能满足请求。对于较差的网络条件下运行的设备(例如:移动设备),这可能会更糟。

微服务中存在的多种通信协议(例如:gRpc、thrift、REST、AMQP 等)使客户端很难轻松采用所有这些协议。

必须在每个微服务中实现通用网关功能(例如:身份验证、授权、日志记录)。

在不中断客户端连接的情况下,很难在微服务中进行更改。例如:在合并或划分微服务时,可能需要重新编写客户端部分代码。

微服务架构 APIGW

为了解决上述挑战,人们引入了一个 API 网关层,位于客户端和服务器之间,充当从客户端到服务器的反向代理路由请求。与面向对象设计的模式相似,它为封装底层系统架构的 API 提供了一个单一的入口,称为 API 网关。随着微服务架构概念的提出,APIGW 成为了微服务架构的一个标配组件。

APIGW,顾名思义,是出现在系统边界上的一个面向 API 的、串行集中式的强管控服务,这里的边界是企业 IT 系统的边界,可以理解为企业级应用防火墙,主要起到隔离外部访问与内部系统的作用。APIGW 是系统对外的唯一入口,封装了系统内部架构,为每个客户端提供定制的 API。所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有非业务功能。

单节点网关

多节点网关

简而言之,APIGW 的行为就像 API 管理员一样,但重要的是:不要将 API 管理与 API Gateway 混为一谈。

APIGW 的功能清单

路由:动态路由规则,网关封装了底层系统并与客户端分离,为客户端提供了与微服务系统进行通信的单个入口点。

安全:IAM 权限认证、鉴权、授权、脱敏,流量清洗,后端签名(保证全链路可信调用),IP 黑白名单(非法调用的限制)。

缓存:缓存响应结果。

监控:记录请求响应数据,API 耗时分析,性能监控。

限流:流量控制,错峰流控,可以定义多种限流规则。

高可用:API 高可用,负载均衡,容错机制。

服务发现。

重试策略、熔断。

日志、链路追踪。

APIGW 具有以下优势:

易于监控:可在微服务网关收集监控数据并将其推送到外部系统进行分析。

易于认证:可在微服务网关上进行认证,然后再将请求转发到后端的微服务,从而无需在每个微服务中进行认证。

减少了客户端与各个微服务之间的交互次数。

APIGW 实现的注意事项:

可能产生的单点故障或者瓶颈。

由于通过 APIGW 进行了额外的网络跳转以及复杂性风险,意味着响应时间增长了。

API 的分组聚合

APIGW 中的一些 API 请求直接映射到单个服务的 API 上,可以通过将请求路由到相应的微服务来提供服务。但是,在需要从多个微服务获得结果的复杂 API 操作的情况下,可以通过 API 组合/聚合来提供服务。在需要同步通信的情况下,如果服务彼此依赖,则必须遵循链式组合模式。组合层必须支持很大一部分的集成功能,例如:转换、编排、弹性和稳定性模式。

微服务架构软件系统必须配备特殊的分发器和聚合器功能(或微服务)。分发者负责分解成细粒度的任务,并将这些任务分发给微服务实例。聚合器负责聚合业务工作流从组合微服务中得出的结果。

具备复杂功能的网关会增大测试和部署的难度。强烈建议大家避免在 APIGW 中进行聚合和数据转换。领域专属的功能更应该遵循软件开发实践的定义,在应用程序的代码中完成。Netflix API Gateway Zuul 2 从他们在 Zuul 到原始系统的网关中,删除了许多业务逻辑。

OpenResty

OpenResty 是一个基于 Nginx + Lua 的高性能 Web 平台,本质是一个 Web 应用服务器。它打包了标准的 Nginx 内核,并集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。

OpenResty 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用系统 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统、Web 服务和动态网关(APIGW)。

OpenResty 的目标是让你的 Web Service 直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。

注意,OpenResty 不是 Nginx 的分支,整合了一组 Lua 扩展功能模块后重新发布的 Nginx。

为何 OpenResty 适合用于 APIGW 开发?

对于 APIGW,有一个最基础的核心功能就是需要实现 API Service 的代理路由,而这个本身也是 Nginx 反向代理能够提供的一个标准功能。如果应用场景比较简单,仅仅是需求实现统一接口对外暴露,实际上很多企业实际并没有采用 APIGW,而是直接采用了 Nginx 来替代 APIGW 的服务代理路由功能。

可见,基于 Nginx 来实现一个 APIGW(在其内部来扩展一个 Web Container 能力),可以利用 Nginx 本身的服务代理路由和性能优势。而 OpenResty 本身就是基于 Nginx 服务器的,在其 Worker 里面内嵌了一个 LuaJVM,通过这种方式来实现了两者的融合。同时,还可以通过开发和定制各种 Lua 库来进行快速的功能扩展。

所以,基于 OpenResty 来扩展动态网关功能是一个很好的选择。

Lua Nginx Module

由于 Nginx 把一个请求分成了很多阶段,这样第三方模块就可以根据自己行为,挂载到不同阶段进行处理达到目的,OpenResty 应用了 Nginx 的这个特性。

Nginx 处理一个请求的处理流程:

OpenResty 的本质是一个在 Nginx 上运行的 Lua 应用程序,由 lua-nginx-module 实现。

init_by_lua*:发生在 Nginx Master 进程启动阶段。这里会对数据访问层进行初始化,加载插件的代码,构造路由规则表。

init_worker_by_lua*:发生在 Nginx Worker 进程启动阶段。这里会开启数据同步机制,执行每个插件的 init_worker 方法。

set_by_lua*:处理请求的第一个执行阶段。这里可以做一些流程分支处理判断变量初始化。Kong 并没有使用该阶段。

rewrite_by_lua*:这里可以对请求做一些修改。Kong 在这里会把处理代理给插件的 rewrite 方法。

access_by_lua*:Kong 在这里对请求进行路由匹配,找到 Upstream 的 Backend Real Server。

balancer_by_lua*:Kong 在这里会把上一阶段找到的 Backend Real Server 设置给 Nginx 的 Load Balancer。如果设置了重试次数,此阶段可能会被执行多次。

header_filter_by_lua*:这里可以对响应头做一些处理。Kong 在这里会把处理代理给插件的 header_filter 方法。

body_filter_by_lua*:这里可以对响应体做一些处理。Kong 在这里会把处理代理给插件的 body_filter 方法。

log_by_lua*:Kong 在这里会通过插件异步记录日志和一些 metrics 数据。

上述几个阶段的存在,是 OpenResty 不同于其他 Web 平台编程的明显特征。不同的阶段,有不同的处理行为,这是 OpenResty 的一大特色。

Kong APIGW

Kong 是一款由 Mashape 公司开源的 APIGW 软件,基于 OpenResty(Nginx + Lua 模块)实现,具有高可用、易扩展的特性。Kong 在 Mashape 上管理了超过 15,000 个 API,为 200,000 开发者提供了每月数十亿的请求支持。

官网:https://konghq.com/kong/

Github:https://github.com/Kong/kong

Docs:https://docs.konghq.com/

中文文档:https://github.com/qianyugang/kong-docs-cn

Kong 和 OpenResty 一起打包发行,其中已经包含了 lua-nginx-module。可以简单理解为:Kong > OpenResty > Nginx + lua-nginx-module。

Kong 的特性:

可扩展:Kong Server 支持水平扩展。

插件:Kong Server 实现了 Plugin 机制进行功能定制,通过 RESTful Admin API 安装和配置插件,

在任何基础设施上运行:Kong 可以部署在云端、机房、或者混合环境,包括单个或多个数据中心。

Kong 的功能:

Cloud Native(云原生):与平台无关,Kong 可以从裸机运行到 Kubernetes。

Dynamic Load Balancing(动态路由):Kong 的背后是 OpenResty + Lua,所以从 OpenResty 继承了动态路由的特性。

Circuit Breaker(熔断)

Health Checks(健康检查)

Logging(日志):可以记录通过 Kong 的 HTTP,TCP,UDP 请求和响应。

Security(安全访问):权限控制,IP 黑白名单,同样是 OpenResty 的特性。

SSL:Setup a Specific SSL Certificate for an underlying service or API。

监控:Kong 提供了实时监控插件。

认证:支持 HMAC、JWT、Basic、OAuth2.0 等常用协议。

Rate-limiting(限流):Block and throttle requests based on many variables。

REST API:通过 Rest API 进行配置管理,从繁琐的配置文件中解放。

高可用性:天然支持分布式。

Plugins(插件机制):提供众多开箱即用的插件,且有易于扩展的自定义插件接口,用户可以使用 Lua 自行开发插件。

Kong 的软件架构

Kong 有 3 个核心组件:

Kong Server:主体程序,基于 Nginx 的 HTTP APIGW 服务器,用来接收 API 请求。

Apache Cassandra/PostgreSQL:后端数据库。

Kong Dashboard:UI 管理工具。

Kong 的分层架构:

Nginx 层:Niginx Server。

OpenResty 层:可以通过 Lua 模块来进行功能扩展是 Nginx 的一大特点,OpenResty 就是一组实现了 Web 平台的基础 Lua 模块,并与 Nginx 一起打包发布。

Cluster & Data Store 层:持久化 Kong 所需要的配置和生产数据,目前支持 Apache Cassandra 和 PostgreSQL 两种后端数据库。Cassandra 是分布式的 NoSQL 数据库,天然支持高可用。

Plugin 层:Kong 基于 OpenResty 可以继续实现各类 Plugin 继而满足 APIGW 的基本功能,且可以通过添加新的插件进行扩展,这些插件可以通过 RESTful Admin API 轻松配置。

RESTful APIs 层:包括 RESTful Admin API 和 RESTful Proxy API。

可见,Kong 覆盖了 Nginx 的所有功能,包括:反向代理、负载均衡以及基本的缓存、安全的认证、限流限速等。同时还支持 Nginx 等 Web 服务器实现不了的功能,例如:动态上游、动态 SSL 证书、动态限流限速,以及主动/被动健康检查、服务熔断等。

Kong 的安装部署

安装 Kong Server

官方安装文档 base on docker

注:因为 Kong Dashboard 仅支持 1.x 版本的 Kong Server,所以我们选择安装较低的版本。

Create a Docker network

$ docker network create kong-net 33892a744b782e5f7d86032372ff1e32c51d0756e196b0563e16515d6b379218 $ docker network ls NETWORK ID NAME DRIVER SCOPE 33892a744b78 kong-net bridge local $ ifconfig br-33892a744b78: flags=4099 mtu 1500 inet 172.18.0.1 netmask 255.255.0.0 broadcast 172.18.255.255 ether 02:42:93:e6:d7:5d txqueuelen 0 (Ethernet) RX packets 6 bytes 416 (416.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 6 bytes 416 (416.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 $ brctl show bridge name bridge id STP enabled interfaces br-33892a744b78 8000.024293e6d75d no

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

Start your database (PostgreSQL)

$ docker run -d --name kong-database \ --network=kong-net \ -p 5432:5432 \ -e "POSTGRES_USER=kong" \ -e "POSTGRES_DB=kong" \ -e "POSTGRES_PASSWORD=kong" \ postgres:9.6

1

2

3

4

5

6

7

Prepare your database (Migrations)

$ docker run --rm \ --network=kong-net \ -e "KONG_DATABASE=postgres" \ -e "KONG_PG_HOST=kong-database" \ -e "KONG_PG_USER=kong" \ -e "KONG_PG_PASSWORD=kong" \ -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \ kong:1.5.1-centos kong migrations bootstrap

1

2

3

4

5

6

7

8

Start Kong

$ docker run -d --name kong \ --network=kong-net \ -e "KONG_DATABASE=postgres" \ -e "KONG_PG_HOST=kong-database" \ -e "KONG_PG_USER=kong" \ -e "KONG_PG_PASSWORD=kong" \ -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \ -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \ -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \ -e "KONG_PROXY_ERROR_LOG=/dev/stderr" \ -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \ -e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" \ -p 8000:8000 \ -p 8443:8443 \ -p 127.0.0.1:8001:8001 \ -p 127.0.0.1:8444:8444 \ kong:1.5.1-centos

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

Use Kong

$ curl -i http://localhost:8001/ HTTP/1.1 200 OK Date: Tue, 15 Dec 2020 01:05:20 GMT Content-Type: application/json; charset=utf-8 Connection: keep-alive Access-Control-Allow-Origin: * Server: kong/1.5.1 Content-Length: 6971 X-Kong-Admin-Latency: 147

1

2

3

4

5

6

7

8

9

Kong Server 启动后监听了 4 个端口:

8000:HTTP Proxy API

8443:HTTPS Proxy API

8001:HTTP Admin API

8444:HTTPS Admin API

Kong Server 的进程:

/usr/local/openresty/nginx/sbin/nginx -p /usr/local/kong -c nginx.conf

1

Kong 指令行选项:

$ kong Usage: kong COMMAND [OPTIONS] The available commands are: check config health migrations prepare quit reload restart roar start stop version Options: --v verbose --vv debug

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

安装 Kong Dashboard

Github:https://github.com/pantsel/konga

安装

docker run -p 1337:1337 \ --network=kong-net \ -e "TOKEN_SECRET=konga" \ -e "DB_ADAPTER=postgres" \ -e "DB_HOST=kong-database" \ -e "DB_PORT=5432" \ -e "DB_USER=kong" \ -e "DB_PASSWORD=kong" \ -e "DB_DATABASE=konga_database" \ -e "NODE_ENV=development" \ --name konga \ pantsel/konga:latest

1

2

3

4

5

6

7

8

9

10

11

12

访问:http://{your server’s public ip}:1337

登录 Konga 之后的第一件事情就是需要添加 Kong Server Connection。

配置 Kong Server

安装完 Kong Server 后主要关注两个文件目录:

配置文件目录:/etc/kong

运行文件目录:/usr/local/kong

如果我们需要修改 Nginx 的配置,实际上我们可以直接通过 Kong 的配置文件注入到 Nginx 配置,Kong 在启动的时候会生成 Nginx 的配置文件 nginx.conf 和 nginx-kong.conf。

Kong 的配置,分为以下几种:

常规配置:服务运行目录,插件加载,日志等。

Nginx 配置:Nginx 监听 IP、端口配置等,用于 Kong 在启动的时候生成 Nginx 配置文件。

数据库存储配置:数据库类型,地址、用户名密码等。

数据库缓存配置:数据的缓存规则,Kong 会缓存诸如 API 信息、用户、凭证等信息,以减少访问数据库次数提高性能。

DNS 解析器配置:默认情况会使用系统设置,如:hosts 和 resolv.conf 的配置,你也可以通过 DNS 的解析器配置来修改。

其他杂项配置:继承自 lua-nginx 模块的其他设置允许更多的灵活性和高级用法。

Admin Server:

server { server_name kong_admin; listen 0.0.0.0:8001; listen 0.0.0.0:8444 ssl; access_log /dev/stdout; error_log /dev/stderr notice; client_max_body_size 10m; client_body_buffer_size 10m; ssl_certificate /usr/local/kong/ssl/admin-kong-default.crt; ssl_certificate_key /usr/local/kong/ssl/admin-kong-default.key; ssl_session_cache shared:AdminSSL:10m; # injected nginx_admin_* directives location / { default_type application/json; content_by_lua_block { Kong.admin_content() } header_filter_by_lua_block { Kong.admin_header_filter() } } location /nginx_status { internal; access_log off; stub_status; } location /robots.txt { return 200 'User-agent: *\nDisallow: /'; } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

Proxy Server:

server { server_name kong; listen 0.0.0.0:8000 reuseport backlog=16384; listen 0.0.0.0:8443 ssl http2 reuseport backlog=16384; error_page 400 404 408 411 412 413 414 417 494 /kong_error_handler; error_page 500 502 503 504 /kong_error_handler; access_log /dev/stdout; error_log /dev/stderr notice; ssl_certificate /usr/local/kong/ssl/kong-default.crt; ssl_certificate_key /usr/local/kong/ssl/kong-default.key; ssl_session_cache shared:SSL:10m; ssl_certificate_by_lua_block { Kong.ssl_certificate() } # injected nginx_proxy_* directives real_ip_header X-Real-IP; real_ip_recursive off; rewrite_by_lua_block { Kong.rewrite() } access_by_lua_block { Kong.access() } header_filter_by_lua_block { Kong.header_filter() } body_filter_by_lua_block { Kong.body_filter() } log_by_lua_block { Kong.log() } ... }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

Kong Admin API 的核心逻辑对象

Admin API 官方文档:https://docs.konghq.com/2.2.x/admin-api

Service(服务)

Service(服务),顾名思义是一个实际的 Upstream API Service 的抽象对象,例如:用户创建 API、用户计费 API,etc。本质是自定义的一个 URL path 字符串,e.g. /some_api。此外,Service 也可以单独指定其 Protocol、host 和 Port。

注:

Upstream Server:Backend 的 Real Server。

Upstream API Service:Backend 的 Real API Service。

Admin API URL:

# 创建 Service,或查询所有已创建的 Services。 /services # 指定一个 Certificate 创建 Service,或查询所有关联绑定了该 Certificate 的 Services。 /certificates/{certificate name or id}/services

1

2

3

4

5

Request Body:

path(可选):指定 Upstream API Service 的 URL path。

host(必选):指定 Upstream Server 的 Host(Domain Name)。

port(必选):指定 Upstream Server 的 Port,默认为 80。

protocol(必选):指定 Upstream API Service 的协议类型,包括:grpc、grpcs、http、https、tcp、udp、tls,默认为 http。

connect_timeout(可选):指定客户端连接超时时长。

read_timeout(可选):指定客户端读取超时时长。

write_timeout(可选):指定客户端写入超时时长。

client_certificate(可选):指定客户端与 Upstream API Service 建立 TLS 通信的客户端签发证书。

ca_certificates(可选):指定客户端与 Upstream API Service 建立 TLS 通信的 CA 证书。

retries(可选):指定与 Upstream API Service 建立连接的重试次数,默认 5 次。

Request Body Example:

{ "id": "9748f662-7711-4a90-8186-dc02f10eb0f5", "created_at": 1422386534, "updated_at": 1422386534, "name": "my-service", "path": "/some_api", "host": "example.com", "port": 80, "protocol": "http", "connect_timeout": 60000, "write_timeout": 60000, "read_timeout": 60000, "tls_verify": true, "tls_verify_depth": null, "client_certificate": {"id":"4e3ad2e4-0bc4-4638-8e34-c84a417ba39b"}, "ca_certificates": ["4e3ad2e4-0bc4-4638-8e34-c84a417ba39b", "51e77dc2-8f3e-4afa-9d0e-0e3bbbcfd515"] "retries": 5, "tags": ["user-level", "low-priority"], }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

Route(路由)

Route(路由)通过定义一系列规则(e.g. HTTP Method,HTTP URL,etc)来匹配一类 Frontend Client Request。每个 Route 都会关联一个 Service,Service 和 Route 是 1:N 关系。当 Route 匹配到一个 Frontend Client Request 时,就会将这个 Request 代理到其关联的 Service 中,然后 Service 再转发到 Backend。并且在代理的过程中会将 Request 通过 Plugin 的处理。

Route 和 Service 的解耦为 Kong 提供了一种强大的路由机制,是一种非常细粒度的路由分发机制。不同协议类型的匹配规则限制如下,否者无法创建 Route Object。

http:至少包含 HTTP methods、hosts、headers、paths 其中之一。

https:至少包含 HTTPS methods、hosts、headers、paths、snis 其中之一。

tcp:至少包含 sources IP/Port、destinations IP/Port 其中之一。

tls:至少包含 sources IP/Port、destinations IP/Port、snis 其中之一。

grpc:至少包含 hosts、headers、paths 其中之一。

grpcs:至少包含 hosts、headers、paths、snis 其中之一。

Admin API URL:

# Create Route /routes # Create Route Associated to a Specific Service /services/{service name or id}/routes

1

2

3

4

5

Request Body:

service(可选):指定 Route 关联的 Service,可选时,从 Request URL 中获取 Service ID。

protocols(必选):指定 Frontend Client Request 的协议,支持 grpc、grpcs、http、https、tcp、udp、tls 等协议,默认为同时支持 http、https。

methods(条件必选):当协议类型为 HTTP/S 时,指定 Frontend Client Request 的 Methods。

hosts(条件必选):当协议类型为 HTTP/S 时,指定 Frontend Client Request 的 Hosts(Domain Names)。

paths(条件必选):当协议类型为 HTTP/S 时,指定 Frontend Client Request 的 URL paths。

headers(条件必选):当协议类型为 HTTP/S 时,指定 Frontend Client Request 的 headers,注意:HTTP header Host 不可以使用 headers 字段来指定,应该使用 hosts 字段。

strip_path(可选):当协议类型为 HTTP/S 并且匹配到 paths 时,是否删除匹配到的前缀,默认为 true。

preserve_host(必选):当协议类型为 HTTP/S 并且匹配到 hosts 时,使用 Request Header host 的值作为 Domain Name 向 Backend 发起请求,默认为 false。

sources(条件必选):当协议为 TCP/UDP 时,指定源 IP/Ports,支持 CIDR 范围形式。

destinations(条件必选):当协议为 TCP/UDP 时,指定目的 IP/Ports,支持 CIDR 范围形式。

snis(条件必选):指定使用的 SNIs。

Request Body Example:

{ "id": "d35165e2-d03e-461a-bdeb-dad0a112abfe", "created_at": 1422386534, "updated_at": 1422386534, "name": "my-route", "protocols": ["http", "https"], "methods": ["GET", "POST"], "hosts": ["example.com", "foo.test"], "paths": ["/foo", "/bar"], "headers": {"x-another-header":["bla"], "x-my-header":["foo", "bar"]}, "https_redirect_status_code": 426, "regex_priority": 0, "strip_path": true, "path_handling": "v0", "preserve_host": false, "request_buffering": true, "response_buffering": true, "tags": ["user-level", "low-priority"], "service": {"id":"af8330d3-dbdc-48bd-b1be-55b98608834b"} }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

Upstream(上游)

Kong Upstream(上游)与 Nginx Upstream 具有相同的含义,本质是一个 Virtual Hostname(基于 Hostname 的 HTTP 虚拟主机)。

Upstream 的主要作用有两个:

Upstream 和 Service 通过 Host(Domain Name)进行关联的,两者都强调了 Virtual Hostname(基于 Hostname 的 HTTP 虚拟主机)的实现,使用一个 Server IP:Port 可以虚拟出多个 HTTP Server,继而在不同的 HTTP Server 上提供 API Service 服务。

Upstream 位于 Service 和 Targets 之间,可以实现负载均衡的功能。

例如:一个名为 service.v1.xyz 的 Upstream API Service 的 Host 是 service.v1.xyz,那么对这个 API Service 的请求将被代理到具有相同 Host 参数的 Upstream 关联的 Targets 上,以此来实现 Virtual Hostname 和负载均衡的效果。

另外,Upstream 这个逻辑对象还具有健康检查器(Health Checker)的功能,Health Checker 能够检查所有关联的 Backend Targets 的健康情况,以此来自动的启用/禁用一个 Target。Upstream request body 包含了类型丰富的 healthchecks.* 字段。

Admin API URL:

# Create Upstream /upstreams # Create Upstream Associated to a Specific Certificate /certificates/{certificate name or id}/upstreams

1

2

3

4

5

Request Body:

algorithm(可选):指定负载均衡算法,包括:consistent-hashing、least-connections、round-robin,默认为 round-robin。

host_header(可选):指定需要给代理的客户端请求的 HTTP header Host 的 hostname。

client_certificate(可选):指定于 Backend Real Server(Target)建立 TLS 通信的客户端证书。

Request Body EXAMPLE:

{ "id": "58c8ccbb-eafb-4566-991f-2ed4f678fa70", "created_at": 1422386534, "name": "my-upstream", "algorithm": "round-robin", "hash_on": "none", "hash_fallback": "none", "hash_on_cookie_path": "/", "slots": 10000, "healthchecks": { "active": { "https_verify_certificate": true, "unhealthy": { "http_statuses": [429, 404, 500, 501, 502, 503, 504, 505], "tcp_failures": 0, "timeouts": 0, "http_failures": 0, "interval": 0 }, "http_path": "/", "timeout": 1, "healthy": { "http_statuses": [200, 302], "interval": 0, "successes": 0 }, "https_sni": "example.com", "concurrency": 10, "type": "http" }, "passive": { "unhealthy": { "http_failures": 0, "http_statuses": [429, 500, 503], "tcp_failures": 0, "timeouts": 0 }, "type": "http", "healthy": { "successes": 0, "http_statuses": [200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 306, 307, 308] } }, "threshold": 0 }, "tags": ["user-level", "low-priority"], "host_header": "example.com", "client_certificate": {"id":"ea29aaa3-3b2d-488c-b90c-56df8e0dd8c6"} }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

Target(目标)

Target(目标)是一台 Backend Real Server(后端真实服务器)的抽象,本质是 IP/Hostname:Port 字符串,Target 和 Upstream 是 1:N 关系,用于实现负载均衡。

Admin API URL:

# Create Target /upstreams/{upstream host:port or id}/targets

1

2

Request Body:

target:指定 Target 的 IP/Hostname:Port。

weight(可选):指定 Target 的负载均衡权重(0-65535),默认为 10。

Request Body EXAMPLE:

{ "id": "173a6cee-90d1-40a7-89cf-0329eca780a6", "created_at": 1422386534, "upstream": {"id":"bdab0e47-4e37-4f0b-8fd0-87d95cc4addc"}, "target": "example.com:8000", "weight": 100, "tags": ["user-level", "low-priority"] }

1

2

3

4

5

6

7

8

Consumer(消费者)

Consumer 作为一个客户端或用户的抽象,作为一个 Service 的消费者。其核心原则是通过为 Consumer 添加 Plugins,从而自定义客户端的请求行为,例如:用于实现客户端的认证鉴权。

Admin API URL:

# Create Consumer /consumers

1

2

Request Body:

username:指定 Consumer 的全局唯一名称。

custom_id:指定 Consumer 的全局唯一 ID。

Request Body EXAMPLE:

{ "id": "ec1a1f6f-2aa4-4e58-93ff-b56368f19b27", "created_at": 1422386534, "username": "my-username", "custom_id": "my-custom-id", "tags": ["user-level", "low-priority"] }

1

2

3

4

云计算与云原生 — 微服务架构 Kong APIGW 完全解析

5

6

7

Plugins(插件)

当客户端调用 Kong Proxy API 时,每个前端 API(虚)请求被反向代理到后端 API(实)。在 Requests 和 Responses 之间,Kong Server 会依次执行已经事先安装和配置好的任何 Plugins。

Kong Hub:https://docs.konghq.com/hub/

Plugins(插件)表示将在 HTTP 请求/响应的生命周期中执行的插件逻辑,例如:身份验证、速率限制。当我们将 Plugin 添加到 Service 时,客户端对该 Service 发出的每个请求都执行这个插件。通过 Service 和 Consumer 字段来指定服务者和使用者。

在 Kong 配置文件中可以配置要安装的 Plugins,但实际上只有在通过 Admin API 启用之后才会真正生效。可以通过以下几种不同的方式启用一个插件:

适用于所有 Service、Route、Consumer。不设置 service_id、route_id、consumer_id。

适用于特定 Service/Route、Consumer。仅设置 service_id/ route_id 和 consumer_id。(注:并非所有插件都允许指定 consumer_id)

适用于每个 Service/Route 和特定 Consumer。仅设置 consumer_id。(注:并非所有插件都允许指定 consumer_id)

适用于特定 Service 和每个 Consumer。仅设置 service_id。(注:某些插件只允许设置 route_id)。

适用于特定 Route 和每个 Consumer。仅设置 route_id。(注:某些插件只允许设置 service_id)。

需要注意的是,因为同一个插件在底层始终只会运行一次,所以如果对不同的 Object 配置相同插件时就会有优先级的概念。优先级从高到低顺序如下:

在 Route、Service 和 Consumer 组合上配置的插件。

在 Route 和 Consumer 组合上配置的插件。

在 Service 和 Consumer 组合上配置的插件。

在 Route 和 Service 组合上配置的插件。

在 Consumer 上配置的插件。

在 Route 上配置的插件。

在 Service 上配置的插件。

配置为全局运行的插件。

可见,无论是 “3 者组合”、“两者组合” 或 “单独” 配置的情况下,Consumer 都拥有较高的优先级。例如:无论在什么情况下为 Consumer 配置了 Authentication Plugin,都意味着必须对 Consumer 的请求进行身份验证。

Admin API URL:

# Create Plugin /plugins # Create Plugin Associated to a Specific Route /routes/{route name or id}/plugins # Create Plugin Associated to a Specific Service /services/{service name or id}/plugins # Create Plugin Associated to a Specific Consumer /consumers/{consumer name or id}/plugins

1

2

3

4

5

6

7

8

9

10

11

Request Body:

Request Body EXAMPLE:

{ "id": "ce44eef5-41ed-47f6-baab-f725cecf98c7", "name": "rate-limiting", "created_at": 1422386534, "route": null, "service": null, "consumer": null, "config": {"hour":500, "minute":20}, "protocols": ["http", "https"], "enabled": true, "tags": ["user-level", "low-priority"] }

1

2

3

4

5

6

7

8

9

10

11

12

CA Certificate(CA 证书)

CA Certificate 是一个受信任的 CA 证书逻辑对象,用于与 Backend Real Server 建立 TLS 连接。

Admin API URL:

# Create CA Certificate /ca_certificates

1

2

Request Body EXAMPLE:

{ "id": "04fbeacf-a9f1-4a5d-ae4a-b0407445db3f", "created_at": 1422386534, "cert": "-----BEGIN CERTIFICATE-----...", # PEM-encoded public certificate of the CA. "cert_digest": "c641e28d77e93544f2fa87b2cf3f3d51...", # SHA256 hex digest of the public certificate. "tags": ["user-level", "low-priority"] }

1

2

3

4

5

6

7

Certificate 与 SNI

Certificate 是一个 Real Backend Server 的 TLS 证书公/私钥对(Public Certificate / Private Key)。Kong 使用 Certificate 对象来处理 Client 发起的 TLS 请求,即:将 Real Backend Server 的 TLS 握手提前到了 Kong Proxy API Front-End 进行。

因此就出现了在一个 HTTPS Server(Kong Proxy API)上管理多个 Certificate 的情况,这就需要结合 TLS 的 SNI 扩展特性来说明每个 Client TLS 请求所面向的 Certificate 证书,以此来告知 HTTPS Server 这次 TLS 请求所针对哪一个 Certificate。同时,Certificate 还可以选择与 SNI 进行关联,以此将 Certificate 对与多个 Hostname 进行绑定,即:多个 Hostname 公用一个 Certificate。

例如:curl 7.18.1+ & openssl 0.9.8j+ 的组合就可以支持 SNI 了。

curl \ --cacert /root/CA/nginx1.com/cacert.pem \ -X GET "https://webserver.com:8443/" \ -H 'Content-type: application/json' \ -H 'Accept: application/json' \ -H 'host: nginx1.com'

1

2

3

4

5

6

Certificate(证书)

Admin API URL:

# Create Certificate /certificates

1

2

Request Body EXAMPLE:

{ "id": "7fca84d6-7d37-4a74-a7b0-93e576089a41", "created_at": 1422386534, "cert": "-----BEGIN CERTIFICATE-----...", # PEM-encoded public certificate chain of the SSL key pair. "key": "-----BEGIN RSA PRIVATE KEY-----...", # PEM-encoded private key of the SSL key pair. "snis": ["www.nginx1.com", "www.nginx2.com"], "tags": ["user-level", "low-priority"] }

1

2

3

4

5

6

7

8

SNI(Server Name Indication,服务器名称指示)

在 Kong 中,SNI 表示表示 Hostname 到 Certificate 的 N:1 映射,一个 Certificate 可以有许多与之关联的 Hostname。当 Kong 收到 TLS 请求时,它使用 Client Hello 中的 SNI 字段查找到关联的 Certificate 对象(即:TLS 本地设备证书,也称作 Server 证书)。

snis 支持通配符的形式,可以在最左边(前缀)或最右边(后缀)包含一个通配符,这在维护多个子域名时非常有用。例如:mydomain.*、 *.mydomain.com 等。

snis 的匹配遵循以下优先级:

确切的 SNI 匹配证书。

根据前缀通配符搜索证书。

根据后缀通配符搜索证书。

搜索与 SNI 关联的证书。

文件系统上的默认证书。

在建立连接和协商 TLS 握手时,如果客户端将 prefix.tls-example.com 作为 SNI 扩展的一部分发送,Kong 将提供之前配置与该 SNI 关联的 Certificate 证书。

Admin API URL:

# Create SNI /snis # Create SNI Associated to a Specific Certificate /certificates/{certificate name or id}/snis

1

2

3

4

5

Request Body EXAMPLE:

{ "id": "91020192-062d-416f-a275-9addeeaffaf2", "name": "my-sni", "created_at": 1422386534, "tags": ["user-level", "low-priority"], "certificate": {"id":"a2e013e8-7623-4494-a347-6d29108ff68b"} }

1

2

3

4

5

6

7

Kong 的基本使用

非安全访问

创建 Service

指定 Upstream API Service 的 URL,e.g. http://web.apigw.com:8080/infos。

POST http://172.20.148.34:1337/kong/services/ { "host": "web.apigw.com", # Upstream API Service 的 Host "created_at": 1609753805, "connect_timeout": 60000, "id": "0f48d716-a95d-46b1-877d-51669c8b9b2f", "protocol": "http", # Upstream API Service 的 Protocol "name": "web-service", "read_timeout": 60000, "port": 8080, # Upstream API Service 的 Port "path": "/infos", # Upstream API Service 的 Path "updated_at": 1609753805, "retries": 5, "write_timeout": 60000, "tags": [], "client_certificate": null, "extras": { "id": 4, "service_id": "0f48d716-a95d-46b1-877d-51669c8b9b2f", "kong_node_id": "3", "description": null, "tags": null, "createdAt": "2021-01-04T09:50:05.000Z", "updatedAt": "2021-01-04T09:50:05.000Z", "createdUser": null, "updatedUser": null } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

创建 Route

指定代理给特定 Service 的 Client Request,e.g. 将 Host 为 web.apigw.com、HTTP Method 为 GET、URL Path 为 /infos 的客户端请求转发给上述 Service。

注意:在实际使用中 Route 和 Service 的 host 应该始终保持一致,以此来保证在前端匹配到的客户端请求与后端进行服务的 API 始终属于一个 “虚拟主机” 内的。

POST http://172.20.148.34:1337/kong/routes/ { "id": "ee0fc3ba-5c42-4610-b944-2ce3cb1d3abb", "path_handling": "v1", "paths": null, "destinations": null, "headers": null, "protocols": [ "http" ], "methods": [ "GET" ], "snis": null, "service": { "id": "0f48d716-a95d-46b1-877d-51669c8b9b2f" }, "name": "http-get-route", "strip_path": true, "preserve_host": false, "regex_priority": 0, "updated_at": 1609754211, "sources": null, "hosts": ["web.apigw.com"], "https_redirect_status_code": 426, "tags": null, "created_at": 1609754211 }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

创建 Upstream

最主要是指定 Upstream Name 和 Service Host 一致,以此将 Service 和 Upstream 关联起来。

创建 Targets

指定若干个 Targets(IP/Hostname:Port)作为上述 Upstream 的 Backend Real Server。

调用测试

# 没有 DNS 的情况 curl -X GET "http://localhost:8000/infos" \ -H 'host: web.apigw.com' \ -H 'Content-type: application/json' \ -H 'Accept: application/json' # 有 DNS 的情况 curl -X GET "http://web.apigw.com:8000/infos" \ -H 'Content-type: application/json' \ -H 'Accept: application/json'

1

2

3

4

5

6

7

8

9

10

注意:实际上,web.apigw.com 和 localhost 解析的 IP 都是 Kong Proxy API 的 IP 地址。

Front-End 安全访问,Backend 非安全访问

使用默认 Kong Proxy API Domain Name 的 TLS 证书

使用默认 Kong Proxy API Domain Name 的 TLS 证书,需要我们为 Kong Proxy API Domain Name 自签发本地设备证书:

自签发 CA 根证书、Kong Proxy API 本地设备证书、Kong Proxy API 本地设备私钥。

Kong Server 加载 Kong Proxy API 本地设备证书、Kong Proxy API 本地设备私钥启动。

客户端获得 CA 证书与 Kong Proxy API 建立 TLS 连接。

Kong Server 的证书配置项位于:

$ vi /usr/local/kong/nginx-kong.conf ... # Kong Proxy API ssl_certificate /usr/local/kong/ssl/kong-default.crt; ssl_certificate_key /usr/local/kong/ssl/kong-default.key; ... # Kong Admin API ssl_certificate /usr/local/kong/ssl/admin-kong-default.crt; ssl_certificate_key /usr/local/kong/ssl/admin-kong-default.key; ...

1

2

3

4

5

6

7

8

9

10

11

指定 Upstream Server(Backend Real Server)的 Protocol 为 http(根据实际情况而定)。

指定 Upstream Server(Backend Real Server)的 Host 为 Server 的 Domain Name(根据实际情况而定)。

指定 Upstream Server(Backend Real Server)的 Port 为 80(根据实际情况而定)。

指定 Upstream Server(Backend Real Server)的 Path 为 / (根据实际情况而定)。

Front-End 安全访问与非安全访问主要的区别在 Route Object:

指定 Front-End 的 Protocol 为 https(安全连接)。

指定 Front-End 的 Hosts 为 Kong Proxy API Domain Name(视实际情况而定)。

指定 Front-End 的 Methods 为 GET(视实际情况而定)。

指定 Front-End 的 Paths 为 /(视实际情况而定)。

指定 Upstream Name 为 Backend Server 的 Domain Name。

$ curl --cacert /root/CA/apigw.com/cacert.pem -X GET "https://apigw.com:8443/" -H 'Content-type: application/json' -H 'Accept: application/json' -H "host: nginx1.com" nginx1.com

1

2

3

使用用户自定义的 Domain Name 的 TLS 证书

使用用户自定义的 Domain Name 的 TLS 证书,则由用户自己提供 Real Backend Server 的本地设备证书和私钥,然后 Kong 将 TLS 认证流程从 Backend 移到了 Frontend。用户在客户端使用 CA 证书结合 TLS SNI 扩展与 Kong Proxy API 建立 TLS 连接。

上传 Backend Real Server 的 Server 证书。

上传 Backend Real Server 的 Server 密钥。

指定 Upstream Server(Backend Real Server)的 Protocol 为 http(根据实际情况而定)。

指定 Upstream Server(Backend Real Server)的 Host 为 Server 的 Domain Name(根据实际情况而定)。

指定 Upstream Server(Backend Real Server)的 Port 为 80(根据实际情况而定)。

指定 Upstream Server(Backend Real Server)的 Path 为 / (根据实际情况而定)。

指定 Upstream Server(Backend Real Server)的 Certificate ID 为上述创建的 Certificate。

指定 Front-End 的 Protocol 为 https(安全连接)。

指定 Front-End 的 Hosts 为 Certificate 签发的 Domain Name,通常与 Real Server 的 Domain Name 一致(视实际情况而定)。

指定 Front-End 的 Methods 为 GET(视实际情况而定)。

指定 Front-End 的 Paths 为 /(视实际情况而定)。

指定 Upstream Name 为 Backend Server 的 Domain Name。

curl \ --cacert /root/CA/nginx1.com/cacert.pem \ --resolve nginx1.com:8443:127.0.0.1 \ -X GET "https://nginx1.com:8443/" \ -H 'Content-type: application/json' \ -H 'Accept: application/json' \ -H 'host: nginx1.com' # URL 中的 Domain Name: nginx1.com 会作为 Host 信息,被插入到 TLS 握手的 Client Hello 阶段中的 SNI 扩展字段中。

1

2

3

4

5

6

7

8

9

Front-End 安全访问,Backend 安全访问

Front-End 安全访问,Backend 安全访问。除了需要在 Front-End 使用默认的 TLS 证书或用户自定义的 Certificate 证书之外,还要求 Backend Server 自身也加载 HTTPS 证书,然后通过在 Service 中的 ca_certificate 字段来指定 CA Certificate(CA 证书)来完成对 Backend Server 的 TLS 认证。

云原生 云计算 微服务

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:【奖励公示】【内容共创】第11期 携手2021,共创2022,华为云邀您参与签约作者征集令,赢高达500元礼包!
下一篇:[Python从零到壹] 十一.Numpy、Pandas和Matplotlib入门知识万字详解 | 【生长吧!Python】
相关文章