Kong

Mar 18, 2020 16:00 · 1396 words · 3 minute read Gateway Nginx OpenResty Kong

Kong 是什么?

Kong 是一款可伸缩的开源 API 网关。Kong 运行在业务 RESTful API 之前并且支持通过插件来扩展。

Kong 的优势

  • 可扩展:只需添加机器即可实现水平伸缩以应对任何负载,同时保持较低的延迟。
  • 模块化:通过添加插件来扩展,可以通过 RESTful 管理 API 轻松配置。
  • 通吃任何基础架构:随处可运行,无论公有云还是本地环境。

Kong 基于 NGINX 和 Apache Cassandra 或 PostgreSQL 打造,并提供了简单易用的 RESTful API 来配置系统。

请求流程

一旦 Kong 运行,所有 API 请求会先到达 Kong 并被代理至上游 API,Kong 就是每个 API 请求的入口。

Kong 使用指南(CentOS)

1. 部署数据中间件

Kong 需要 Apache Cassandra 或 PostgreSQL 作为数据库:

$ docker run -d --name kong-database \
    -p 5432:5432 \
    -e "POSTGRES_USER=kong" \
    -e "POSTGRES_DB=kong" \
    -e "POSTGRES_PASSWORD=kong" \
    postgres:9.6

2. 安装 Kong

Kong 支持任何环境的部署,请参考 https://konghq.com/install/?itm_source=website&itm_medium=nav/

$ wget https://bintray.com/kong/kong-rpm/rpm -O bintray-kong-kong-rpm.repo
$ export major_version=`grep -oE '[0-9]+\.[0-9]+' /etc/redhat-release | cut -d "." -f1`
$ sed -i -e 's/baseurl.*/&\/centos\/'$major_version''/ bintray-kong-kong-rpm.repo
$ sudo mv bintray-kong-kong-rpm.repo /etc/yum.repos.d/
$ sudo yum update -y
$ sudo yum install -y kong

3. 初始化数据库

首先将 Kong 默认的配置文件 /etc/kong/kong.conf.default 去掉 .default 后缀,并修改数据库相关配置:

# When not using a database, Kong is said to be in "DB-less mode": it will keep
# its entities in memory, and each node needs to have this data entered via a
# declarative configuration file, which can be specified through the
# `declarative_config` property, or via the Admin API using the `/config`
# endpoint.

database = postgres             # Determines which of PostgreSQL or Cassandra
                                 # this node will use as its datastore.
                                 # Accepted values are `postgres`,
                                 # `cassandra`, and `off`.

pg_host = 127.0.0.1             # Host of the Postgres server.
pg_port = 5432                  # Port of the Postgres server.
pg_timeout = 5000               # Defines the timeout (in ms), for connecting,
                                 # reading and writing.

pg_user = kong                  # Postgres user.
pg_password = kong              # Postgres user's password.
pg_database = kong              # The database name to connect to.

执行 Kong 迁移命令:

$ kong migrations bootstrap -c /etc/kong/kong.conf
Bootstrapping database...
migrating core on database 'kong'...
core migrated up to: 000_base (executed)
core migrated up to: 003_100_to_110 (executed)
core migrated up to: 004_110_to_120 (executed)
core migrated up to: 005_120_to_130 (executed)
core migrated up to: 006_130_to_140 (executed)
core migrated up to: 007_140_to_150 (executed)
core migrated up to: 008_150_to_200 (executed)
migrating hmac-auth on database 'kong'...
hmac-auth migrated up to: 000_base_hmac_auth (executed)
hmac-auth migrated up to: 002_130_to_140 (executed)
migrating oauth2 on database 'kong'...
oauth2 migrated up to: 000_base_oauth2 (executed)
oauth2 migrated up to: 003_130_to_140 (executed)
migrating jwt on database 'kong'...
jwt migrated up to: 000_base_jwt (executed)
jwt migrated up to: 002_130_to_140 (executed)
migrating basic-auth on database 'kong'...
basic-auth migrated up to: 000_base_basic_auth (executed)
basic-auth migrated up to: 002_130_to_140 (executed)
migrating key-auth on database 'kong'...
key-auth migrated up to: 000_base_key_auth (executed)
key-auth migrated up to: 002_130_to_140 (executed)
migrating rate-limiting on database 'kong'...
rate-limiting migrated up to: 000_base_rate_limiting (executed)
rate-limiting migrated up to: 003_10_to_112 (executed)
migrating acl on database 'kong'...
acl migrated up to: 000_base_acl (executed)
acl migrated up to: 002_130_to_140 (executed)
migrating acme on database 'kong'...
acme migrated up to: 000_base_acme (executed)
migrating response-ratelimiting on database 'kong'...
response-ratelimiting migrated up to: 000_base_response_rate_limiting (executed)
migrating session on database 'kong'...
session migrated up to: 000_base_session (executed)
24 migrations processed
24 executed
Database is up-to-date

4. 启动 Kong

$ kong start -c /etc/kong/kong.conf
2020/03/18 15:43:13 [warn] ulimit is currently set to "1024". For better performance set it to at least "4096" using "ulimit -n"
Kong started
$ netstat -ltupn | grep nginx
tcp        0      0 0.0.0.0:8443            0.0.0.0:*               LISTEN      15227/nginx: master
tcp        0      0 127.0.0.1:8444          0.0.0.0:*               LISTEN      15227/nginx: master
tcp        0      0 0.0.0.0:8000            0.0.0.0:*               LISTEN      15227/nginx: master
tcp        0      0 127.0.0.1:8001          0.0.0.0:*               LISTEN      15227/nginx: master
  • :8000 - Kong 用户业务 HTTP API
  • :8443 - Kong 用户业务 HTTPS API
  • :8001 - Kong 管理 HTTP API
  • :8444 - Kong 管理 HTTPS API

使用 kong stop 命令即可停止 Kong。

5. 配置上游服务

5.1 启动一个 flask app 作为上游

$ docker run -d --name flask-app \
    -p 5000:5000 \
    jcdemo/flaskapp:latest
$ curl -X GET http://127.0.0.1:5000
<html><head><title>Docker + Flask Demo</title></head><body><table><tr><td> Start Time </td> <td>2020-Mar-18 03:25:05</td> </tr><tr><td> Hostname </td> <td>d04f1dddbae4</td> </tr><tr><td> Local Address </td> <td>172.18.0.4</td> </tr><tr><td> Remote Address </td> <td>172.18.0.1</td> </tr><tr><td> Server Hit </td> <td>5</td> </tr></table></body></html>#

5.2 调用 Kong 管理 API 添加服务

$ curl -i -X POST http://127.0.0.1:8001/services/ \
    --data 'name=flask-app' \
    --data 'url=http://127.0.0.1:5000'
HTTP/1.1 201 Created
Date: Wed, 18 Mar 2020 07:57:37 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Server: kong/2.0.2
Content-Length: 290
X-Kong-Admin-Latency: 110

{"host":"127.0.0.1","created_at":1584518257,"connect_timeout":60000,"id":"7f597887-a38c-4fa3-be7b-cbd4c0abf604","protocol":"http","name":"flask-app","read_timeout":60000,"port":5000,"path":null,"updated_at":1584518257,"retries":5,"write_timeout":60000,"tags":null,"client_certificate":null}

5.3 调用 Kong API 添加路由

$ curl -i -X POST http://127.0.0.1:8001/services/flask-app/routes \
    --data 'hosts[]=foo.bar.baz'
HTTP/1.1 201 Created
Date: Wed, 18 Mar 2020 08:01:25 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Server: kong/2.0.2
Content-Length: 429
X-Kong-Admin-Latency: 116

{"id":"33a0c14d-a030-4d82-bf23-624db029f76f","path_handling":"v0","paths":null,"destinations":null,"headers":null,"protocols":["http","https"],"methods":null,"snis":null,"service":{"id":"7f597887-a38c-4fa3-be7b-cbd4c0abf604"},"name":null,"strip_path":true,"preserve_host":false,"regex_priority":0,"updated_at":1584518485,"sources":null,"hosts":["foo.bar.baz"],"https_redirect_status_code":426,"tags":null,"created_at":1584518485}#

5.4 测试通过 Kong 来转发请求

$ curl -i -X GET http://127.0.0.1:8000/ \
    --header 'Host: foo.bar.baz'
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 351
Connection: keep-alive
Server: Werkzeug/0.14.1 Python/3.7.1
Date: Wed, 18 Mar 2020 08:03:21 GMT
X-Kong-Upstream-Latency: 3
X-Kong-Proxy-Latency: 0
Via: kong/2.0.2

<html><head><title>Docker + Flask Demo</title></head><body><table><tr><td> Start Time </td> <td>2020-Mar-18 03:25:05</td> </tr><tr><td> Hostname </td> <td>d04f1dddbae4</td> </tr><tr><td> Local Address </td> <td>172.18.0.4</td> </tr><tr><td> Remote Address </td> <td>172.18.0.1</td> </tr><tr><td> Server Hit </td> <td>6</td> </tr></table></body></html>#

可以看到 Kong 成功将请求转发至了 #5.2 中通过 url 参数配置的 flask app,Kong 通过 HTTP 请求头中的 Host 来决定转发路径。

6. 使能插件

6.1 配置 key-auth 插件

curl -i -X GET http://127.0.0.1:8001/services/flask-app/plugins/ \
    --data 'name=key-auth'
HTTP/1.1 201 Created
Date: Wed, 18 Mar 2020 08:17:49 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Server: kong/2.0.2
Content-Length: 363
X-Kong-Admin-Latency: 6

{"created_at":1584519469,"config":{"key_names":["apikey"],"run_on_preflight":true,"anonymous":null,"hide_credentials":false,"key_in_body":false},"id":"7747d48d-1142-47d1-ba2d-799cf5678201","service":{"id":"7f597887-a38c-4fa3-be7b-cbd4c0abf604"},"enabled":true,"protocols":["grpc","grpcs","http","https"],"name":"key-auth","consumer":null,"route":null,"tags":null}#

6.2 测试插件生效

$ curl -i -X GET http://127.0.0.1:8000/ \
    --header 'Host: foo.bar.baz'
HTTP/1.1 401 Unauthorized
Date: Wed, 18 Mar 2020 08:25:22 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
WWW-Authenticate: Key realm="kong"
Content-Length: 41
X-Kong-Response-Latency: 2
Server: kong/2.0.2

{"message":"No API key found in request"}#

因为暂时还未指定 apikey HTTP 请求头或参数。

7. 添加消费者

7.1 调用 Kong API 创建消费者

$ curl -i -X POST http://127.0.0.1:8001/consumers/ \
    --data 'username=crazytaxii'
HTTP/1.1 201 Created
Date: Wed, 18 Mar 2020 08:31:26 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Server: kong/2.0.2
Content-Length: 122
X-Kong-Admin-Latency: 2

{"custom_id":null,"created_at":1584520286,"id":"55b21259-c76c-458f-b7e6-8d4116b2c839","tags":null,"username":"crazytaxii"}#

7.2 为消费者配置凭证

$ curl -i -X POST http://127.0.0.1:8001/consumers/crazytaxii/key-auth \
    --data 'key=shamballa'
HTTP/1.1 201 Created
Date: Wed, 18 Mar 2020 08:34:26 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Server: kong/2.0.2
Content-Length: 167
X-Kong-Admin-Latency: 4

{"created_at":1584520466,"consumer":{"id":"55b21259-c76c-458f-b7e6-8d4116b2c839"},"id":"c522bc31-aa5f-455e-89b5-add819941c9d","tags":null,"ttl":null,"key":"shamballa"}#

7.3 测试消费者凭证是否有效

$ curl -i -X GET http://127.0.0.1:8000/ \
    --header 'Host: foo.bar.baz' \
    --header 'apikey: shamballa'
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 351
Connection: keep-alive
Server: Werkzeug/0.14.1 Python/3.7.1
Date: Wed, 18 Mar 2020 08:35:58 GMT
X-Kong-Upstream-Latency: 3
X-Kong-Proxy-Latency: 2
Via: kong/2.0.2

<html><head><title>Docker + Flask Demo</title></head><body><table><tr><td> Start Time </td> <td>2020-Mar-18 03:25:05</td> </tr><tr><td> Hostname </td> <td>d04f1dddbae4</td> </tr><tr><td> Local Address </td> <td>172.18.0.4</td> </tr><tr><td> Remote Address </td> <td>172.18.0.1</td> </tr><tr><td> Server Hit </td> <td>7</td> </tr></table></body></html>#