Kubernetes-部署API网关Kong

1、Kong的概述

Kong是一个clould-native、快速的、可扩展的、分布式的微服务抽象层(也称为API网关、API中间件或在某些情况下称为服务网格)框架。Kong作为开源项目在2015年推出,它的核心价值是高性能和可扩展性。Kong被广泛用于从初创企业到全球5000家公司以及政府组织的生产环境中。

如果构建Web、移动或IoT(物联网)应用,可能最终需要使用通用的功能来实现这些应用。Kong充当微服务请求的网关(或侧车),通过插件能够提供负载平衡日志记录、身份验证、速率限制、转换等能力。

2、功能特性

  • 云本土化(Cloud-Native):Kong可以在Kubernetes或物理环境上运行;
  • 动态负载平衡(Dynamic Load Balancing):跨多个上游服务的负载平衡业务。
  • 基于哈希的负载平衡(Hash-based Load Balancing):一致的散列/粘性会话的负载平衡。
  • 断路器(Circuit-Breaker):智能跟踪不健康的上游服务。
  • 健康检查(Health Checks):主动和被动监控您的上游服务。
  • 服务发现(Service Discovery):解决如Consul等第三方DNS解析器的SRV记录。
  • 无服务器(Serverless):从Kong中直接调用和保证AWS或OpenWhisk函数安全。
  • WebSockets:通过WebSockets与上游服务进行通信。
  • OAuth2.0:轻松的向API中添加OAuth2.0认证。
  • 日志记录(Logging):通过HTTP、TCP、UDP记录请求或者相应的日志,存储在磁盘中。
  • 安全(Security):ACL,Bot检测,IPs白名单/黑名单等。
  • 系统日志(Syslog):记录信息到系统日志。
  • SSL:为基础服务或API设置特定的SSL证书。
  • 监视(Monitoring):能够实时对关键负载和性能指标进行监控。
  • 转发代理(Forward Proxy):使端口连接到中间透明的HTTP代理。
  • 认证(Authentications):支持HMAC,JWT和BASIC方式进行认证等等。
  • 速率限制(Rate-limiting):基于多个变量的阻塞和节流请求。
  • 转换(Transformations):添加、删除或操作HTTP请求和响应。
  • 缓存(Caching):在代理层进行缓存和服务响应。
  • 命令行工具(CLI):能够通过命令行控制Kong的集群。
  • REST API:可以通过REST API灵活的操作Kong。
  • GEO复制:在不同的区域,配置总是最新的。
  • 故障检测与恢复(Failure Detection & Recovery):如果Cassandra节点失效,Kong并不会受影响。
  • 群集(Clustering):所有的Kong节点会自动加入群集,并更新各个节点上的配置。
  • 可扩展性(Scalability):通过添加节点,实现水平缩放。
  • 性能(Performance):通过缩放和使用Nigix,Kong能够轻松处理负载。
  • 插件(Plugins):基于插件的可扩展体系结构,能够方便的向Kong和API添加功能。

3、Kong依赖的技术

Kong部署在Nginx和Apache Cassandra或PostgreSQL等可靠技术之上,并提供了易于使用的RESTful API来操作和配置系统。下面是Kong的技术逻辑图。基于这些技术,Kong提供相关的特性支持:

  • Nginx
    • 经过验证的高性能基础;
    • HTTP和反向代理服务器;
    • 处理低层级的操作。
  • OpenRestry
    • 支持Lua脚本;
    • 拦截请求/响应生命周期;
    • 基于Nginx进行扩展。
  • Clustering&Datastore
    • 支持Cassandra或PostgreSQL数据库;
    • 内存级的缓存;
    • 支持水平扩展。
  • Plugins
    • 使用Lua创建插件;
    • 功能强大的定制能力;
    • 与第三方服务实现集成。
  • Restful Administration API
    • 通过Restful API管理Kong;
    • 支持CI/CD&DevOps;
    • 基于插件的可扩展。

 

4、使用Helm在Kubernetes上部署Kong

4.1 前置条件

4.2 Helm char配置

下表列示了Kong chart的配置参数和默认值:
参数 说明 默认值
image.repository Kong image kong
image.tag Kong image version 0.14.1
image.pullPolicy Image pull policy IfNotPresent
image.pullSecrets Image pull secrets null
replicaCount Kong instance count 1
admin.useTLS Secure Admin traffic true
admin.servicePort TCP port on which the Kong admin service is exposed 8444
admin.containerPort TCP port on which Kong app listens for admin traffic 8444
admin.nodePort Node port when service type is NodePort
admin.type k8s service type, Options: NodePort, ClusterIP, LoadBalancer NodePort
admin.loadBalancerIP Will reuse an existing ingress static IP for the admin service null
admin.loadBalancerSourceRanges Limit admin access to CIDRs if set and service type is LoadBalancer []
admin.ingress.enabled Enable ingress resource creation (works with proxy.type=ClusterIP) false
admin.ingress.tls Name of secret resource, containing TLS secret
admin.ingress.hosts List of ingress hosts. []
admin.ingress.path Ingress path. /
admin.ingress.annotations Ingress annotations. See documentation for your ingress controller for details {}
proxy.useTLS Secure Proxy traffic true
proxy.servicePort TCP port on which the Kong Proxy Service is exposed 8443
proxy.containerPort TCP port on which the Kong app listens for Proxy traffic 8443
proxy.nodePort Node port when service type is NodePort
proxy.type k8s service type. Options: NodePort, ClusterIP, LoadBalancer NodePort
proxy.loadBalancerSourceRanges Limit proxy access to CIDRs if set and service type is LoadBalancer []
proxy.loadBalancerIP To reuse an existing ingress static IP for the admin service
proxy.ingress.enabled Enable ingress resource creation (works with proxy.type=ClusterIP) false
proxy.ingress.tls Name of secret resource, containing TLS secret
proxy.ingress.hosts List of ingress hosts. []
proxy.ingress.path Ingress path. /
proxy.ingress.annotations Ingress annotations. See documentation for your ingress controller for details {}
env Additional Kong configurations
runMigrations Run Kong migrations job true
readinessProbe Kong readiness probe
livenessProbe Kong liveness probe
affinity Node/pod affinities
nodeSelector Node labels for pod assignment {}
podAnnotations Annotations to add to each pod {}
resources Pod resource requests & limits {}
tolerations List of node taints to tolerate []

4.3 安装Chart

通过执行如下的命令,在Kubernetes中部署Kong:

$ helm install --name my-release stable/kong

4.4 验证Kong(命令行)

通过执行下面的命令,进入Kong的容器:

kubectl exec -it my-release-kong-d448dc869-fblbk sh

并在kong中执行如下的命令:

curl http://localhost:8001

如果kong正常运行的话,应该会返回一些内容。

4.5 验证Kong(客户端)

另外,也可以安装一个Kong的客户端来验证。在安装有Docker引擎的操作系统上执行如下的命令:

docker run -d -p 8080:8080 pgbi/kong-dashboard start --kong-url http://10.0.32.172:31177

通过docker安装一个Kong-Dashboard,安装完成后,通过浏览器访问:

5、使用

5.1 注册服务

在此部分将会向kong添加一个API,为了做到这一点,首先需要往Kong中添加一个服务。我们将创建一个指向Mockbin API的服务,Mockbin是一个“echo”类型的公共网站,它将返回的请求作为响应返回给请求者。通过此示例有助于了解Kong是如何代理API请求。在开始对服务进行请求之前,需要为服务添加一个路由。路由指定在到达Kong之后如何向服务发送请求,单个服务可以有多个路由。在配置了服务和路由之后,就能够通过Kong对服务进行请求。Kong公开了RESTful Admin API:8001,Kong的配置(包括添加服务和路由)是通过对该API的请求进行的。

5.1.1 注册服务

服务实体是上游服务中的每一个抽象。服务的示例将是数据转换微服务、计费API等。服务的主要属性是它的URL(其中Kong应该代理流量),它可以被设置为单个字符串或单独指定它的协议、主机、端口和路径。

通过执行下面的命令,将名称为example-servic,地址为url=http://mockbin.org的服务注册到Kong上。

$ curl -i -X POST \
  --url http://localhost:8001/services/ \
  --data 'name=example-service' \
  --data 'url=http://mockbin.org'

执行命令后,返回的结果类似下面的内容:

HTTP/1.1 201 Created
Content-Type: application/json
Connection: keep-alive

{
   "host":"mockbin.org",
   "created_at":1519130509,
   "connect_timeout":60000,
   "id":"92956672-f5ea-4e9a-b096-667bf55bc40c",
   "protocol":"http",
   "name":"example-service",
   "read_timeout":60000,
   "port":80,
   "path":null,
   "updated_at":1519130509,
   "retries":5,
   "write_timeout":60000
}

 5.1.2 创建路由

路由实体定义用来匹配客户端请求的规则。每个路由都与一个服务相关联,并且一个服务可能具有与其相关的多个路由。匹配给定路由的每个请求都将被代理到其关联的服务。通过路由和服务的组合(以及它们之间的关注点分离)提供了强大的路由机制,通过这种机制,可以在Kong中定义细粒度入口点,从而实现基础设施的不同上游服务。

$ curl -i -X POST \
  --url http://localhost:8001/services/example-service/routes \
  --data 'hosts[]=example.com'

返回结果如下所示:

HTTP/1.1 201 Created
Content-Type: application/json
Connection: keep-alive

{
   "created_at":1519131139,
   "strip_path":true,
   "hosts":[
      "example.com"
   ],
   "preserve_host":false,
   "regex_priority":0,
   "updated_at":1519131139,
   "paths":null,
   "service":{
      "id":"79d7ee6e-9fc7-4b95-aa3b-61d2e17e7516"
   },
   "methods":null,
   "protocols":[
      "http",
      "https"
   ],
   "id":"f9ce2ed7-c06e-4e16-bd5d-3a82daef3f9d"
}

在为服务创建好路由后,Kong就做好对外提供了此服务的准备。

5.1.3 通过Kong转达对于服务的请求

发出以下curl请求,以验证Kong是否正确地将请求转发给服务。注意,缺省情况下,Kong处理端口上的代理请求:8000:

$ curl -i -X GET \
  --url http://localhost:8000/ \
  --header 'Host: example.com'

成功的响应意味着Kong将http://localhost:8000发出的请求转发到在步骤#1中配置的url(https://mockbin.org),并将返回响应结果。通过在curl请求中定义的头,Kong知道如何做的这一点:

  • Host: <given host>

5.2 注册API

在此部分将把API添加到Kong层,以让Kong管理API。

5.2.1 使用Admin API注册

通过下面的命令将API (Mockbin) 注册到Kong中:

$ curl -i -X POST \
  --url http://localhost:8001/apis/ \
  --data 'name=example-api' \
  --data 'hosts=example.com' \
  --data 'upstream_url=http://mockbin.org'

5.2.2 验证API

注册后返回的信息应该如下所示:

HTTP/1.1 201 Created
Content-Type: application/json
Connection: keep-alive

{
  "created_at": 1488830759000,
  "hosts": [
      "example.com"
  ],
  "http_if_terminated": false,
  "https_only": false,
  "id": "6378122c-a0a1-438d-a5c6-efabae9fb969",
  "name": "example-api",
  "preserve_host": false,
  "retries": 5,
  "strip_uri": true,
  "upstream_connect_timeout": 60000,
  "upstream_read_timeout": 60000,
  "upstream_send_timeout": 60000,
  "upstream_url": "http://mockbin.org"
}

5.1.3 通过Kong转发请求

发出以下curl请求,以验证Kong是否正确地将请求转发给服务。注意,缺省情况下,Kong处理端口上的代理请求:8000:

$ curl -i -X GET \
  --url http://localhost:8000/ \
  --header 'Host: example.com'

成功的响应意味着Kong将http://localhost:8000发出的请求转发到在步骤#1中配置的url(https://mockbin.org),并将返回响应结果。通过在curl请求中定义的头,Kong知道如何做的这一点:

  • Host: <given host>

6、Admin API

6.1 API Object

API对象描述了一个由Kong公开的API。当使用者从代理端口(Proxy port)调用它时,Kong需要知道如何获取此API。每个API对象必须指定主机(hosts)、uris和方法(method)的一些组合。Kong将把所有对API的请求委托给指定的upstream URL。

{
    "created_at": 1488830759000,
    "hosts": [
        "example.org"
    ],
    "http_if_terminated": false,
    "https_only": false,
    "id": "6378122c-a0a1-438d-a5c6-efabae9fb969",
    "name": "example-api",
    "preserve_host": false,
    "retries": 5,
    "strip_uri": true,
    "upstream_connect_timeout": 60000,
    "upstream_read_timeout": 60000,
    "upstream_send_timeout": 60000,
    "upstream_url": "http://httpbin.org"
}

6.1.1 注册API

请求地址:/apis/
请求方法:POST

属性 描述
name API的名称
hosts
semi-optional
以逗号分隔,指向API的域名列表。例如:example.com。至少应该指定主机、uri或方法中的一个。
uris
semi-optional
以逗号分隔,指向API的uri前缀列表。例如: /my-path。至少应该指定主机、uri或方法中的一个。
methods
semi-optional
以逗号分隔,指向API的HTTP方法列表。例如: GET,POST。至少应该指定主机、uri或方法中的一个。
upstream_url 指向API服务器的基本目标URL,这个URL将被用于代理请求。例如: https://example.com.
strip_uri
optional
当通过一个uris前缀匹配一个API时,要从upstream URI中去掉匹配的前缀。默认值:true。
preserve_host
optional
当通过一个主机域名匹配一个API时,请确保请求主机头被转发到upstream服务。默认值:false,upstream主机头将从配置的upstream_url中提取出来。
retries
optional
在代理失败的情况下执行的重试次数。默认值是5。
upstream_connect_timeout
optional
建立连接到upstream服务的连接超时时间。默认为60000。
upstream_send_timeout
optional
The timeout in milliseconds between two successive write operations for transmitting a request to your upstream service Defaults to 60000.
upstream_read_timeout
optional
The timeout in milliseconds between two successive read operations for transmitting a request to your upstream service Defaults to 60000.
https_only
optional
如果希望仅使用HTTPS提供API(默认情况下是8443),那么就可以启用该参数。默认值:false。
http_if_terminated
optional
在执行HTTPS通信时,考虑一下X-Forwarded-Proto header。默认值: false

6.1.2 检索API

请求地址:/apis/{name or id}
请求方法:GET

属性 描述
name or id(必填) 要检索的API的唯一标识符或名称。

6.1.3 API列表

请求地址:/apis/
请求方法:GET

属性 描述
id(可选) 基于api id字段的过滤器。
name(可选) 基于api name字段的过滤器。
upstream_url(可选) 基于api upstream_url字段的过滤器。
retries(可选) 基于api retries字段的过滤器。
offset(可选) 用于分页的游标。偏移量是定义列表中的位置的对象标识符。
size(可选,默认是100) 每个页面返回的对象数量的限制。

6.1.4 更新API

请求地址:/apis/{name or id}
请求方法:GET

属性 描述
name or id
required
The unique identifier or the name of the API to delete


6.1.5 删除API

请求地址:/apis/{name or id}

请求方法:DELETE
PATH参数:

属性 描述
name or id

required

删除API的名称或唯一的标识符。

6.2 插件对象(Plugin Object)

插件实体表示将在HTTP请求/响应生命周期期间执行的插件配置。通过插件,可以为服务添加功能,例如身份验证或速率限制。可以通过访问Kong Hub找到需要的插件,以及有关如何安装和值的更多信息。当添加一个插件配置到服务后,客户端向该服务发出的每个请求都将会运行添加的插件。如果需要为特定消费者将插件调整为不同的值,可以通过指定 consumer_id值来实现:

{
    "id": "4d924084-1adb-40a5-c042-63b19db421d1",
    "service_id": "5fd1z584-1adb-40a5-c042-63b19db49x21",
    "consumer_id": "a3dX2dh2-1adb-40a5-c042-63b19dbx83hF4",
    "name": "rate-limiting",
    "config": {
        "minute": 20,
        "hour": 500
    },
    "enabled": true,
    "created_at": 1422386534
}

6.2.1 优先级

插件将始终只被运行一次,即每次请求只运行一次。但是它所运行的配置取决于它所配置的实体。当插件应用于具有不同配置的不同实体时,存在一个优先顺序来运行插件。经验法则是:插件越具体,所配置的实体数量越多,优先级越高。

当一个插件被多次配置时,完整优先纪顺序是:

  1. 插件的配置组合:路由(Route),服务(Service)和消费者(Consumer)。 (消费者意味着必须对请求进行身份验证)。
  2. 在Route和Consumer的组合上配置的插件。 (消费者意味着必须对请求进行身份验证)。
  3. 在服务和使用者的组合上配置的插件。 (消费者意味着必须对请求进行身份验证)。
  4. 在路由和服务的组合上配置的插件。
  5. 在Consumer上配置的插件。 (消费者意味着必须对请求进行身份验证)。
  6. 在路由上配置的插件。
  7. 在服务上配置的插件。
  8. 配置为全局运行的插件。

 

示例:如果rate-limiting插件应用了两次(具有不同的配置):对于服务(插件配置A)和对于消费者(插件配置B),则对此消费者进行身份验证的请求将运行插件配置B并忽略A.但是,请求不认证此消费者将回退到运行插件配置A.请注意,如果禁用配置B(其enabled标志设置为false),配置A将应用于否则将匹配配置B的请求。


6.2.2 添加插件

可以通过下面的几种方式添加插件:

  • 对于每个服务/路由和消费者。不要设置consumer_id,而是设置service_id或route_id。
  • 适用于每个服务/路由和特定消费者。只有设定consumer_id。
  • 适用于每个消费者和特定服务。仅设置service_id(警告:某些插件只允许设置route_id)
  • 对于每个消费者和特定的路由。仅设置route_id(警告:某些插件只允许设置service_id)
  • 对于特定的服务/路由和消费者。设置service_id/route_id和consumer_id。

请注意,并非所有插件都允许指定consumer_id。

6.2.2.1 Request Body

属性 描述
name 要添加的插件的名称。目前,插件必须分别安装在每个Kong实例中。
consumer_id
可选的
使用者的唯一标识符,用于覆盖传入请求中此特定使用者的现有设置。
config.{property} 插件的配置属性,可以在Kong Hub的插件文档页面找到。
enabled 是否应用插件。默认值:true。

Response

HTTP 201 Created
{
    "id": "4d924084-1adb-40a5-c042-63b19db421d1",
    "service_id": "5fd1z584-1adb-40a5-c042-63b19db49x21",
    "consumer_id": "a3dX2dh2-1adb-40a5-c042-63b19dbx83hF4",
    "name": "rate-limiting",
    "config": {
        "minute": 20,
        "hour": 500
    },
    "enabled": true,
    "created_at": 1422386534
}

 

参考资料

1.《Route Object》地址:https://docs.konghq.com/0.13.x/admin-api/#route-object;

2.《Configuring a Service》地址:https://docs.konghq.com/0.14.x/getting-started/configuring-a-service/

3.《Kong and Kong Enterprise on Kubernetes》地址:https://docs.konghq.com/install/kubernetes/?_ga=2.256537099.1475189429.1544400620-1563374863.1537379250

作者简介:
季向远,北京神舟航天软件技术有限公司。本文版权归原作者所有。

K8S中文社区微信公众号