一、背景
当前微服务网关的技术选型很多。常见的有springcloud系的zuul1,gateway;也可以选择nginx+lua方案;或者直接使用UI集成度较高的Kong。
本文记述了如何使用docker安装kong与konga(一个开源的Kong管理UI项目),以及它们的简单使用和一些注意事项。
二、通过docker安装kong(DB模式)与konga
2.1 通过docker安装kong(DB模式)
官方文档:https://docs.konghq.com/install/docker/
2020/07/03 kong目前的最新版本2.0.4,在做websocket转发时,与tomcat版本9.0.29有冲突,会导致websocket无法正常转发。因此这里我们选择安装kong的一个稍微低一点的版本2.0.0
。
# 如果不指定subnet,创建的network默认使用172.17网段,可能会与实际网段发生冲突
docker network create --subnet=12.10.10.0/24 kong-net
# 拉取postgres:9.6作为kong的数据库
docker run -d --name kong-database \
--network=kong-net \
-p 5432:5432 \
-e "POSTGRES_USER=kong" \
-e "POSTGRES_DB=kong" \
-e "POSTGRES_PASSWORD=kong" \
postgres:9.6
# 拉取kong:2.0.0并生成初期数据
docker run --rm \
--network=kong-net \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_PG_USER=kong" \
-e "KONG_PG_PASSWORD=kong" \
-e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \
kong:2.0.0 kong migrations bootstrap
# 启动kong
docker run -d --name kong \
--network=kong-net \
-e "KONG_DATABASE=postgres" \
-e "KONG_PG_HOST=kong-database" \
-e "KONG_PG_USER=kong" \
-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 127.0.0.1:8001:8001 \
-p 127.0.0.1:8444:8444 \
kong:2.0.0
# 启动后在宿主机访问8000与8001端口
curl http://localhost:8000
curl http://localhost:8001
注意,kong的四个端口作用:
- 8000与8443分别用于对http和https的代理访问;
- 8001与8444分别是http与https的管理API访问端口,因为管理API不宜对外暴露,所以在挂载端口时,明确了
127.0.0.1
,即只有宿主机本地能够访问。
2.2 通过docker安装konga
konga安装直接默认最新版本(目前是0.14.9)。
# 拉取pantsel/konga,并创建数据库konga_db。
# 注意这里直接使用刚刚为了kong创建的PG数据库实例,并使用kong的DB用户,
# 注意这里postgresql连接的写法:
# postgresql://<用户>:<密码>@<PG_Host>:<PG_Port>/<database>
docker run --rm \
--network=kong-net \
pantsel/konga -c prepare -a postgres -u postgresql://kong:kong@kong-database:5432/konga_db
# 启动konga
docker run -d -p 1337:1337 \
--network=kong-net \
-e "DB_ADAPTER=postgres" \
-e "DB_HOST=kong-database" \
-e "DB_USER=kong" \
-e "DB_PASSWORD=kong" \
-e "DB_DATABASE=konga_db" \
-e "KONGA_HOOK_TIMEOUT=120000" \
-e "NODE_ENV=production" \
--name konga \
pantsel/konga
三、首次访问konga并配置kong管理API连接
观察docker容器状况,确认kong-database
、kong
、konga
三个容器全部成功启动后,访问地址:http://localhost:1337
。
首次访问会让你创建konga的管理员账户,然后登录,然后创建到kong管理API的连接,过程如下:
- 创建gonga管理员账户
- 用管理员账户登录
- 创建到kong管理API的连接(连接地址:
http://kong:8001/
) - 激活该连接
注意上面第三步,创建到kong管理API的连接时,因为前面启动kong时,8001端口只挂载在12.0.0.1:8001
上,因此只有宿主机自己可以访问。这里在konga容器内访问kong时,就必须通过网络kong-net
中的容器ip或hostname访问。因此这里填写的是kong容器的name:kong
,而不是宿主机IP。
四、添加路由规则
此时konga的界面还是比较简陋的,功能也不多。dashbord只能看到一些总体的统计信息,看不到具体每个目标服务的访问量。
如果需要添加其他功能,需要通过PLUGINS去一个一个添加,具体尚未研究。
但动态添加路由规则是完全没有问题的。这里主要介绍如何添加路由规则。
kong添加路由规则主要分为两步:
- 添加要访问的目标服务。
- 在已经添加的Sevice里添加网关接收到的请求的过滤规则,即把什么样的请求转发给该Service。
4.1 添加目标服务
通过左侧导航菜单SERVICES
,添加目标服务ADD NEW SERVICE
,一般配置项目如下:
- Name: 通常写目标服务名。
- Protocol: http 或 https
- Host: 目标服务的Host
- Port: 目标服务的端口
- Path: 目标服务访问根路径,没有特殊情况就填写
/
注意Path不要空着,没有指定Path就填上/
表示服务根目录。
其他项目一般保持默认即可。
4.2 为目标服务添加路由
通过左侧导航菜单SERVICES
,点击一个目标服务,选择它的Routes
,并点击ADD ROUTE
,配置如下:
路由一般配置项:
- Name : 路由名称。
- 其他 : 略
路由过滤条件配置项:
- Hosts : 网关所在服务器有多个域名时,可以根据请求的域名做过滤条件;一般不填。
- Paths : 一般都是在Paths做过滤条件。Kong通过PCRE(与Perl兼容的正则表达式)支持paths字段的正则表达式模式匹配。因此可以同时使用path前缀和正则表达式匹配路由。注意每写一个Path过滤条件就要回车(一定要回车,不然konga认为你没有输入。。。),多个Path过滤条件就写多个。
- Methods : 将HTTP methods作为过滤条件,填入
POST
,GET
等。 - Headers : 需要通过Header信息作为过滤条件时填写。直接将header信息的
属性:值
填入即可,注意回车。例如:Connection: keep-alive
。 - Protocols : 将协议作为过滤条件,http或https。
- 其他 : 略
注意:
- Hosts,Paths,Methods三者最少需要配置一个。
- 大部分情况下,我们都是根据Path来做转发的过滤条件的,因此不同目标系统如果某些资源访问Path相同的话,会导致不同目标服务的路由规则冲突。
关于Path冲突,建议如下:
- 尽量确保不同的目标服务具有各自统一的资源访问根目录。即每个目标服务都有自己统一且唯一的Path前缀。如,某个目标服务的Path都是
/service1/*
,静态资源用/service1/static/*
,API用/service1/api/*
等等。- 没有统一访问根目录的目标服务,尽量保证各自的路径满足不同的正则表达式。比如Path的中间某一层统一为能识别具体服务的字符串。如,某个目标服务的Path都满足
/*/service2/*
,静态资源用/static/service2/*
,API用/api/service2/*
等等。- 前面两点都不能满足的话,考虑加入其他过滤条件(Hosts,Headers等),例如,网关有多个域名,当请求用域名1访问时,路由到目标服务1,用域名2访问时,路由到目标服务2。
路由附加操作配置项:
- Strip Path : 满足条件的请求在转发给目标服务时,是否将Paths中匹配的部分从访问路径中去掉。
- 其他 : 略
五、关于websocket的转发
kong是天生支持websocket转发的,关于这一点,可以参考官网的说明:https://docs.konghq.com/2.0.x/proxy/#proxy-websocket-traffic
但当kong位于客户端与服务端之间时,kong的某些版本与服务器的版本可能会有冲突,导致websocket转发发生异常。
例如,目前kong的最新版本(2.0.4)作为网关,如果目标服务是tomcat的9.0.29版本,那么会发生以下现象:
- 客户端在试图连接websocket时,发生
Error during WebSocket handshake: 'Upgrade' header is missing
错误。 - 位于kong后面的服务端tomcat能够接收到转发的websocket连接请求并成功建立连接,但紧接着就会发生
java.io.EOFException
异常,导致连接被关闭。
具体原因在kong的issue #5714 (https://github.com/Kong/kong/issues/5714
) 中有讨论,该issue已被关闭但实际上问题并未解决。。。倒是其中一个回答提到,如果将kong版本回退到2.0.0
则该问题不会发生。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。