這裏提到的網關特指API網關。API網關是在微服務架構的演進過程當中產生的,其核心功能是聚合後端服務,爲客戶端調用提供統一的門戶。因爲網關的集中式管理,在其上又衍生了限流、負載、路由管理、安全防禦等新的需求和功能。基於應用系統現狀,咱們將網關進一步的細分爲帶有業務邏輯的業務網關和專一於服務聚合、路由的中臺網關。具體來講,業務網關通常是指某一個業務系統的網關,其除了聚合本系統的後端服務以外,還會額外承擔一些業務邏輯,好比通用的用戶鑑權、基於業務的路由規則等。中臺網關,是跨系統的、是將已有的平臺能力抽象、聚合,統一包裝成API服務,以便各平臺、業務複用;中臺網關關注的重點是服務的路由、抽象,提供基本的身份認證、限流等功能便可,不會嵌入具體的業務邏輯。注意這裏的身份認證和業務網關裏的是不同的,業務網關身份認證通常是具體的終端用戶,中臺網關裏的身份認證是對調用方的識別、鑑權,不涉及具體終端用戶。
前端
目前比較流行的API網關主要分爲三類:nginx
一、 基於NGINX的反向代理git
二、 基於網絡編程框架(netty、socket)自開發github
三、 基於組件的API網關框架,主要有:spring cloud gateway、zuul一、zuul2web
基於網絡編程框架的自開發不在咱們考慮範圍內,主要緣由有:自開發週期長,未通過實戰驗證可靠性須要長時間的磨合,並且自開發性能不會比已有框架表現的更好。所以咱們不考慮此類狀況。下面咱們將分析1和3兩種狀況。spring
nginx與spring cloud gateway、zuul對比docker
nginx由內核和模塊組成,內核的設計很是微小和簡潔,完成的工做也很是簡單,僅僅經過查找配置文件與客戶端請求進行URL匹配,而後啓動不一樣的模塊去完成相應的工做。下圖反映了HTTP請求處理的常規流程:
數據庫
spring cloud gateway是在spring boot基礎上構建的,用於快速構建分佈式系統的通用模式的工具集。其核心也是基於filter的,能夠實現相似於zuul的特性功能,可是使用spring cloud 開發的應用程序很是適合在Docker或者Paas上部署。
編程
zuul是Netflix開源的微服務網關組件,它能夠和Euraka、Ribbon、Hystrix等組件配合使用。其核心是一系列的過濾器,經過這些過濾器咱們能夠實現身份認證、審查、監控、動態路由、壓力測試、負載分配、靜態影響處理、多區域彈性等。
json
不難看出三者在處理請求的思想上是一致的,都是基於filter作邏輯嵌入和處理。
產品 | 模型 | 優點 | 劣勢 |
---|---|---|---|
nginx | 基於進程,採用epoll_wait、select這樣的I/O多路複用模型。採用了異步非阻塞的方式處理請求,理論上是能夠同時處理成千上萬個請求。 | 內核小巧,自身佔用資源少,久經高併發考驗,產品穩定、性能最好。 | 只有基本功能配置,額外的功能須要自開發插件,插件語言與通常企業開發人員差別較大,學習成本較高。 |
spring cloud gatway | spring本身的gateway,基於Spring Boot2.x響應式的、非阻塞的API,支持WebSocket等長鏈接,和Spring框架緊密集成;總體模型與Nginx相似 | spring組件,與傳統業務開發組件能很好集成,易於添加定製化需求,周邊擴展組件豐富,學習成本較低。 | 自身資源消耗較大,在資源有限的狀況下(1核2G),性能較差。相同配置下,併發的天花板要比nginx低很多。屬於技術組件、沒有成熟的產品,須要自開發。 |
zuul 1 | 基於servlet框架,採用阻塞和多線程方式,存在內部延遲嚴重、設備故障較多狀況下會引發存活鏈接增多和線程增長的狀況發生。並且不支持如WebSocket之類的長鏈接 | 和其餘幾款相比,沒有明顯優點 | 這個沒什麼好說的,性能表現差、併發數小、且不支持長鏈接。 |
zuul 2 | 與1相比,最大的區別是它採用了異步和無阻塞框架,每一個CPU一個線程,總體模型與Nginx相似 | 有netflix的成套產品支持,經常使用功能容易實現,相對於nginx來講更容易定製化開發。 | 總體缺點與spring cloud相似,自身資源佔用較大、低配下表現差,且須要必定的定製化開發才能使用。 |
從上面對比能夠看到,各種網關都有其自身的優劣勢和適用場景。對於業務網關開發,spring cloud gateway 或許是個不錯的選擇。中臺網關,對於定製化功能要求很少,對於性能和穩定性要求是第一位的,所以nginx內核網關是個不錯的選擇。
基於以上緣由咱們選擇了基於nginx內核的kong做爲中颱網關基座。首先,kong的內核是基於nginx的,其性能和穩定性是有保障的,並且也通過了大廠的實踐驗證;其次,kong是一個完整的網關產品,能夠開箱即用,而且提供了豐富的插件以及簡單的插件擴展機制。所以不管從性能、穩定性仍是從時間成本上看,kong都是首選。
微服務五種開源API網關實現組件對比:http://www.javashuo.com/article/p-ndsazcux-gr.html
Kong是Mashape開源的高性能高可用API網關和API服務管理層,在Mashape 管理了超過15,000個API,爲200,000開發者提供了每個月數十億的請求支持。
在微服務架構之下,按照康威定律,咱們系統架構會拆的很散,系統由一堆服務組成,下降了耦合度的同時也給服務的統一管理增長了難度。 上圖左邊描述了在舊的服務治理體系之下,鑑權,限流,日誌,監控等通用功能須要在每一個服務中單獨實現,這使得系統維護者沒有一個全局的視圖來統一管理這些功能。 Kong致力於解決的問題即是爲微服務納管這些通用的功能,在此基礎上提升系統的可擴展性。如右圖所示,微服務搭配上 Kong,可使得服務自己更專一於本身的領域,很好地對服務調用者和服務提供者作了隔離。
網關所須要的基本特性,Kong 都如數支持:
- 雲原生 : 與平臺無關,Kong 能夠從裸機運行到 Kubernetes
- 動態路由 :Kong 的背後是 OpenResty+Lua,因此從 OpenResty 繼承了動態路由的特性
- 熔斷
- 健康檢查
- 日誌 : 能夠記錄經過 Kong 的請求和響應。
- 鑑權 : 權限控制,IP 黑白名單
- 監控 : 提供了實時監控插件
- 認證 : 如數支持 HMAC, JWT, Basic, OAuth2.0 等經常使用協議
- 限流
- REST API: 經過 Rest API 進行配置管理,從繁瑣的配置文件中解放
- 可用性 : 自然支持分佈式
- 高性能 : 背靠非阻塞通訊的nginx,性能高
- 插件機制 : 提供衆多開箱即用的插件,且有易於擴展的自定義插件接口,用戶可使用 Lua 自行開發插件
Kong總體架構以下所示:
從技術的角度講,Kong能夠認爲是一個OpenResty應用程序。 OpenResty 運行在 Nginx 之上,使用 Lua 擴展了 Nginx。 Lua 是一種很是容易使用的腳本語言,可讓你在Nginx中編寫一些能夠執行的操做。
- Kong核心基於OpenResty、nginx構建,用來接收 API 請求;
- Kong插件攔截請求/響應,進行處理;
- 提供 restfull 方式管理 admin api;
- 數據庫存儲Kong集羣節點信息、API、消費者、插件等信息,目前提供了PostgreSQL和Cassandra支持。
Kong 抽象了一些概念Route、Service、Upstream、Consumer等,他們之間的關係以下圖所示 :
- Route 路由至關於nginx 配置中的location Route實體定義匹配客戶端請求的規則. 每一個路由都與一個服務相關聯,而服務可能有多個與之相關聯的路由. 每個匹配給定路線的請求都將被提交給它的相關服務. 路由和服務的組合提供了強大的路由機制, 能夠在Kong中定義細粒度的入口點,從而引導訪問到不一樣upstream服務
- service 是抽象層面的服務,他能夠直接映射到一個物理服務 (host 指向 ip + port),也能夠指向一個 upstream 來作到負載均衡,一個Service能夠有不少Route,匹配到的Route就會轉發到Service中
- upstream 是對上游服務器的抽象;target 表明了一個物理服務,是 ip + port 的抽象
- Consumer 對象表示服務的使用者或者用戶。最簡單的理解和配置consumer的方式是,將其於用戶進行一一映射,即一個consumer表明一個用戶(或應用),但若是你將幾個應用定義統一個consumer,這些均可以。
openresty定義的請求生命週期以下:
Kong插件遵循嚴格的文件結構,即包命,類名,文件位置等組織代碼的方式是固定的,詳細的文件結構以下圖所示:
Kong 提供了一個基類,容許開發者覆蓋類中提供的方法,這些方法的本質是openresty定義的請求生命週期,能夠在request/response 的生命週期中的幾個入口點注入自定義邏輯。每個方法有一個config參數,這個參數即schema.lua 中聲明的,在使用插件時的配置。詳細的邏輯以下圖所示:
Kong 默認自帶的插件集,按照功能的不一樣大體能夠分爲如下這些類:Authentication 認證、Security 安全、Serverless、Traffic Control 流量控制、Analytics & Monitoring 分析監控、Transformations 請求報文處理、Logging 日誌等
咱們目前用到的插件以下:
類別 | 插件名 | 使用場景 |
---|---|---|
認證 | key-auth | 對於服務或者路由提供用關鍵字認證機制 |
認證 | jwt | 提供JWT(JSON WEB Token)的認證方式 |
安全 | acl | 經過ACL(Access Control List)的組名稱對服務或者路由進行黑白名單的訪問控制 |
日誌 | tcp-log | 發送請求和響應日誌到TCP服務器 |
流量控制 | rate-limiting | 提供對給定時間請求數目的控制功能 |
流量控制 | request-termination | 根據響應的狀態碼和信息,可中止對某個服務或者路由的流量 |
監控 | prometheus | 暴露kong的metric endpoint |
服務 | 配置說明 |
---|---|
SLB | 阿里雲SLB,QPS:10000,IP:10.163.240.30 |
kong | 單節點獨立部署,4核8G,IP:10.163.204.90 |
負載均衡 | compass負載均衡,IP:10.163.204.8 |
後端服務 | 容器化部署,0.3核,400m |
日誌服務 | 1核,2G |
ES | ES集羣,3臺,16核64G |
後端服務是標準Spring Boot服務,部署在Compass平臺,沒有作額外業務邏輯,提供如下接口
- /api/v1/quick:直接返回計數,不錯額外處理
- /api/v1/slown:直接返回計數,但會延遲3~10秒鐘,該值爲隨機值
jmeter測試軟件,進行吞吐量測試,測試樣本爲1000併發,1000次輪詢,即100w次調用。如下是測試結果統計:
序號 | 測試用例 | 總耗時 | 最小耗時 | 最大耗時 | 平均耗時 | CPU_start | CPU_end | memory_start | memory_end | memory_max | 備註 |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 直連服務,不通過網關 | 161s | 1ms | 496ms | 156ms | - | - | - | - | - | - |
2 | 網關+服務+logstash日誌服務 | 168s | 2ms | 6255ms | 161ms | 0.2 | 37.8 | 28.3 | 55.3 | 70.4 | 日誌服務滯後服務吞吐量,日誌寫完約用時8分鐘;且在日誌寫入期間網關內存持續上升 |
3 | 網關+服務+filebeat日誌服務 | 163s | 2ms | 5286ms | 155ms | 0.2 | 44.9 | 10.8 | 11.2 | 11.2 | 日誌滯後約1分鐘,耗時3分半。無其餘明顯影響 |
4 | 網關+服務 | 161s | 2ms | 5134ms | 156ms | 0.2 | 34.8 | 8.9 | 9.2 | 9.2 | - |
5 | 短鏈接+https+網關+filebeat | 561s | 2ms | 255ms | 128ms | 0.2 | 25.1 | 9.3 | 9.1 | 9.3 | 在短連接狀況下,吞吐量爲2000/s因此耗時較長,可是每條的耗時並無受到太大影響 |
6 | 短鏈接+http+網關+filebeat | 160s | 2ms | 4988ms | 156ms | 0.2 | 44.4 | 11.2 | 10.8 | 11.2 | 關閉SLB的https協議轉換以後,吞吐量明顯提高,與上文長鏈接測試結果一致 |
從上圖不難看出,在客戶端訪問結束(3.5分鐘)時,CPU佔用就開始明顯降低,可是因爲日誌服務處理效率跟不上,網關內存卻繼續上升,最高佔用70%左右,隨後降低。從這裏不難看出,logstash日誌處理方案,在大吞吐量時會成爲瓶頸,進而影響網關機器。
從上圖看,filebeat對於網關內存幾乎沒有影響,實際測試中,filebeat日誌吞吐量約爲4200/s,滯後網關吞吐量,可是並不會形成額外的內存開銷。
從上圖不難看出,就網關自己的吞吐量看,三者基本是一致的。logstash日誌服務,會有較大的額外內存開銷和較小的CPU開銷;filebeat幾乎沒有額外的內存開銷,僅有少許的CPU開銷。 綜上在大吞吐量及日誌需求下,filebeat是個不錯的選擇。
通過對比和統計測試數據,發現kong自己,在啓用插件的狀況下,額外的性能損耗約爲0.11ms。
須要注意的是,因爲咱們使用的是阿里雲的SLB,在https和短鏈接併發的狀況下,會帶來比較嚴重的性能損失,所以在實際應用中,須要根據API安全級別去考慮策略。
一、測試方案
基本配置與吞吐量測試一致。資源所限,很難達到nginx的訪問瓶頸(這也從側面說明了nginx內核的強大).咱們修改了kong的nginx配置項,將鏈接上限改成100.
nginx_work_processes=1 nginx_events_work_connections=100
二、測試結論
咱們以100併發訪問後端應用,後端應用耗時在3~10秒之間隨機。測試中發現當併發數達到40左右就達到了上限。這時網關其餘服務也不可用,範文均返回502;直至測試結束才逐步恢復。 所以能夠推斷出,在規模化場景中,低質的後端服務會對網關自身的運行形成影響,嚴重的狀況下會是致命的。咱們在設計網關的高可用方案時要考慮此類狀況。
參考《部署架構》章節,咱們採用集羣模式部署。該模式容許咱們水平的擴展集羣大小,以應對不一樣的流量。從kong的設計上講其水平擴展是平滑且簡單的。惟一的影響就是,它是基於數據庫作的一致性,爲了提升效率,全部數據是緩存在內存中的,所以在一致性上會存在必定的延遲(5S左右)。集羣前端咱們採用阿里雲的SLB做爲負載均衡,以保證整個集羣的高可用。
結合prometheuse以及告警平臺實現網關集羣運行狀態的監控。
具體來講就是啓用prometheuse插件,將Kong與上游服務的相關指標,以prometheuse exposition的形式公開。prometheuse集羣會對這些指標進行抓取。主要指標包括:
- 節點內存佔用狀況
- API服務請求數
- API響應耗時
- 當前活躍鏈接數
- 數據存儲是否可達
- 基於指標,指定相關告警規則,經過告警平臺,實現集羣運行狀態監控。
上文提到了,上游低質服務會對網關自己的可用性形成影響,嚴重狀況下會致使網關宕機。做爲服務中樞的網關一旦宕機,後果將是災難性的。所以對於上游服務的管理和監控是必要的。目前主要從如下三個方面着手:
咱們經過啓用上游的健康檢查,來實現對後端服務可用性的實時監測,以便kong及時發現異常服務,並終止到其的路由。kong提供兩類健康檢查:
1.主動健康檢查(active)
主動健康檢查是指,上游服務提供一個心跳接口,由空定時調用,當達到指定閾值時,就認定服務不可用;
同時根據設置的閾值,一旦服務達到健康閾值,kong會自動恢復對該服務的路由。
優勢:與實際運行無關,由kong主動探查服務,能夠及時發現異常,並能自動恢復。 缺點:該方案會對上游服務帶來額外的流量消耗。
2.被動健康檢查(passive)
被動健康檢查是指,kong不會主動心跳上游服務,而是根據實際路由狀況,結合設置的閾值來判斷服務是否可用。
優勢:不會對上游服務帶來任何影響 缺點:一旦異常,服務不能自動恢復,並且異常的發現取決於實際的路由訪問狀況,不能及時發現
限流插件,顧名思義就是對後端服務的訪問流量進行限制。kong提供了靈活的限流策略,他容許咱們對消費者訪問某個服務、API進行限制。提供了多種級別的閾值設置。該插件能夠有效的攔截惡意攻擊請求。
咱們經過配置SLB策略,將低質服務所有負載到獨立的網關集羣,使其與其餘服務在物理上隔離,以免其可能帶來的雪崩。
Kong的日誌插件中咱們選用http-log,原理是設置一個log-server地址,Kong會將日誌經過post請求發送到設置的log-server,而後log-server把日誌給沉澱下來。 這裏的log-server咱們使用logstash實現,將收集到的日誌發送到ES中。
日誌收集流程以下:
logstash計劃根據集羣地域不一樣分別部署,青島集羣共用一套,北京集羣另外搭建。 青島kong集羣分爲測試和生產環境,logstash將開放兩個http服務端口,9000對應接收測試環境日誌,9001對應接收生產環境日誌。 根據端口數據來源不一樣,logstash將日誌存儲到es的不一樣索引上,用以區分環境信息。
logstash青島集羣服務部署在容器雲內, 全部配置文件都使用配置文件掛載的形式,方便修改配置。
官方文檔地址:https://docs.konghq.com/hub/kong-inc/http-log/
每次請求都會以JSON形式的內容記錄,格式以下:
{ "request": { "method": "GET", "uri": "/get", "url": "http://httpbin.org:8000/get", "size": "75", "querystring": {}, "headers": { "accept": "*/*", "host": "httpbin.org", "user-agent": "curl/7.37.1" }, "tls": { "version": "TLSv1.2", "cipher": "ECDHE-RSA-AES256-GCM-SHA384", "supported_client_ciphers": "ECDHE-RSA-AES256-GCM-SHA384", "client_verify": "NONE" } }, "upstream_uri": "/", "response": { "status": 200, "size": "434", "headers": { "Content-Length": "197", "via": "kong/0.3.0", "Connection": "close", "access-control-allow-credentials": "true", "Content-Type": "application/json", "server": "nginx", "access-control-allow-origin": "*" } }, "tries": [ { "state": "next", "code": 502, "ip": "127.0.0.1", "port": 8000 }, { "ip": "127.0.0.1", "port": 8000 } ], "authenticated_entity": { "consumer_id": "80f74eef-31b8-45d5-c525-ae532297ea8e", "id": "eaa330c0-4cff-47f5-c79e-b2e4f355207e" }, "route": { "created_at": 1521555129, "hosts": null, "id": "75818c5f-202d-4b82-a553-6a46e7c9a19e", "methods": null, "paths": [ "/example-path" ], "preserve_host": false, "protocols": [ "http", "https" ], "regex_priority": 0, "service": { "id": "0590139e-7481-466c-bcdf-929adcaaf804" }, "strip_path": true, "updated_at": 1521555129 }, "service": { "connect_timeout": 60000, "created_at": 1521554518, "host": "example.com", "id": "0590139e-7481-466c-bcdf-929adcaaf804", "name": "myservice", "path": "/", "port": 80, "protocol": "http", "read_timeout": 60000, "retries": 5, "updated_at": 1521554518, "write_timeout": 60000 }, "workspaces": [ { "id":"b7cac81a-05dc-41f5-b6dc-b87e29b6c3a3", "name": "default" } ], "consumer": { "username": "demo", "created_at": 1491847011000, "id": "35b03bfc-7a5b-4a23-a594-aa350c585fa8" }, "latencies": { "proxy": 1430, "kong": 9, "request": 1921 }, "client_ip": "127.0.0.1", "started_at": 1433209822425 }
- request 包含客戶端發送的請求內容
- response 包含發送到客戶端的響應內容
- tries 包含負載均衡器爲此請求進行的(從新)嘗試(成功和失敗)列表
- route 包含請求匹配的route信息
- service 包含請求匹配的service信息
- authenticated_entity 包含身份驗證的憑據屬性(若是已啓用身份驗證插件)
- workspaces 包含路由關聯的工做空間的Kong屬性(僅限Kong Enterprise版本> = 0.34)
- consumer 包含消費者認證信息(若是已啓用身份驗證插件)
- proxy 是最終服務處理請求所花費的時間
- kong 是運行全部插件所需的內部Kong延遲
- request 是從客戶端讀取的第一個字節之間以及最後一個字節發送到客戶端之間通過的時間。用於檢測慢速客戶端
- client_ip 包含原始客戶端IP地址
- started_at 包含開始處理請求的UTC時間戳
配置一個webhook,網關根據返回響應碼決定是否繼續執行路由。
經過發出如下請求在Service上配置次插件
$ curl -X POST http://kong:8001/services/{service}/plugins \ --data "name=pre-filter" \ --data "config.http_endpoint=http://mockbin.org/bin/:id" \ --data "config.header_names=headers" \ --data "config.timeout=1000" \ --data "config.keepalive=1000"
{service}是此插件配置將定位的Service的id或name
$ curl -X POST http://kong:8001/routes/{route}/plugins \ --data "name=pre-filter" \ --data "config.http_endpoint=http://mockbin.org/bin/:id" \ --data "config.header_names=headers" \ --data "config.timeout=1000" \ --data "config.keepalive=1000"
{route}是此插件配置將定位的Route的id或name
後面結合k8s進行演示
如下是此插件使用的參數列表
參數 | 默認值 | 說明 |
---|---|---|
name | 要啓用的插件的名稱,本例中爲pre-filter | |
service_id | 此插件定位的Service的Id,能夠爲空 | |
route_id | 此插件定位的Route的ID,能夠爲空 | |
enabled | true | 是否應用此插件 |
config.http_endpoint | 將要調用的webhook地址,須要是GET請求 | |
config.timeout | 1000 | 調用服務的超時時間,默認是1000ms |
config.header_names | authorization | 須要轉發的請求頭信息 |
該插件處於路由轉發的前置位置。在請求到來時,會根據header_names配置,從請求頭中獲取對應的信息,並封裝到新的請求中,發送到指定的http_endpoint。根據返回狀態碼來判斷是否繼續執行。
- 200 表示經過,會繼續執行後續操做
- 302 表示經過,會繼續執行後續操做
- 大於等於400,表示不經過,會阻斷請求,返回401到前端;注意若是http_endpoint出現異常,也會阻斷請求。
kong 搭建手冊
操做系統版本
lsb_release -a 內核版本 uname -a 記錄好系統版本
在yum源配置完善的狀況下能夠直接執行 $ sudo yum install epel-release $ sudo yum install kong-2.0.2.el7.amd64.rpm --nogpgcheck 若是yum源配置有問題,能夠手動指定遠程資源安裝 安裝epel-release軟件包,以便Kong能夠獲取全部必需的依賴項: $ EL_VERSION=`cat /etc/redhat-release | grep -oE '[0-9]+\.[0-9]+'` $ sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-${EL_VERSION%.*}.noarch.rpm 安裝Kong 對應的packages能夠從https://docs.konghq.com/install/centos/#packages 對照系統版本選擇: $ sudo yum install -y https://bintray.com/kong/kong-rpm/download_file?file_path=centos/7/kong-2.0.2.el7.amd64.rpm --nogpgcheck
修改配置數據庫 cp /etc/kong/kong.conf.default /etc/kong/kong.conf vi /etc/kong/kong.conf grep -E "pg|post" /etc/kong/kong.conf database = postgres # Determines which of PostgreSQL or Cassandra # Accepted values are `postgres`, 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, pg_user = kong # Postgres user. pg_password = 123456 # Postgres user's password. pg_database = kong # The database name to connect to. 初始化數據庫 kong migrations bootstrap #集羣其中一個節點配置完成便可,其他節點無需重複執行 啓動 kong start 檢查狀態 kong health
全部節點啓動完成以後,能夠自主部署nginx負載,至此集羣部署完成。
組件 | 版本 |
---|---|
kubectl | 1.16.9 |
kong | 2.0 |
默認狀況下,Kong Gateway在其配置的代理端口8000和8443上偵聽流量。它評估傳入的客戶端API請求,並將其路由到適當的後端API。在路由請求和提供響應時,能夠根據須要經過插件應用策略。
例如,在路由請求以前,可能須要客戶端進行身份驗證。這帶來了許多好處,包括:
- 因爲Kong Gateway正在處理身份驗證,所以該服務不須要本身的身份驗證邏輯。
- 該服務僅接收有效請求,所以不會浪費週期來處理無效請求。
- 記錄全部請求以集中查看流量。
plantuml @startuml "API CLIENT" -> "KONG GATEWAY": REQUESTS activate "KONG GATEWAY" "KONG GATEWAY" -> "BACKEND API": REQUESTS "BACKEND API" -> "KONG GATEWAY": RESPONSES "KONG GATEWAY" -> "API CLIENT": RESPONSES deactivate "KONG GATEWAY" @enduml
kong中的插件
plantuml @startuml "API CLIENT" -> "KONG GATEWAY": REQUESTS activate "KONG GATEWAY" "KONG GATEWAY" -> "KONG GATEWAY": "forward-plugin" "KONG GATEWAY" -> "AUTH BACKEND SERVER": REQUEST "AUTH BACKEND SERVER" -> "KONG GATEWAY": RESPONSES "KONG GATEWAY" -> "KONG GATEWAY": "forward-plugin" "KONG GATEWAY" -> "BACKEND API": REQUESTS "BACKEND API" -> "KONG GATEWAY": RESPONSES "KONG GATEWAY" -> "API CLIENT": RESPONSES deactivate "KONG GATEWAY" @enduml
kubectl apply -k manifests/base
查看po狀態
# kubectl get po -n kong NAME READY STATUS RESTARTS AGE ingress-kong-7f8f64c5fc-xrsbg 2/2 Running 1 17m
查看svc
# kubectl get svc -n kong NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kong-proxy LoadBalancer 10.96.178.210 <pending> 80:32724/TCP,443:31298/TCP,8100:32415/TCP 25m kong-validation-webhook ClusterIP 10.104.253.149 <none> 443/TCP 25m
運行如下命令
# export PROXY_IP=$(kubectl get -o jsonpath="{.spec.clusterIP}" service kong-proxy -n kong)
這個時候訪問kong服務,響應頭包含kong信息。
curl -i $PROXY_IP
以本demo爲例,構建服務鏡像
docker build -t kong-test-server apps/test/
docker build -t kong-auth-server apps/auth/
在kubernetes環境跑起來
kubectl apply -f apps/test/test.yaml kubectl apply -f apps/auth/auth.yaml
訪問服務
能夠看到結果以下,流量通過kong訪問到了test和auth
curl -i $PROXY_IP/test/
curl -i $PROXY_IP/auth/
設置局部插件
- 注:設置在Ingress或Service,都能使插件生效。如下以Ingress爲例,Service同。
查看Ingress資源,能夠看到剛剛建立的兩個Ingress資源
kubectl get ingress
聲明官方插件
$ echo ' apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: name: add-response-header config: add: headers: - "demo: injected-by-kong" plugin: response-transformer ' | kubectl apply -f -
將官方插件與Ingress規則相關聯
kubectl patch ingress kong-test-server -p '{"metadata":{"annotations":{"konghq.com/plugins":"add-response-header"}}}'
查看ingress信息
訪問服務,能夠看到響應頭多了剛剛插件的信息
curl -i $PROXY_IP/test/
設置全局插件
$ echo " apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: name: global-rate-limit labels: global: \"true\" config: minute: 5 limit_by: consumer policy: local plugin: rate-limiting " | kubectl apply -f -
查看插件資源
kubectl get kp -A
再次訪問服務,響應頭多了全局插件信息(全局插件不須要在指定ingress或service配置註解)
curl -i $PROXY_IP/test/
本demo使用lua實現了兩個自定義插件:
- my-custom-plugin:根據配置文件返回指定響應頭
- request-uri-pass-auth:根據配置文件,配置路由白名單,對不符合路由白名單規則的請求做攔截
爲插件代碼建立ConfigMap
以ConfigMap的方式將插件加載進kong服務裏
下面建立這2個自定義插件
kubectl create configmap kong-plugin-myheader --from-file=demo/custom-plugins/myheader -n kong kubectl create configmap kong-plugin-request-uri-pass-auth --from-file=demo/custom-plugins/request-uri-pass-auth -n kong
查看建立的configmap
kubectl get configmap -n kong
要使用自定義插件,須要新增自定義插件環境變量,而且將上述生成的插件代碼以ConfigMap的方式映射到kong中。
apiVersion: apps/v1 kind: Deployment metadata: name: ingress-kong namespace: kong spec: template: spec: containers: - name: proxy env: - name: KONG_PLUGINS value: request-uri-pass-auth,myheader - name: KONG_LUA_PACKAGE_PATH value: "/opt/?.lua;;" volumeMounts: - name: plugin-request-uri-pass-auth mountPath: /opt/kong/plugins/request-uri-pass-auth - name: my-custom-plugin mountPath: /opt/kong/plugins/myheader volumes: - name: plugin-request-uri-pass-auth configMap: name: kong-plugin-request-uri-pass-auth - name: my-custom-plugin configMap: name: kong-plugin-myheader
更新kong Deployment資源
kubectl apply -k demo/custom-plugins/
建立Kong Plugin自定義資源
分別對剛剛2個插件建立Kong Plugin
myheader.yaml
apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: name: my-custom-plugin config: header_value: "my first plugin" plugin: myheader
request-uri-pass-auth.yaml
apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: name: request-uri-pass-auth config: prefixs: - "/open/" plugin: request-uri-pass-auth # kubectl apply -f demo/custom-plugins/myheader/myheader.yaml kongplugin.configuration.konghq.com/my-custom-plugin created # kubectl apply -f demo/custom-plugins/request-uri-pass-auth/request-uri-pass-auth.yaml kongplugin.configuration.konghq.com/request-uri-pass-auth created
能夠看到官方的Kong Plugin和自定義Kong Plugin
kubectl get KongPlugin -A
注意!這裏有一個坑!當使用自定義插件的時候。咱們須要聲明KONG_PLUGINS環境變量,這會致使官方的插件失效。這個時候須要將官方插件也加入到聲明的KONG_PLUGINS中。
官方插件失效後訪問設置了官方插件註解的服務時返回如下結果
以本demo爲例,完整的yaml應該爲: custoem-plugin.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: ingress-kong namespace: kong spec: template: spec: containers: - name: proxy env: - name: KONG_PLUGINS value: request-uri-pass-auth,myheader,response-transformer,rate-limiting - name: KONG_LUA_PACKAGE_PATH value: "/opt/?.lua;;" volumeMounts: - name: plugin-request-uri-pass-auth mountPath: /opt/kong/plugins/request-uri-pass-auth - name: my-custom-plugin mountPath: /opt/kong/plugins/myheader volumes: - name: plugin-request-uri-pass-auth configMap: name: kong-plugin-request-uri-pass-auth - name: my-custom-plugin configMap: name: kong-plugin-myheader
更新kong Deployment資源
kubectl apply -k demo/custom-plugins/
測試自定義插件是否生效
爲test服務添加request-uri-pass-auth插件
kubectl patch ingress kong-test-server -p '{"metadata":{"annotations":{"konghq.com/plugins":"request-uri-pass-auth"}}}'
爲auth服務添加my-custom-plugin插件
kubectl patch ingress kong-auth-server -p '{"metadata":{"annotations":{"konghq.com/plugins":"my-custom-plugin"}}}'
測試自定義插件是否生效
訪問test服務
curl -i $PROXY_IP/test/
能夠看到/test/路由被"request-uri-pass-auth"插件攔截
curl -i $PROXY_IP/open/
能夠看到,/open/路由沒有被攔截,由於"request-uri-pass-auth"插件對/open/路由做了放行。而後還放回了全局插件"rate-limit"信息。自定義插件和官方對全局插件生效。
訪問auth服務
curl -i $PROXY_IP/auth/
能夠看到,返回了"my-custom-plugin"插件信息和"rate-limit"插件信息。自定義插件和官方全局插件生效。
注意!KongPlugin資源須要跟對應的svc或ingress處於同一個命名空間。本demo都是聲明在default空間。
建立slb
修改manifests/base/service.yaml
... metadata: name: kong-proxy namespace: kong annotations: ## ALIYUN SLB service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id: lb-wxxxxxxxxxxxe service.beta.kubernetes.io/alicloud-loadbalancer-address-type: internet ...
綜合demo/custom-plugins/README.md 以及manifests/base/kong-ingress-dbless.yaml和manifests/base/service.yaml