Kong是Mashape開源的高性能高可用API網關和API服務管理層。自2015年在github開源後,普遍受到關注。它基於OpenResty,進行API管理,並提供了插件實現API的AOP。Kong在Mashape 管理了超過15,000 個API,爲200,000開發者提供了每個月數十億的請求支持。html
在微服務架構之下,服務被拆的很是零散,下降了耦合度的同時也給服務的統一管理增長了難度。如上圖左所示,在舊的服務治理體系之下,鑑權,限流,日誌,監控等通用功能須要在每一個服務中單獨實現,這使得系統維護者沒有一個全局的視圖來統一管理這些功能。API 網關致力於解決的問題即是爲微服務納管這些通用的功能,在此基礎上提升系統的可擴展性。如右圖所示,微服務搭配上 API 網關,可使得服務自己更專一於本身的領域,很好地對服務調用者和服務提供者作了隔離。mysql
Kong 的插件機制是其高可擴展性的根源,Kong 能夠很方便地爲路由和服務提供各類插件,網關所須要的基本特性,Kong 都如數支持:nginx
雲原生: 與平臺無關,Kong能夠從裸機運行到Kubernetes
動態路由: Kong 的背後是 OpenResty+Lua,因此從 OpenResty 繼承了動態路由的特性
熔斷
健康檢查
日誌: 能夠記錄經過 Kong 的 HTTP,TCP,UDP 請求和響應。
鑑權: 權限控制,IP 黑白名單,一樣是 OpenResty 的特性
SSL: Setup a Specific SSL Certificate for an underlying service or API.
監控: Kong 提供了實時監控插件
認證: 如數支持 HMAC, JWT, Basic, OAuth2.0 等經常使用協議
限流
REST API: 經過 Rest API 進行配置管理,從繁瑣的配置文件中解放
可用性: 自然支持分佈式
高性能: 背靠非阻塞通訊的 nginx,性能自不用說
插件機制: 提供衆多開箱即用的插件,且有易於擴展的自定義插件接口,用戶可使用 Lua 自行開發插件git
Kong支持多種安裝方式,這裏使用Docker安裝,比較簡單。github
1.建立一個Docker網絡web
首先,咱們你須要建立一個自定義網絡,這樣的話多個容器之間可以相互發現和通信,網絡名稱能夠隨便命名。sql
docker network create kong-net
2.啓動數據庫mongodb
你可使用 PostgreSQL 或 Cassandra 做爲你的存儲。這裏選擇PostgreSQL做爲Kong的數據庫。docker
$ docker run -d --name kong-database \ --network=kong-net \ -p 5432:5432 \ -e "POSTGRES_USER=kong" \ -e "POSTGRES_DB=kong" \ postgres:9.6
若是你但願使用Cassandra。數據庫
$ docker run -d --name kong-database \ --network=kong-net \ -p 9042:9042 \
3.準備數據庫
如今讓咱們經過啓動一個短暫的Kong容器來準備咱們的數據庫,這個容器將運行適當的遷移並死掉!
$ docker run --rm \ --network=kong-net \ -e "KONG_DATABASE=postgres" \ -e "KONG_PG_HOST=kong-database" \ -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \ kong:latest kong migrations bootstrap
注意:上面的例子中,若是你使用的是 Cassandra,那麼你應該更新 KONG_DATABASE 環境變量的值爲 cassandra 。
4.啓動Kong
當遷移已經運行而且數據庫準備就緒後,啓動一個Kong容器,它將鏈接到你的數據庫容器。
$ docker run -d --name kong \ --network=kong-net \ -e "KONG_DATABASE=postgres" \ -e "KONG_PG_HOST=kong-database" \ -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
5.測試Kong!
Kong’s admin API is exposed on port 8001 and the gateway on port 8000
$ curl -i http://localhost:8001/ $ curl -i http://localhost:8000/
當前KONG的社區版是沒有dashboard的,可是付費的企業版是有帶的,而且還有一些企業版才能使用的插件以及升級後的企業版插件。因此對於使用社區版的用戶而言,排除本身去擼一個dashboard的這種選擇,第三方開源的dashboard無疑是首選。當前GitHub上還在更新維護的dashboard有三個,分別是kong-dashboard,kongdash 和 konga。
說道Kong的管理GUI,網上說的比較多的都是kong-dashboard,但目前最新版(v3.6.0)彷佛並未支持最新版本的Kong。而目前在github能找到star比較多的就是konga了。konga不只支持了Kong的最新版本(service和route的拆分新特性)同時支持管理員的權限控制和多個Kong鏈接池的管理。Konga因爲自帶了用戶權限控制和Kong鏈接池管理,因此須要一些數據持久化處理。默認支持的數據庫有mongodb、postgres、mysql。這裏咱們選擇的是PostgresSQL,緣由是KONG鏈接的數據庫也是PGSQL,這樣能夠減小數據庫的部署。
1.和之前同樣,咱們須要經過啓動一個短暫的容器來準備Konga的數據庫。
$ docker run --rm \ --network=kong-net \ pantsel/konga -c prepare -a postgres -u postgresql://kong@kong-database:5432/konga_db
當遷移運行了,咱們能夠啓動 Konga
$ docker run -p 1337:1337 \ --network=kong-net \ -e "DB_ADAPTER=postgres" \ -e "DB_HOST=kong-database" \ -e "DB_USER=kong" \ -e "DB_DATABASE=konga_db" \ -e "KONGA_HOOK_TIMEOUT=120000" \ -e "NODE_ENV=production" \ --name konga \ pantsel/konga
After a while, Konga will be available at:
http://<your-servers-public-ip-or-host>:1337
你須要註冊一個管理員帳號
登陸成功後,你將看到這個頁面:
此時,您須要手動建立與Kong的管理API的鏈接。
若是您打開鏈接(connections)頁面,您會注意到與先前建立的Kong實例的鏈接已經存在但還沒有激活。
點擊激活按鈕。若是一切設置正確,Konga將鏈接到Kong,界面將充滿各類酷感。
簡要介紹一些核心的概念
Dashboard
儀表板顯示有關您當前鏈接的Kong實例,基礎數據庫和可用插件的基本信息。更多詳細信息可在INFO頁面中找到。
Snapshots
快照功能容許您輕鬆地跨節點備份,恢復和移動Kong配置。您還能夠安排Kong實例的自動快照。
Settings
設置頁面提供了一種配置Konga併爲用戶賬戶設置基本ACL的簡單方法。請記住,用戶權限是全局設置的,並將用戶賬戶稱爲實體。尚不支持單個用戶ACL。
咱們將使用優秀的在線虛假API(由typicode提供的)進行測試和原型設計。
導航到服務頁面並添加新服務。填寫表格以下:
注意:url參數是一個簡化參數,用於一次性添加protocol,host,port和path。另外不要把Services看成後端的具體API,要把它看成一個大的服務,該服務下面有多個API(endpoint or route)。因此建立服務的時候填上該服務的域名就好了。固然也能夠是一個url(帶Path的),這樣每一個API(route)會路由到該path上。
提交後,服務被建立,詳情以下:
The jsonplaceholder API 提供如下資源(假設咱們有這些API):
posts
comments
albums
photos
todos
users
咱們須要爲這些資源建立路由。單擊json-placeholder服務,選擇routes選項卡並添加新路由。
這裏的 Path 就是具體業務API的路徑(endpoint)。Hosts不設置會默認採用Services裏的Host,可是一旦設置了,客戶端請求該route的時候必須帶上設置的host,且必須一致。、
若是Strip path設置爲YES,這裏的 Path 能夠加一個前綴,如:/passport/users,但最終會映射到後端真實的API /users。Kong轉發到後端服務的時候會把前綴/passport部分去掉。客戶端調用API必須和Routes裏的Path一致才行(/passport/users),不然會獲得404,沒法匹配。用戶的請求是先匹配route,而後轉發到service。
好比:
If your route has /my-service in the paths property, then
/my-service/foo will be routed upstream as /foo,
/my-service/bar will be routed upstream as /bar.
I’d recommend you to go through the definition of the Route Object in Kong to gain a better understanding.
試試看
$ curl -i http://localhost:8000/users
一樣,建立響應POST,PUT,PATCH和DELETE請求的第二個路由。
繼續建立一個新用戶並測試它:
$ curl -X POST \ -H "Content-Type: application/json" \ -d '{"name":"JohnDoe","username":"jdoe"}' \ http://localhost:8000/users
到目前爲止,咱們成功部署了Kong&Konga並設法經過咱們的網關訪問jsonplaceholder API。
接受客戶端流量的端口,proxy部分
admin API 端口 admin部分
咱們來看一個典型的Nginx的配置對應在Kong上是怎麼樣的,下面是一個典型的Nginx配置
upstream passportUpstream { server localhost:8080 weight=100; } server { listen 80; location /hello { proxy_pass http://passportUpstream; } }
下面咱們來看看其對應Kong中的配置
# 配置 upstream curl -X POST http://localhost:8001/upstreams --data "name=passportUpstream" # 配置 target curl -X POST http://localhost:8001/upstreams/passport/targets --data "target=localhost:8080" --data "weight=100" # 配置 service curl -X POST http://localhost:8001/services --data "name=getUserInfo" --data "host=passportUpstream" # 配置 route curl -X POST http://localhost:8001/routes --data "paths[]=/user" --data "service.id=8695cc65-16c1-43b1-95a1-5d30d0a50409" curl -X POST http://localhost:8001/routes --data "hosts[]=*.example.com,test.com,*.abc.com" --data "service.id=8695cc65-16c1-43b1-95a1-5d30d0a50409"
這一切配置都是經過其Http Restful API 來動態實現的,無需咱們在手動的 reload Nginx.conf 。開發的同窗看到這是否是感受到很幸福了。
在上述的配置中涉及到了幾個概念:upstrean、target、service、route等概念,它們是Kong的幾個核心概念,也是咱們在使用Kong Api 時常常打交道的,下面咱們就其幾個核心概念作一下簡單的說明。
Upstream
Upstream 對象表示虛擬主機名,可用於經過多個服務(目標)對傳入請求進行負載均衡。例如:service.v1.xyz 爲Service對象命名的上游host是service.v1.xyz對此服務的請求將代理到上游定義的目標。
Target
目標IP地址/主機名,其端口表示後端服務的實例。每一個上游均可以有多個target,而且能夠動態添加Target。
因爲上游維護Target的更改歷史記錄,所以沒法刪除或者修改Target。要禁用目標,請發佈一個新的Targer weight=0,或者使用DELETE來完成相同的操做。
Service
顧名思義,服務實體是每一個上游服務的抽象。服務的示例是數據轉換微服務,計費API等。
服務的主要屬性是它的URL(其中,Kong應該代理流量),其能夠被設置爲單個串或經過指定其protocol, host,port和path。
服務與路由相關聯(服務能夠有許多與之關聯的路由)。路由是Kong的入口點,並定義匹配客戶端請求的規則。一旦匹配路由,Kong就會將請求代理到其關聯的服務。
Route
路由實體定義規則以匹配客戶端的請求。每一個Route與一個Service相關聯,一個服務可能有多個與之關聯的路由。與給定路由匹配的每一個請求都將代理到其關聯的Service上。能夠配置的字段有
Service 和 Route 的組合(以及它們之間的關注點分離)提供了一種強大的路由機制,經過它能夠在Kong中定義細粒度的入口點,從而使基礎架構路由到不一樣上游服務。
Consumer
Consumer 對象表示服務的使用者或者用戶。您能夠依靠Kong做爲主數據庫存儲,也能夠將使用者列表與數據庫映射,以保持Kong與現有的主數據存儲之間的一致性。
Plugin
插件實體表示將在HTTP請求/響應生命週期期間執行的插件配置。它是如何爲在Kong後面運行的服務添加功能的,例如身份驗證或速率限制。
將插件配置添加到服務時,客戶端向該服務發出的每一個請求都將運行所述插件。若是某個特定消費者須要將插件調整爲不一樣的值,您能夠經過建立一個單獨的插件實例,經過service和consumer字段指定服務和消費者 。
對應關係
Upstream : target -> 1:n
Service:Upstream -> 1:1 or 1:0 (Service 能夠直接指向具體的Target,至關於不作負載均衡)
Service : Route -> 1:n
Note: Client請求的流量經過Route指向與之相關的Service,若是配置插件的話就會做用插件,Service接到流量後給相應的Upstream的服務上面。
經過向Admin API發送HTTP請求來向Kong添加服務:
curl -i -X POST http://localhost:8001/services/ \ -d 'name=foo-service' \ -d 'url=http://foo-service.com' HTTP/1.1 201 Created ... { "connect_timeout": 60000, "created_at": 1515537771, "host": "foo-service.com", "id": "d54da06c-d69f-4910-8896-915c63c270cd", "name": "foo-service", "path": "/", "port": 80, "protocol": "http", "read_timeout": 60000, "retries": 5, "updated_at": 1515537771, "write_timeout": 60000 }
這裏註冊一個名爲「foo-service」的服務,該服務指向http://foo-service.com(上游)。
注意:url參數是一個簡化參數,用於一次性添加protocol,host,port和path。
更多見官方指南
如今讓咱們討論Kong如何匹配針對路由的已配置host,path和methods屬性(或字段)的請求。請注意,全部這三個字段都是可選的,但必須至少指定其中一個。
對於匹配路線的請求:
這裏思考一個問題,Kong route 中的host的做用是什麼?有什麼意義?哪些場景會用到設置多個host呢?
這是官方的解釋:
Routing a request based on its Host header is the most straightforward way to proxy traffic through Kong, as this is the intended usage of the HTTP Host header. Kong makes it easy to do so via the hosts field of the API entity.
顯然官方對host的說明,沒有回答上面的問題,下面看下網絡上對host的解釋:
咱們知道Http請求頭信息裏面會帶有一個Host字段,不少人不是很清楚這個字段具體的做用或者用法,包括我被不少人問過也曾經有些迷茫,這裏具體掃盲下。
Host 是HTTP 1.1 協議中新增的一個請求頭,主要用來實現虛擬主機技術。咱們知道一個IP地址能夠對應多個域名,好比假設我有這麼幾個域名 www.qiniu.com,www.taobao.com和www.jd.com 而後在域名提供商那經過A記錄或者CNAME記錄的方式最終都和個人虛擬機服務器IP 111.111.111.111關聯起來,那麼我經過任何一個域名去訪問最終解析到的都是IP 111.111.111.111。
可是仍是沒有提到Host的概念,其實能夠這樣看,咱們的那臺虛擬機111.111.111.111上面實際上是能夠放很不少網站的(否則若是隻能放一個網站的話就太不合理了,虛擬機那麼多資源都浪費了),咱們能夠把www.qiniu.com,www.taobao.com 和 www.jd.com 這些網站都假設那臺虛擬機上面,可是這樣會有一個問題,咱們每次訪問這些域名其實都是解析到服務器IP 111.111.111.111,我怎麼來區分每次根據域名顯示出不一樣的網站的內容呢,其實這就要用到請求頭中Host的概念了,每一個Host能夠看作是我在服務器111.111.111.111上面的一個站點,每次我用那些域名訪問的時候都是會解析同一個虛擬機沒錯,可是我經過不一樣的Host能夠區分出我是訪問這個虛擬機上的哪一個站點。
咱們再來看幾個例子就完全明白了。考慮以下配置的路由:
{ "hosts": ["example.com", "foo-service.com"], "paths": ["/foo", "/bar"], "methods": ["GET"] }
下面咱們假設請求時不帶Host
$ curl -v -H "Host: ''" -i http://localhost:8000/users/1
注意觀察請求頭,* Connected to localhost (127.0.0.1) port 8000 (#0);客戶端和kong創建了tcp鏈接,可是host是空的,因此Kong匹配不到上面的route。
$ curl -v -H "Host: ''" -i http://localhost:8000/users/1 * Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8000 (#0) > GET /users/1 HTTP/1.1 > Host: '' > User-Agent: curl/7.54.0 > Accept: */* > < HTTP/1.1 404 Not Found HTTP/1.1 404 Not Found < Date: Thu, 19 Sep 2019 09:49:49 GMT Date: Thu, 19 Sep 2019 09:49:49 GMT < Content-Type: application/json; charset=utf-8 Content-Type: application/json; charset=utf-8 < Connection: keep-alive Connection: keep-alive < Content-Length: 48 Content-Length: 48 < Server: kong/1.3.0 Server: kong/1.3.0 < * Connection #0 to host localhost left intact {"message":"no Route matched with those values"}
讓咱們看下設置了正確Host的請求:
curl -v -H "Host: example.com" -i http://localhost:8000/users/1
此次kong匹配到了route,因此拿到了數據。
$ curl -v -H "Host: example.com" -i http://localhost:8000/users/1 * Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8000 (#0) > GET /users/1 HTTP/1.1 > Host: example.com > User-Agent: curl/7.54.0 > Accept: */* > < HTTP/1.1 200 OK HTTP/1.1 200 OK < Content-Type: application/json; charset=utf-8 Content-Type: application/json; charset=utf-8 < Content-Length: 509 Content-Length: 509 < Connection: keep-alive Connection: keep-alive < Date: Thu, 19 Sep 2019 10:13:05 GMT Date: Thu, 19 Sep 2019 10:13:05 GMT < Set-Cookie: __cfduid=d20158b06862bc2fa86521fef7e966e771568887985; expires=Fri, 18-Sep-20 10:13:05 GMT; path=/; domain=.typicode.com; HttpOnly Set-Cookie: __cfduid=d20158b06862bc2fa86521fef7e966e771568887985; expires=Fri, 18-Sep-20 10:13:05 GMT; path=/; domain=.typicode.com; HttpOnly < X-Powered-By: Express X-Powered-By: Express < Vary: Origin, Accept-Encoding Vary: Origin, Accept-Encoding < Access-Control-Allow-Credentials: true Access-Control-Allow-Credentials: true < Cache-Control: public, max-age=14400 Cache-Control: public, max-age=14400 < Pragma: no-cache Pragma: no-cache < Expires: Thu, 19 Sep 2019 14:13:05 GMT Expires: Thu, 19 Sep 2019 14:13:05 GMT < X-Content-Type-Options: nosniff X-Content-Type-Options: nosniff < Etag: W/"1fd-+2Y3G3w049iSZtw5t1mzSnunngE" Etag: W/"1fd-+2Y3G3w049iSZtw5t1mzSnunngE" < Via: kong/1.3.0 Via: kong/1.3.0 < CF-Cache-Status: MISS CF-Cache-Status: MISS < Accept-Ranges: bytes Accept-Ranges: bytes < Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct" Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct" < Server: cloudflare Server: cloudflare < CF-RAY: 518ac8f28e0bd362-LAX CF-RAY: 518ac8f28e0bd362-LAX < X-Kong-Upstream-Latency: 981 X-Kong-Upstream-Latency: 981 < X-Kong-Proxy-Latency: 0 X-Kong-Proxy-Latency: 0 < { "id": 1, "name": "Leanne Graham", "username": "Bret", "email": "Sincere@april.biz", "address": { "street": "Kulas Light", "suite": "Apt. 556", "city": "Gwenborough", "zipcode": "92998-3874", "geo": { "lat": "-37.3159", "lng": "81.1496" } }, "phone": "1-770-736-8031 x56442", "website": "hildegard.org", "company": { "name": "Romaguera-Crona", "catchPhrase": "Multi-layered client-server neural-net", "bs": "harness real-time e-markets" } * Connection #0 to host localhost left intact }
因此Host的做用是上面,如今徹底搞清楚了吧。
https://docs.konghq.com/insta...
https://docs.konghq.com/0.14....
https://pantsel.github.io/konga/
https://ajaysreedhar.github.i...
https://discuss.konghq.com/t/...
https://zhuanlan.zhihu.com/p/...
https://www.lijiaocn.com/%E9%...
https://keyla.vip/kong/route/
https://www.li-rui.top/2019/0...
https://www.linzepeng.com/201...
https://medium.com/@tselentis...
https://www.cnkirito.moe/kong...
https://www.li-rui.top/2019/0...
https://www.qingtingip.com/h_...
http://www.102no.com/archives...