Kong is a cloud-native, fast, scalable, and distributed Microservice Abstraction Layer (also known as an API Gateway, API Middleware or in some cases Service Mesh). Made available as an open-source project in 2015, its core values are high performance and extensibility.

实体对象

  • Router:请求转发规则,将请求转发给 Service
  • Services:多个 Upstream 集合,Router 的转发目标
  • Consumers:消费者
  • Plugin:插件,可以是全局的也可以配置到特定的 Router、Services、Consumers
  • Certificate:https 证书
  • Sni:域名与 Certificate 的绑定
  • Upstream:负载均衡策略
  • Target:最终处理请求的后端服务

安装

API

# Admin api 对 Kong 的所有操作
$ curl localhost:8001
# Proxy api 提供给客户端或者消费者对上游 service 的消费接口
$ curl localhost:8000
$ curl localhost:8443 (SSL)

具体操作请参考: Admin API 操作手册

核心实体

$ curl localhost:8001/apis //service apis
$ curl localhost:8001/consumers //消费者
$ curl localhost:8001/plugins //插件

图形界面

简单的接入配置

添加 API 到 Kong 中,首先添加 Service, 这个服务就是Kong 管理的微服务或者 Upstream 上游的服务。

本地测试使用 Flask 部署一个最简单的 Web 应用

$ cat web.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
$ export FLASK_APP=web.py
$ flask run
* Serving Flask app "web.py"
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

添加 Service

$ curl -i -X POST \
--url http://localhost:8001/services/ \
--data 'name=example-service' \
--data 'url=http://localhost:5000'
HTTP/1.1 201 Created
Date: Mon, 12 Aug 2019 06:28:29 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Server: kong/1.2.1
Content-Length: 270
{
"host":"localhost",
"created_at":1565591309,
"connect_timeout":60000,
"id":"00100765-1bb9-45d8-bb38-afb853f6fa37",
"protocol":"http",
"name":"example-service",
"read_timeout":60000,
"port":5000,
"path":null,
"updated_at":1565591309,
"retries":5,
"write_timeout":60000,
"tags":null
}

给 Service 添加 Router

$ curl -i -X POST \
--url http://localhost:8001/services/example-service/routes \
--data 'hosts[]=example.com'
HTTP/1.1 201 Created
Date: Mon, 12 Aug 2019 06:35:36 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Server: kong/1.2.1
Content-Length: 393
{
"id":"3daac1d8-7570-414a-b1a9-606cda10d2f1",
"tags":null,
"paths":null,
"destinations":null,
"protocols":[
"http",
"https"
],
"created_at":1565591736,
"snis":null,
"hosts":[
"example.com"
],
"name":null,
"preserve_host":false,
"regex_priority":0,
"strip_path":true,
"sources":null,
"updated_at":1565591736,
"https_redirect_status_code":426,
"service":{
"id":"00100765-1bb9-45d8-bb38-afb853f6fa37"
},
"methods":null
}

通过 Kong 转发请求

直接访问 Kong 的 Proxy api 即可访问到 Flask 应用

$ curl -i -X GET \
--url http://localhost:8000/ \
--header 'Host: example.com'
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 13
Connection: keep-alive
Server: Werkzeug/0.15.5 Python/2.7.11
Date: Mon, 12 Aug 2019 06:37:10 GMT
X-Kong-Upstream-Latency: 2
X-Kong-Proxy-Latency: 1
Via: kong/1.2.1
Hello, World!

添加插件

添加一个接口验证 key-auth 插件

$ curl -i -X POST \
--url http://localhost:8001/services/example-service/plugins/ \
--data 'name=key-auth'
HTTP/1.1 201 Created
Date: Mon, 12 Aug 2019 06:43:47 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Server: kong/1.2.1
Content-Length: 365
{
"created_at":1565592227,
"config":{
"key_names":[
"apikey"
],
"run_on_preflight":true,
"anonymous":null,
"hide_credentials":false,
"key_in_body":false
},
"id":"54ca5f58-975a-49b4-8c14-d6b4e5add330",
"service":{
"id":"00100765-1bb9-45d8-bb38-afb853f6fa37"
},
"name":"key-auth",
"protocols":[
"http",
"https"
],
"enabled":true,
"run_on":"first",
"consumer":null,
"route":null,
"tags":null
}

再次访问则提示 401 Unauthorized

$ curl -i -X GET \
--url http://localhost:8000/ \
--header 'Host: example.com'
HTTP/1.1 401 Unauthorized
Date: Mon, 12 Aug 2019 06:45:24 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
WWW-Authenticate: Key realm="kong"
Content-Length: 41
Server: kong/1.2.1
{
"message":"No API key found in request"
}

添加消费者

$ curl -i -X POST \
--url http://localhost:8001/consumers/ \
--data "username=Abner"
HTTP/1.1 201 Created
Date: Mon, 12 Aug 2019 06:51:54 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Server: kong/1.2.1
Content-Length: 117
{
"custom_id":null,
"created_at":1565592714,
"id":"c3d8a745-5d6f-4966-8678-e6644139e0b7",
"tags":null,
"username":"Abner"
}

给消费者添加 key

$ curl -i -X POST \
--url http://localhost:8001/consumers/Abner/key-auth/ \
--data 'key=test'
HTTP/1.1 201 Created
Date: Mon, 12 Aug 2019 06:53:42 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Server: kong/1.2.1
Content-Length: 139
{
"key":"test",
"created_at":1565592822,
"consumer":{
"id":"c3d8a745-5d6f-4966-8678-e6644139e0b7"
},
"id":"d71b6d4d-3f74-489f-a036-d340f4bcc991"
}
# 验证
$ curl -i -X GET \
--url http://localhost:8000 \
--header "Host: example.com" \
--header "apikey: test"
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 13
Connection: keep-alive
Server: Werkzeug/0.15.5 Python/2.7.11
Date: Mon, 12 Aug 2019 06:55:51 GMT
X-Kong-Upstream-Latency: 2
X-Kong-Proxy-Latency: 2
Via: kong/1.2.1
Hello, World!

负载均衡配置

我们可以通过 Kong 配置如下的负载均衡效果

upstream example {
server localhost:5000 weight=100;
server localhost:5001 weight=50;
}
server {
listen 80;
location /example {
proxy_pass http://example;
}
}

主要涉及到的 Kong 的几个核心东西:

  • upstream:和 nginx upstream 相同,对上游服务器进行抽象
  • target:具体的主机或者微服务实例,IP + PORT 的形式
  • service:服务层面抽象,可以映射到具体服务,也可以指向 upstream 来实现负载均衡
  • router:路由的抽象,将请求映射到 service

首先我用 Flask 启动两个 web 应用,分别监听 5000 和 5001 端口

$ curl 0.0.0.0:5000
server 5000
$ curl 0.0.0.0:5001
server 5001

配置 upstream 和 target

添加 example upstream

$ curl -X POST http://localhost:8001/upstreams \
--data "name=example"

添加两个负载均衡节点

$ curl -X POST http://localhost:8001/upstreams/example/targets \
--data "target=localhost:5000" \
--data "weight=100"
$ curl -X POST http://localhost:8001/upstreams/example/targets \
--data "target=localhost:5001" \
--data "weight=50"

配置 service 和 route

$ curl -X POST http://localhost:8001/services\
--data "name=example" \
--data "host=example"
{
"host":"example",
"created_at":1565595520,
"connect_timeout":60000,
"id":"d9873e6e-6dd5-4a5a-accb-40f96865d0a2",
"protocol":"http",
"name":"example",
"read_timeout":60000,
"port":80,
"path":null,
"updated_at":1565595520,
"retries":5,
"write_timeout":60000,
"tags":null
}
$ curl -X POST http://localhost:8001/routes \
--data "paths[]=/example" \
--data "service.id=d9873e6e-6dd5-4a5a-accb-40f96865d0a2"

至此一个典型的负载均衡已经配置完成,实测有效。