Kong 是一款基于 OpenResty(Nginx + Lua 模块)编写的高可用、易扩展的,由 Mashape 公司开源的 API Gateway 项目。Kong 是基于 NGINX 和 Apache Cassandra 或 PostgreSQL 构建的,能提供易于使用的 RESTful API 来操作和配置 API 管理系统,所以它可以水平扩展多个 Kong 服务器,通过前置的负载均衡配置把请求均匀地分发到各个 Server,来应对大批量的网络请求。
Kong 主要有三个组件:
Kong 采用插件机制进行功能定制,插件集(可以是 0 或 N 个)在 API 请求响应循环的生命周期中被执行。插件使用 Lua 编写,目前已有几个基础功能:HTTP 基本认证、密钥认证、CORS(Cross-Origin Resource Sharing,跨域资源共享)、TCP、UDP、文件日志、API 请求限流、请求转发以及 Nginx 监控。
Kong 网关具有以下的特性:
环境: PostgreSQL 9.6 + CentOS 7
下载地址:https://www.postgresql.org/download/linux/redhat/
选择 PostgreSQL 9.6 + CentOS 7 后获得安装方式:
启动 postgresql 后查看状态:
为了安全以及满足 Kong 初始化的需求,需要创建一个 Linux 用户 kong,并创建对应的 PostgreSQL 用户 kong 和数据库 kong
# 创建一个 Linux 用户 `kong`$ adduser kong
# 切换到 Linux 系统用户 `postgres`,因为它是 PostgreSQL 数据库的系统管理员$ su postgres
# 进入 PostgreSQL 控制台$ psql
# 设置用户 `postgres` 的密码【仅仅首次需要】# 注意开头的 \ 必须有!$ \password postgres
# 创建一个 PostgreSQL 用户 `kong`,和上面创建的 Linux 用户 `kong` 对应。# 密码 '123456' 根据自己需要生成$ create user kong with password '123456'; # 创建一个 PostgreSQL 数据库 `kong`$ create database kong owner kong;# 将数据库 `kong` 授权给 PostgreSQL 用户 `kong`$ grant all privileges on database kong to kong;
# 退出 PostgreSQL 控制台$ \q
复制代码
PostgreSQL 有四种身份认证方式:
默认配置下,我们无法在本地或者远程使用 PostgreSQL 用户名和密码直接连接,因为本地使用 peer 认证方式,远程使用 ident 认证方式。解决方法比较简单,将本地和远程的认证方式修改成 trust 或者 password 即可。
修改 /var/lib/pgsql/9.6/data/pg_hba.conf 文件,注释掉所有默认配置,并添加一条 host all all 0.0.0.0/0 trust 默认,无论远程还是本地访问,任何 PostgreSQL 用户和数据库,都使用 trust 认证方式。
默认配置下,PostgreSQL 只允许本地连接,所以我们需要修改 /var/lib/pgsql/9.6/data/postgresql.conf 文件,添加 listen_address 配置项为 *,允许远程连接。
修改完成后,执行 sudo systemctl restart postgresql-9.6 命令,重启 PostgreSQL 数据库。
通过 Navicat 可以连接到 postgresql 数据库:
centos7 下安装 kong:
https://download.konghq.com/gateway-1.x-centos-7/Packages/k/
wget https://download.konghq.com/gateway-1.x-centos-7/Packages/k/kong-1.5.1.el7.amd64.rpmsudo yum install kong-1.5.1.el7.amd64.rpm
复制代码
Kong 的默认配置文件是 /etc/kong/kong.conf.default,使用 cp /etc/kong/kong.conf.default /etc/kong/kong.conf 命令,复制一份新的配置文件。
复制完成后,修改 /etc/kong/kong.conf 配置文件,设置使用 PostgreSQL 数据库。
执行 kong migrations bootstrap -c /etc/kong/kong.conf 命令,进行 Kong 的 PostgreSQL 数据库的表初始化。
navicat 中可以看到表信息
执行 kong start -c /etc/kong/kong.conf 命令,执行 Kong 的启动。
#启动命令kong start -c /etc/kong/kong.conf # 停止命令kong stop# 重新加载kongkong reload
复制代码
启动成功时,会看到 Kong started 日志。
默认情况下,Kong 绑定 4 个端口:
# 请求 Proxy 端口$ curl http://127.0.0.1:8000{"message":"no Route matched with those values"} # 因为我们暂时没配置 Kong 路由。
# 请求 Admin 端口# 注意,考虑到安全性,Admin 端口只允许本机访问。$ curl http://127.0.0.1:8001{"plugins":{"enabled_in_cluster":[],"available_on_server":{... // 省略
复制代码
前提:准备好 docker 环境
Kong 安装有两种方式一种是没有数据库依赖的 DB-less 模式,另一种是 with a Database 模式。我们这里使用第二种带 Database 的模式,因为这种模式功能更全。
首先我们创建一个 Docker 自定义网络,以允许容器相互发现和通信。在下面的创建命令中kong-net
是我们创建的 Docker 网络名称,当然你可以使用你认为合适的名称。
docker network create kong-net
复制代码
Kong 目前使用 Cassandra(Facebook 开源的分布式的 NoSQL 数据库) 或者 PostgreSql,你可以执行以下命令中的一个来选择你的 Database。请注意定义网络 --network=kong-net
。
docker run -d --name kong-database \ --network=kong-net \ -p 9042:9042 \ cassandra:3
复制代码
docker run -d --name kong-database \ --network=kong-net \ -p 5432:5432 \ -e "POSTGRES_USER=kong" \ -e "POSTGRES_DB=kong" \ postgres:9.6
复制代码
这里有个小问题。如果你使用的是 PostgreSQL,想挂载卷持久化数据到宿主机。通过 -v
命令是不好用的。这里推荐你使用 docker volume create
命令来创建一个挂载。
docker volume create kong-volume
复制代码
然后上面的 PostgreSQL 就可以通过- v kong-volume:/var/lib/postgresql/data
进行挂载了。
docker run -d --name kong-database \ --network=kong-net \ -p 5432:5432 \ -v kong-volume:/var/lib/postgresql/data \ -e "POSTGRES_USER=kong" \ -e "POSTGRES_DB=kong" \ -e "POSTGRES_PASSWORD=kong" \ postgres:9.6
复制代码
我们使用docker run --rm
来初始化数据库,该命令执行后会退出容器而保留内部的数据卷(volume)。
docker run --rm \ --network=kong-net \ -e "KONG_DATABASE=postgres" \ -e "KONG_PG_HOST=kong-database" \ -e "KONG_PG_PASSWORD=kong" \ -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \ kong:latest kong migrations bootstrap
复制代码
navicat 中可以看到表信息
完成初始化或者迁移数据库后,我们就可以启动一个连接到数据库容器的 Kong 容器,请务必保证你的数据库容器启动状态,同时检查所有的环境参数 -e
是否是你定义的环境。
docker run -d --name kong \ --network=kong-net \ -e "KONG_DATABASE=postgres" \ -e "KONG_PG_HOST=kong-database" \ -e "KONG_PG_PASSWORD=kong" \ -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \ -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \ -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \ -e "KONG_PROXY_ERROR_LOG=/dev/stderr" \ -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \ -e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" \ -p 8000:8000 \ -p 8443:8443 \ -p 8001:8001 \ -p 8444:8444 \ kong:latest
复制代码
可通过 curl -i http://192.168.65.200:8001/
或者浏览器调用 http://192.168.65.200:8001/ 来验证 Kong Admin 是否联通 。
Kong 企业版提供了管理 UI,开源版本是没有的。但是有很多的开源的管理 UI ,其中比较好用的是 Konga。项目地址:https://github.com/pantsel/konga
Konga 主要是用 AngularJS 写的,运行于 nodejs 服务端。具有以下特性:
docker volume create konga-postgresql
复制代码
docker run -d --name konga-database \ --network=kong-net \ -p 5433:5432 \ -v konga-postgresql:/var/lib/postgresql/data \ -e "POSTGRES_USER=konga" \ -e "POSTGRES_DB=konga" \ -e "POSTGRES_PASSWORD=konga" \ postgres:9.6
复制代码
docker run --rm --network=kong-net \ pantsel/konga:latest -c prepare -a postgres -u postgres://konga:konga@konga-database:5432/konga
复制代码
相关命令解读:
到此 Konga 的数据库环境就搞定了,通过 Navicat 可以查看到 konga 数据库及其数据表。
Konga 还有一些可配置的环境参数:
通过以下命令就可以启动 Konga 容器了
docker run -d -p 1337:1337 \ --network kong-net \ -e "DB_ADAPTER=postgres" \ -e "DB_URI=postgres://konga:konga@konga-database:5432/konga" \ -e "NODE_ENV=production" \ -e "DB_PASSWORD=konga" \ --name konga \ pantsel/konga
复制代码
运行完后,如果成功可以通过http://192.168.65.200:1337/ 链接到控制台。
通过注册后进入,然后在 dashboard 面板里面添加 Kong 的管理 Api 路径 http://ip:8001
nginx 下负载均衡配置
upstream tulingmall-product-upstream { server 192.168.65.190:8866 weight=100; server 192.168.65.190:8867 weight=100;}
server { listen 80; location /pms/ { proxy_pass http://tulingmall-product-upstream; }}
复制代码
通过 Kong Admin API 进行上述的负载均衡的配置
https://docs.konghq.com/enterprise/2.4.x/admin-api/
调用 Kong Admin API /upstreams
,创建名字为 demo-upstream
的 upstream
$ curl -X POST http://127.0.0.1:8001/upstreams --data "name=tulingmall-product-upstream"
复制代码
调用 Kong Admin API /upstreams/{upstream}/targets
,创建 tulingmall-product 服务对应的 2 个 target。注意,{upstream}
路径参数为 upstream 的名字。
# 192.168.65.190:8866 对应的 target$ curl -X POST http://127.0.0.1:8001/upstreams/tulingmall-product-upstream/targets --data "target=192.168.65.190:8866" --data "weight=100"# 192.168.65.190:8867 对应的 target$ curl -X POST http://127.0.0.1:8001/upstreams/tulingmall-product-upstream/targets --data "target=192.168.65.190:8867" --data "weight=100"
复制代码
调用 Kong Admin API /services
,创建名字为 tulingmall-product
的 service。host 参数,用于设置对应的 upstream 的名字。
curl -X POST http://127.0.0.1:8001/services --data "name=tulingmall-product" --data "host=tulingmall-product-upstream" --data "path=/pms"
复制代码
调用 Kong Admin API services/${service}/routes
,创建一个请求路径为 path
的 route。注意,{service}
路径参数,为 service 的名字。
curl -X POST http://localhost:8001/services/tulingmall-product/routes --data "name=tulingmall-product-route" --data "paths[]=/pms"
复制代码
curl http://127.0.0.1:8000/pms/productInfo/42
复制代码
Kong 提供了 Rate Limiting 插件,实现对请求的限流功能,避免过大的请求量过大,将后端服务打挂。
Rate Limiting 支持秒/分/小时/日/月/年多种时间维度的限流,并且可以组合使用。例如说:限制每秒最多 100 次请求,并且每分钟最多 1000 次请求。
Rate Limiting 支持 consumer
、credential
、ip
三种基础维度的限流,默认为 consumer
。例如说:设置每个 IP 允许每秒请求的次数。计数的存储,支持使用 local
、cluster
、redis
三种方式进行存储,默认为 cluster
:
local
:存储在 Nginx 本地,实现单实例限流。cluster
:存储在 Cassandra 或 PostgreSQL 数据库,实现集群限流。redis
:存储在 Redis 数据库,实现集群限流。Rate Limiting 采用的限流算法是计数器的方式,所以无法提供类似令牌桶算法的平滑限流能力。
调用 Kong Admin API services/${service}/plugins
,创建 Rate Limiting 插件的配置:
# 服务上启用插件$ curl -X POST http://127.0.0.1:8001/services/tulingmall-product/plugins \ --data "name=rate-limiting" \ --data "config.second=1" \ --data "config.limit_by=ip" # 路由上启用插件$ curl -X POST http://127.0.0.1:8001/routes/{route_id}/plugins \ --data "name=rate-limiting" \ --data "config.second=5" \ --data "config.hour=10000"
# consumer上启用插件$ curl -X POST http://127.0.0.1:8001/plugins \ --data "name=rate-limiting" \ --data "consumer_id={consumer_id}" \ --data "config.second=5" \ --data "config.hour=10000"
复制代码
name
参数,设置为 rate-limiting
表示使用 Rate Limiting 插件。config.second
参数,设置为 1 表示每秒允许 1 次请求。config.limit_by
参数,设置为 ip
表示使用 IP 基础维度的限流。
也可以通过 konga UI 操作添加 rate-limiting 插件请求超过阈值,会被 kong 限流
# 在服务上配置插件curl -X POST http://127.0.0.1:8001/services/{service}/plugins \ --data "name=basic-auth" \ --data "config.hide_credentials=true"
#在路由上配置插件curl -X POST http://127.0.0.1:8001/routes/{route_id}/plugins \ --data "name=basic-auth" \ --data "config.hide_credentials=true"
复制代码
通过 konga UI 为路由添加 basic-auth 插件
创建用户并添加 Basic 凭证
调用 Kong Admin API services/${service}/plugins
,创建 JWT 插件的配置:
curl -X POST http://127.0.0.1:8001/services/tulingmall-product/plugins \ --data "name=jwt"
复制代码
name
参数,设置为 jwt
表示使用 JWT 插件。# 查看插件列表curl -X GET localhost:8001/services/tulingmall-product/plugins
#查看jwt插件curl -X GET localhost:8001/services/tulingmall-product/plugins/jwt
#删除jwt插件curl -X DELETE localhost:8001/services/tulingmall-product/plugins/{jwt.id}
复制代码
通过 konga UI 操作添加jwt
插件
请求被 kong 安全拦截
调用 Kong Admin API consumers
,创建一个 Consumer 消费者:
$ curl -i -X POST http://localhost:8001/consumers/ \ --data "username=fox"
复制代码
调用 Kong Admin API consumers/{username}/{plugin}
,生成该消费者的 JWT 信息:
{username}
路径参数,为 Consumer 的用户名。{plugin}
路径参数,为 Plugin 的插件名。可以指定算法algorithm
,iss
签发者key
,密钥secret
,也可以省略,会自动生成。
$ curl -i -X POST http://localhost:8001/consumers/fox/jwt/ \-d "algorithm=HS256" \-d "key=fox123" \-d "secret=uFLMFeKPPL525ppKrqmUiT2rlvkpLc9u"
复制代码
{ "rsa_public_key":null, "algorithm":"HS256", "id":"3dc4d177-8a7a-4edc-bc88-ee7aa2447fc7", "tags":null, "consumer":{ "id":"8e7fb82d-68ef-4f2b-a30c-613866378525" }, "secret":"uFLMFeKPPL525ppKrqmUiT2rlvkpLc9u", "created_at":1625803149, "key":"fox123"}
复制代码
查看 fox 的 jwt 凭证
curl -X GET localhost:8001/consumers/fox/jwt
复制代码
业务服务器根据kong
生成的jwt
凭证中的algorithm、key(iss)、secret
进行token
的演算和下发。请求鉴权接口
需携带Authorization: Bearer jwt
进行请求。测试可以在https://jwt.io/中通过 Debugger 生成 jwt token
获取到 jwt token 令牌:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJpc3MiOiJmb3gxMjMifQ.hqHGVujYheALxXpEVtgisA5pPTGfQYet0IKadnYPtj8
复制代码
curl http://192.168.65.200:8000/pms/productInfo/42 \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJpc3MiOiJmb3gxMjMifQ.hqHGVujYheALxXpEVtgisA5pPTGfQYet0IKadnYPtj8"
复制代码
# 在服务上启用插件$ curl -X POST http://kong:8001/services/{service}/plugins \ --data "name=ip-restriction" \ --data "config.whitelist=54.13.21.1, 143.1.0.0/24"
# 在路由上启用插件$ curl -X POST http://kong:8001/routes/{route_id}/plugins \ --data "name=ip-restriction" \ --data "config.whitelist=54.13.21.1, 143.1.0.0/24"
复制代码
curl -X POST http://127.0.0.1:8001/routes/ad515a07-bae4-4b54-a927-35bc6c85565b/plugins \ --data "name=ip-restriction" \ --data "config.whitelist=192.168.65.200"
复制代码
当前本机器 IP 地址为: 192.168.65.103
将本机 ip 加入到白名单
领取专属 10元无门槛券
私享最新 技术干货