之前简单介绍安装了 Kong,这篇就是深入 Kong 详细讲述下它的一些工作原理、核心概念。

附上:
Kong 官网:https://konghq.com/
Kong GitHub地址:https://github.com/kong/kong

Kong的工作原理

architecture
architecture

Kong默认开放的端口

接收客户端流量的端口,proxy 部分

  • :8000 —— http 端口
  • :8443 —— https 端口

admin API 端口,admin 部分

  • :8001 —— http 端口
  • :8444 —— https 端口

Nginx配置 VS Kong配置

我们来看一个典型 Nginx 的配置对应在 Kong 上是怎么样的,下面是一个典型的 Nginx 配置

upstream passportUpstream {
    server localhost:8080 weight=100;
}
server {
    listen 80;
    location /hello {
        proxy_pass http://passportUpstream;
    }
}

下面我们开看看其对应 Kong 中的配置

# 配置 upstream 
curl -X POST http://localhost:8001/upstreams 
    --data "name=passportUpstream" 

# 配置 target 
curl -X POST http://localhost:8001/upstreams/passport/targets 
    --data "target=localhost:8080" --data "weight=100" 

# 配置 service 
curl -X POST http://localhost:8001/services 
    --data "name=getUserInfo" --data "host=passportUpstream" 

# 配置 route 
curl -X POST http://localhost:8001/routes 
    --data "paths[]=/user"
    --data "service.id=8695cc65-16c1-43b1-95a1-5d30d0a50409" 

curl -X POST http://localhost:8001/routes 
    --data "hosts[]=*.example.com,test.com,*.abc.com" 
    --data "service.id=8695cc65-16c1-43b1-95a1-5d30d0a50409" 

这一切配置都是通过其 Http Restful API 来动态实现的,无需我们再手动的 reload Nginx.conf

在上述的配置中涉及到了几个概念: UpstreamTargetServiceRoute 等概念,它们是 Kong 的几个核心概念,也是我们在使用 Kong API 时经常打交道的,下面我们就其几个核心概念做一下简单的说明。

Kong关键术语/名词解析

Upstream

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

Target

目标 IP地址/主机名,其端口表示后端服务的实例。每个上游都可以有多个 Target,并且可以动态添加 Target。

由于上游维护 Target 的更改历史记录,因此无法删除或者修改 Target。要禁用目标,请发布一个新的 Targer weight=0,或者使用 DELETE 来完成相同的操作。

Service

顾名思义,服务实体是每个上游服务的抽象。服务的示例是数据转换微服务,计费API等。

服务的主要属性是它的 URL(其中,Kong 应该代理流量),其可以被设置为单个串或通过指定其 protocol, host,port 和path。

服务与路由相关联(服务可以有许多与之关联的路由)。路由是 Kong 的入口点,并定义匹配客户端请求的规则。一旦匹配路由,Kong 就会将请求代理到其关联的服务。

Route

路由实体定义规则以匹配客户端的请求。每个 Route 与一个 Service 相关联,一个服务可能有多个与之关联的路由。与给定路由匹配的每个请求都将代理到其关联的 Service 上。可以配置的字段有:

  • hosts
  • paths
  • methods

Service 和 Route 的组合(以及它们之间的关注点分离)提供了一种强大的路由机制,通过它可以在 Kong 中定义细粒度的入口点,从而使基础架构路由到不同上游服务。

Consumer

Consumer 对象表示服务的使用者或者用户。你可以依靠 Kong 作为主数据库存储,也可以将使用者列表与数据库映射,以保持Kong 与现有的主数据存储之间的一致性。

Plugin

插件实体表示将在 HTTP请求/响应生命周期 期间执行的插件配置。它是为在 Kong 后面运行的服务添加功能的,例如身份验证或速率限制。

将插件配置添加到服务时,客户端向该服务发出的每个请求都将运行所述插件。如果某个特定消费者需要将插件调整为不同的值,你可以通过创建一个单独的插件实例,通过 service 和 consumer 字段指定服务和消费者。

对应关系

Upstream : target -> 1:n
Service : Upstream -> 1:1 or 1:0 (Service 可以直接指向具体的 Target,相当于不做负载均衡)
Service : Route -> 1:n

Client 请求的流量通过 Route 指向与之相关的 Service,如果配置插件的话就会作用插件,Service 接到流量后给到相应的 Upstream 的服务上面。

Kong API操作

配置服务

通过向 Admin API 发送 HTTP 请求来向 Kong 添加服务:

curl -i -X POST http://localhost:8001/services/ \
      -d 'name=test-service' \
      -d 'url=http://test-service.com'
  HTTP/1.1 201 Created
  ...

  {
      "connect_timeout": 60000,
      "created_at": 1587869247,
      "host": "test-service.com",
      "id": "d54da06c-d69f-4910-8896-915c63c270cd",
      "name": "test-service",
      "path": "/",
      "port": 80,
      "protocol": "http",
      "read_timeout": 60000,
      "retries": 5,
      "updated_at": 1587869247,
      "write_timeout": 60000
  }

这里注册一个名为 test-service 的服务,该服务指向 http://test-service.com(上游)。

url 参数是一个简化参数,用于一次性添加 protocol,host,port 和 path。

路由匹配规则

现在让我们讨论 Kong 如何匹配针对路由的已配置 host,path 和 methods 属性(或字段)的请求。请注意,所有这三个字段都是可选的,但必须至少指定其中一个。

对于匹配路线的请求:

  • 请求必须包含所有已配置的字段
  • 请求中的字段值必须至少与其中一个配置值匹配(当字段配置接收一个或多个值时,请求只需要其中一个值被视为匹配)

这里思考一个问题,Kong route 中的 host 的作用是什么?有什么意义?哪些场景会用到设置多个 host 呢?

这是官方的解释:
Routing a request based on its Host header is the most straightforward way to proxy traffic through Kong, as this is the intended usage of the HTTP Host header. Kong makes it easy to do so via the hosts field of the API entity.

显然官方对 host 的说明,没有回答上面的问题,下面看下网络上对 host 的解释:
我们知道 HTTP 请求头信息里面会带有一个 Host 字段,很多人不是很清楚这个字段具体的作用或者用法,包括我被很多人问过也曾经有些迷茫,这里具体扫盲下。

Host 是 HTTP 1.1 协议中新增的一个请求头,主要用来实现虚拟主机技术。我们知道一个 IP 地址可以对应多个域名,比如假设我有这么几个域名 www.baidu.com,www.taobao.com 和 www.jd.com 然后在域名提供商那通过 A 记录或者 CNAME 记录的方式最终都和我的虚拟机服务器 IP:111.111.111.111 关联起来,那么我通过任何一个域名去访问最终解析到的都是 IP:111.111.111.111。

但是还是没有提到 Host 的概念,其实可以这样看,我们的那台虚拟机 111.111.111.111 上面其实是可以放很多很多网站的(不然如果只能放一个网站的话就太不合理了,虚拟机那么多资源都浪费了),我们可以把 www.baidu.com,www.taobao.com 和 www.jd.com 这些网站假设都部署在那台虚拟机上面,但是这样会有一个问题,我们每次访问这些域名其实都是解析到服务器 IP:111.111.111.111,我怎么来区分每次根据域名显示出不同的网站的内容呢,其实这就要用到请求头中 Host 的概念了,每个 Host 可以看做是我在服务器 111.111.111.111 上面的一个站点,每次我用那些域名访问的时候都是会解析同一个虚拟机没错,但是我通过不同的 Host 可以区分出我是访问这个虚拟机上的哪个站点。

我们再来看几个例子就彻底明白了。考虑如下配置的路由:

{
      "hosts": ["example.com", "test-service.com"],
      "paths": ["/header", "/test"],
      "methods": ["GET"]
}

下面我们假设请求时不带 Host:

curl -v -H "Host: ''" -i http://localhost:8000/users/1

注意观察请求头,* Connected to localhost (127.0.0.1) port 8000 (#0);客户端和 Kong 建立了 tcp 连接,但是 host 是空的,所以 Kong 匹配不到上面的 route。

让我们看下设置了正确 Host 的请求:

curl -v -H "Host: example.com" -i http://localhost:8000/users/1

这次 Kong 匹配到了 route,所以拿到了数据。所以 Host 作用明白了吧。

最后修改:2020 年 06 月 09 日 12 : 45 PM
如果觉得我的文章对你有用,请随意赞赏