来自骷髅岛的 Ingress Controller:Kong

2019-07-22 11:24:21 浏览数 (1)

Kong,是一个在 Nginx 反向代理基础上发展而来的 API 网关产品。我之前一直在推动的 Service Mesh,主要关注的是集群(Mesh)内微服务之间的关系,而 API 网关所管理的则是微服务集群边缘,对外服务的管理。(据我观测,Istio 近期的文档已经出现了 Gateway 等说法,似乎也对这方面的问题颇有兴趣的样子)。

传统的 API:

API Gateway:

5 月 8 日,Kong 发布了 Ingress Controller,对 Kubernetes 和对 Kong 自身来说都是个有意思的事情。

首先,Ingress Controller 本来应该负责集群的对外通信,有些 Ingress Controller,例如 haproxy 和 Traefik 已经初步具备了这方面的能力。 其次,Kong 之前使用 API 调用的方式来进行管理,在 Ingress Controller 的上下文中,改用 CRD 方式进行管理,对于我等 YAML 程序员来说,无疑是个大大的利好消息。

Kong 使用插件的方式提供了一些常见功能,这些现在也可以用 CRD 方式进行使用,其中包括日志、限流、认证、鉴权几大类。

Kong 同时提供商业和社区两个版本,目前有部分插件也是商业版独占的。

今天这一篇,就会对 Kong Ingress Controller 从部署到应用的介绍。

安装

官方提供了一个简易的 Kubernetes 环境中的安装文件;另外在 Ingress Controller 出现之前,Kong 也有一个相对更丰富的 Kubernetes 下的安装文档。

全部组件都运行在 kong 命名空间。

数据库

安装过程中会创建一个 Postgres 的 StatefulSet,前面提到,这一版本对 Kubernetes 集群的最低版本要求是 1.8,如果是 1.8 版本,需要将这一个 StatefulSet API 版本改为 apps/v1beta2。另外这一部分需要用 PVC 的形式给数据提供存储空间,所以集群中应该设置缺省 StorageClass。完整的 Kubernetes 安装文档中,还介绍了 Cassandra 的存储方式。

CRD

安装过程中创建了如下的自定义资源:

  • 凭据:用于身份认证。
  • 服务消费者:给不同的 API 用户提供不同的消费者身份,以便实施不同的治理方式。
  • 插件:将过去使用 HTTP API 管理的插件系统,以 CRD 的形式在 Kubernetes 环境下统一管理。
  • KongIngress:对反向代理行为本身进行定义。

服务

其中提供了两组服务:

  • kong-ingress-controller:暴露 8001 端口,用于对 Kong 进行管理。这里建议将服务类型改为 ClusterIP,而不是直接暴露于公网。
  • kong-proxy:Ingress 服务,对其承载的接口调用都从此经过,可以根据集群情况酌情使用 NodePort 或者 ClusterIP -> Ingress 的方式对外提供服务。

提供服务

安装结束后,就可以使用网关来对外提供服务了。

官方提供了一个简单的例子应用,我们当然也可以选择别的应用来试用。为他编写一个 Ingress 资源:

代码语言:javascript复制
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: dummy
annotations:
kubernetes.io/ingress.class: nginx # 这里仍然是 nginx
spec:
rules:
- host: dummy.example.com
http:
paths:
- path: /
backend:
serviceName: http-svc
servicePort: 89

如果没有公网 Loadbalancer 条件,可以使用 /etc/hosts、dnsmasq、或者 curl host 几种方式来模拟。

ingress 资源创建成功之后,就可以使用域名来访问这一服务了。

TLS 加密

作为 Ingress Controller,添加证书提供 https 服务也是基本要求之一。这方面 Kong Ingress Controller 使用的是 tls secret 的方式:

  1. 首先获取证书,可以自行签名,或者使用已有证书文件。
  2. kubectl create secret tls rocks --key privkey.pem --cert fullchain.pem:创建一个名为 rocks 的 Secret,其中包含我们的证书和私钥。
  3. 在 Ingress 资源定义中加入下列内容,引用刚才创建的 Secret: tls: - hosts: - dummy.example.com secretName: rocks

这样就可以使用 https 进行访问了。

试用限流插件

前面提到,Kong Ingress Controller 使用 CRD 方式来实现插件的应用。下面我们创建一个限流插件的 CRD:

代码语言:javascript复制
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: one-per-second-ten-per-hour
config:
hour: 10
limit_by: ip
second: 1

目前并没有很完善的插件 CRD 规范的文档,因此其中的具体字段需要去该插件的文档页面去查找,例如这里引用的 Ratelimit。

在这一个 YAML 中我们会发现,其中并没有表明具体使用的插件以及对应的服务,通过对 controller 管理端口的 /plugins 进行查询,也会看到其中并没有定义活动的插件。

要把它应用到具体服务上,还需要修改我们要控制的 Ingress 资源,在其中加入注解,来引用这一 CRD:

代码语言:javascript复制
kubernetes.io/ingress.class: nginx
rate-limiting.plugin.konghq.com: one-per-second-ten-per-hour

提交新的 Ingress 之后,再次访问管理端口的 plugins 路径,会得到以下响应:

代码语言:javascript复制
{
"total": 1,
"data": [
{
"created_at": 1525966801000,
"config": {
"redis_database": 0,
"policy": "cluster",
"redis_timeout": 2000,
"hide_client_headers": false,
"hour": 20,
"limit_by": "ip",
"redis_port": 6379,
"second": 10,
"fault_tolerant": true},
"id": "8539eb6f-5467-11e8-a92e-000d3a07d45d",
"name": "rate-limiting",
"enabled": true,
"route_id": "f2961715-11fd-410a-a934-dbd6822e5fac"}
]}

可以使用 siege 或者 curl/wrk 等其他工具来访问 API,会发现超过限度之后,服务器返回 429 的状态码:

HTTP/1.1 200 0.20 secs: 727 bytes ⇒ GET / HTTP/1.1 200 0.22 secs: 729 bytes ⇒ GET / HTTP/1.1 429 0.20 secs: 38 bytes ⇒ GET / HTTP/1.1 429 0.21 secs: 38 bytes ⇒ GET / HTTP/1.1 429 0.20 secs: 38 bytes ⇒ GET / HTTP/1.1 200 0.20 secs: 729 bytes ⇒ GET / HTTP/1.1 200 0.20 secs: 727 bytes ⇒ GET / HTTP/1.1 429 0.20 secs: 38 bytes ⇒ GET /

证明限流功能已经生效。

试用消费者

前面提到,可以使用消费者这一概念,对微服务的用户身份加以甄别,从而提供不同的管控方式。在前面的基础上,我们希望为部分用户修改一下响应内容。

首先创建一个 KongConsumer 对象:

代码语言:javascript复制
apiVersion: configuration.konghq.com/v1
kind: KongConsumer
metadata:
name: rich
username: boss

接下来,为这个用户创建凭据,凭据是需要认证的,所以还要启用一个插件:key-auth,官方文档中并没有提及这一点:

代码语言:javascript复制
apiVersion: configuration.konghq.com/v1
kind: KongCredential
metadata:
name: rich-login
consumerRef: rich # 如果删除这一字段,就代表面向所有消费者。
type: key-auth
config:
key: 62eb165c070a41d5c1b58d9d3d725ca1

然后,为这个用户创建一个插件配置

代码语言:javascript复制
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: rich-response
consumerRef: rich
config:
hour: 100
limit_by: ip
second: 10

最后,在 Ingress 资源中启用两个插件,分别是 key-authresponse-transformer

代码语言:javascript复制
response-transformer.plugin.konghq.com: boss
key-auth.plugin.konghq.com: auth

重新配置 Ingress 之后,可以使用 curl 进行校验:

curl —header “apikey: aasome_key_data” -s -i https://dummy.example.com HTTP/1.1 403 Forbidden Date: Fri, 11 May 2018 04:17:57 GMT Content-Type: application/json; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive Server: kong/0.13.1

{“message”:”Invalid authentication credentials”}

可以看到上面的认证没能通过。

curl —header “apikey: some_key_data” -s -i https://dummy.example.com | grep boss boss: true x-consumer-username=boss2

Key Auth 认证插件根据 APIKey 取得了用户名,并且激活了 Response Transformer 插件,在 Header 中加入了我们配置的内容。

Kong 原有的 API 在这里还是可以使用的,例如:

  1. curl http://[api-url]/plugins 查询生效插件
  2. curl http://[api-url] 返回 JSON 中的 /plugins/available_on_server 列出所有可用插件。
  3. curl ttp://[api-url]/consumers 列出所有消费者。

相关链接:

  1. https://konghq.com/
  2. https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/single/all-in-one-postgres.yaml
  3. https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/manifests/dummy-application.yaml

0 人点赞