本文共 8193 字,大约阅读时间需要 27 分钟。
1. 创建kong-net网络
$ docker network create kong-net
2. 启动PostgreSQL容器
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:11.7
3. 运行临时Kong容器迁移数据库
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
4. 启动Kong容器
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 80:8000 \-p 443:8443 \-p 8001:8001 \-p 8444:8444 \kong:latest
5. 验证
curl -s -i http://localhost:8001/ | jq
6. dashboard
# 迁移konga数据表到pgsqldocker run --name konga --rm \--network=kong-net \pantsel/konga -c prepare -a postgres -u postgresql://kong:kong@kong-database:5432/kong# 启动kongadocker run -p 1337:1337 -d \--network=kong-net \-e "DB_ADAPTER=postgres" \-e "DB_HOST=kong-database" \-e "DB_USER=kong" \-e "DB_PASSWORD=kong" \-e "DB_DATABASE=kong" \-e "KONGA_HOOK_TIMEOUT=120000" \-e "DB_PG_SCHEMA=public" \-e "NODE_ENV=production" \--name konga \pantsel/konga
upstream: 是对上游服务器的抽象;
target: 代表了一个物理服务,是ip+port的抽象;
service: 是抽象层面的服务,它也可以直接映射到一个物理服务(host 指向 ip + port),也可以指向一个upstream来做到负载均衡;
route: 是路由的抽象,它负责将实际的request映射到service
默认情况下,Kong监听的端口是:8000、8001、8443、8444
8444:通过此端口,管理者可以对HTTP请求进行监控
其中8000/8443分别是用来监听来自客户端的Http和Https请求,等价于Nginx默认的80和443端口,而8001端口是默认的管理端口,可以通过HTTP Restful API来动态管理Kong的配置
一个典型的Nginx的配置
upstream www { server localhost:3001 weight=100;}server { server_name www.flask.com; listen 80; location / { proxy_pass http://www; }}
如上简单的Nginx配置,可以转换为如下的Http请求
对应的Kong配置
- 配置upstream
curl -X POST http://10.0.0.10:8001/upstreams --data "name=www-ups"
- 配置target
curl -X POST http://10.0.0.10:8001/upstreams/www-ups/targets --data "target=10.0.0.10:3001" --data "weight=100"
- 配置service
curl -X POST http://10.0.0.10:8001/services --data "name=www-svc" --data "host=www-ups"
- 配置route
curl -X POST http://10.0.0.10:8001/routes \--data "name=www-route" \--data "hosts[]=www.flask.com" \--data "paths[]=/" \--data "service.id=741dc49d-0a96-4e1d-90c3-d1948cba1175"
- 访问www-route(uri)
curl -s -X GET http://www.flask.com# --url 指定kong proxy服务器的ip:port, 默认为8000端口,这里映射到虚拟机的80端口curl -s -X GET --url 'http://10.0.0.10:80' --header 'Host: www.flask.com'
这一切都是动态的,无需手动reload nginx.conf
为Kong新增路由信息时涉及到了upstream,target,service,route等概念,便是Kong最核心的四个对象.
www-svc服务添加5次/分的限流
curl -X POST http://10.0.0.10:8001/services/www-svc/plugins \--data "name=rate-limiting" \--data "config.minute=5"
www-svc服务添加jwt插件
curl -X POST http://10.0.0.10:8001/services/www-svc/plugins \--data "name=jwt"
代理缓存插件
curl -i -X POST http://10.0.0.10:8001/plugins \--data name=proxy-cache \--data config.content_type="application/json" \--data config.cache_ttl=30 \--data config.strategy=memory
验证代理缓存
# 注意响应的内容格式必须是json格式的才有效果curl -i -X GET --url 'http://10.0.0.10:80' --header 'Host: demo1.flask.com'X-Cache-Status: MissX-Cache-Status: Hit
设置秘钥认证插件
curl -X POST http://10.0.0.10:8001/routes/demo1/plugins \--data name=key-authcurl -i -X GET --url 'http://10.0.0.10:80' --header 'Host: demo1.flask.com'# 返回{"message":"No API key found in request"}创建消费者curl -i -X POST -d "username=consumer&custom_id=consumer" http://10.0.0.10:8001/consumers/创建消费者秘钥curl -i -X POST http://10.0.0.10:8001/consumers/consumer/key-auth -d 'key=apikey'验证秘钥curl -i -X GET --url 'http://10.0.0.10:80' --header 'Host: demo1.flask.com' -H 'apikey:apikey'禁用插件curl -s -X GET http://10.0.0.10:8001/routes/demo1/plugins | jq '.data[].id'curl -X PATCH http://10.0.0.10:8001/routes/demo1/plugins/81554ece-ef5b-42c5-91c4-9e0bf9e29920 \ --data "enabled=false"
同理,插件也可以安装在route之上
获取www-svc的所有路由名称和routeId,带上cookie和 authorizationcurl -s -b "io=rCMjxICHRJ6zv2PTAAAF" -H 'authorization: Bearer eyJhbGciOiJIUzI1NiJ9.MQ.Lu-KcR4aCeuT9hi1K474zV3s4VaopLDCcf4nZvH6DQo' http://10.0.0.10:1337/kong/services/741dc49d-0a96-4e1d-90c3-d1948cba1175/routes |jq '.data[].name, .data[].id'curl -X POST http://10.0.0.10:8001/routes/{routeId}/plugins \--data "name=jwt"curl -X POST http://10.0.0.10:8001/routes/c3ea95c1-7a56-4fad-847e-f77de918bf26/plugins \--data "name=rate-limiting" \--data "config.second=5"
Base Auth访问
curl -s -H 'Authorization: Basic dGVzdDp0ZXN0' --url 'http://10.0.0.10:80' --header 'Host: hello.flask.com'
#添加servicescurl -i -X POST \--url http://10.0.0.10:8001/services/ \--data 'name=svc-demo1' \--data 'url=http://httpbin.org/ip'#添加routescurl -i -X POST \--url http://10.0.0.10:8001/services/svc-demo1/routes \--data 'name=demo1' \--data 'hosts[]=demo1.flask.com'#访问测试curl -i -X GET \--url http://10.0.0.10:80/ \--header 'Host: demo1.flask.com'
curl -s -X POST \--url http://localhost:8001/services/ \--data 'name=book' \--data 'url=http://10.0.0.10:3002/v1/books' | jq
# paths[]的值必须与book服务中的/v1/books一致,使book服务暴露出来以供用户访问,book服务没必要添加多个路由curl -s -X POST \--url http://localhost:8001/services/book/routes \--data 'name=v1' \--data 'hosts[]=book.com' \--data 'paths[]=/v1/books' | jq
curl -s -X GET \--url http://localhost:80/v1/books \--header 'Host: book.com' | jq# 获取book服务的描述信息curl -s http://localhost:8001/services/book | jq# 获取book服务使用的插件curl -s http://localhost:8001/services/book/plugins | jq
curl -s -X POST \--url http://localhost:8001/services/book/plugins \--data "name=oauth2" \--data "config.scopes=email,phone" \--data "config.mandatory_scope=true" \--data "config.enable_implicit_grant=true" | jq# 获取oauth2插件的provision_key,待会发请求需要curl -s http://localhost:8001/services/book/plugins | jq '.data[].config.provision_key' | sed 's/"//g'provision_key: SBUm1zCs5ropHZcCL5iUwoIz2bQW3ZWG
# custom_id参数可以省略,此参数是一个自定义的唯一标识,它作用是把消费者老王映射到另外一个数据库上curl -s -X POST \--url http://localhost:8001/consumers/ \--data "username=laowang" | jq
# redirect_uri参数定义发送code和state的回调地址参数{client_id}和{client_secret}可自定义,省略时由系统随机生成curl -s -X POST \--url http://localhost:8001/consumers/laowang/oauth2/ \--data "name=Book App" \--data "redirect_uris=http://getkong.org" | jq
# 获取 laowang 的client_idcurl -s http://localhost:8001/consumers/laowang | jq '.id'client_id: dfdd8230-ce2e-4378-b42a-de73ae846ada# 记录下消费者老王下的OAuth2的client_secret和client_idcurl -s -X GET \--url http://localhost:8001/oauth2 \--data "client_id=dfdd8230-ce2e-4378-b42a-de73ae846ada" | jq # laowang的oauth2信息client_secret: HnBL9tbsARkS6wUu5cpFsSgfhA3tGJ85client_id: 3mYuLCNoCrY6hnoDjb7Bc3LZcmGkl6iU
# 通过Kong的proxy端口暴露出来的服务地址读一条书籍记录,实际上是通过Kong在转发我的请求,不管是读1条记录还读所有书籍记录,我们都无权获得数据curl -s -X GET \--url http://localhost:80/v1/books \--header 'Host: book.com' | jq#响应{ "error_description": "The access token is missing", "error": "invalid_request"}
# 所有步骤在浏览器中完成,简化模式下令牌对访问者是可见的,且客户端不需要认证。客户端将发送由参数{client_id},{response_type},{scope},{provision_key},{authenticated_userid},{state}构成的POST请求直接获得访问令牌{state}客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值{scope}表示申请的权限范围{authenticated_userid}已授予权限的终端登录用户useridcurl -s -X POST \--url https://localhost:443/v1/books/oauth2/authorize \--header 'Host: book.com' \--data "client_id=3mYuLCNoCrY6hnoDjb7Bc3LZcmGkl6iU" \ #laowang的oauth2的client_id--data "response_type=token" \--data "scope=email,phone" \--data "provision_key=SBUm1zCs5ropHZcCL5iUwoIz2bQW3ZWG" \--data "authenticated_userid=1206" \--data "state=xyz" --insecure | jq# 响应{ "redirect_uri": "http://getkong.org#access_token=a3z6QvuqdhMgz6G9RrAmLqcfCY85s8fK&expires_in=7200&state=xyz&token_type=bearer"}
curl -s -X GET \--url https://localhost:443/v1/books \--header "Authorization: Bearer a3z6QvuqdhMgz6G9RrAmLqcfCY85s8fK" \--header 'Host: book.com' --insecure | jq
转载地址:http://pmpub.baihongyu.com/