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 的方式:
- 首先获取证书,可以自行签名,或者使用已有证书文件。
kubectl create secret tls rocks --key privkey.pem --cert fullchain.pem
:创建一个名为rocks
的 Secret,其中包含我们的证书和私钥。- 在 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
路径,会得到以下响应:
{
"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-auth
和 response-transformer
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 在这里还是可以使用的,例如:
curl http://[api-url]/plugins
查询生效插件curl http://[api-url]
返回 JSON 中的/plugins/available_on_server
列出所有可用插件。curl ttp://[api-url]/consumers
列出所有消费者。
相关链接:
https://konghq.com/
https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/single/all-in-one-postgres.yaml
https://raw.githubusercontent.com/Kong/kubernetes-ingress-controller/master/deploy/manifests/dummy-application.yaml