kong in kubernetes
網關
這裡提到的網關特指API網關。API網關是在微服務架構的演進過程中產生的,其核心功能是聚合後端服務,為客戶端調用提供統一的門戶。由於網關的集中式管理,在其上又衍生了限流、負載、路由管理、安全防護等新的需求和功能。基於應用系統現狀,我們將網關進一步的細分為帶有業務邏輯的業務網關和專註於服務聚合、路由的中台網關。具體來說,業務網關一般是指某一個業務系統的網關,其除了聚合本系統的後端服務之外,還會額外承擔一些業務邏輯,比如通用的用戶鑒權、基於業務的路由規則等。中台網關,是跨系統的、是將已有的平台能力抽象、聚合,統一包裝成API服務,以便各平台、業務復用;中台網關關注的重點是服務的路由、抽象,提供基本的身份認證、限流等功能即可,不會嵌入具體的業務邏輯。注意這裡的身份認證和業務網關里的是不一樣的,業務網關身份認證一般是具體的終端用戶,中台網關里的身份認證是對調用方的識別、鑒權,不涉及具體終端用戶。
網關產品對比
目前比較流行的API網關主要分為三類:
1、 基於NGINX的反向代理
2、 基於網路編程框架(netty、socket)自開發
3、 基於組件的API網關框架,主要有:spring cloud gateway、zuul1、zuul2
基於網路編程框架的自開發不在我們考慮範圍內,主要原因有:自開發周期長,未經過實戰驗證可靠性需要長時間的磨合,而且自開發性能不會比已有框架表現的更好。因此我們不考慮此類情況。下面我們將分析1和3兩種情況。
nginx與spring cloud gateway、zuul對比
nginx
nginx由內核和模組組成,內核的設計非常微小和簡潔,完成的工作也非常簡單,僅僅通過查找配置文件與客戶端請求進行URL匹配,然後啟動不同的模組去完成相應的工作。下圖反映了HTTP請求處理的常規流程:
spring cloud gateway
spring cloud gateway是在spring boot基礎上構建的,用於快速構建分散式系統的通用模式的工具集。其核心也是基於filter的,可以實現類似於zuul的特性功能,但是使用spring cloud 開發的應用程式非常適合在Docker或者Paas上部署。
zuul
zuul是Netflix開源的微服務網關組件,它可以和Euraka、Ribbon、Hystrix等組件配合使用。其核心是一系列的過濾器,通過這些過濾器我們可以實現身份認證、審查、監控、動態路由、壓力測試、負載分配、靜態影響處理、多區域彈性等。
對比
不難看出三者在處理請求的思想上是一致的,都是基於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網關實現組件對比://blog.csdn.net/squirrelanimal0922/article/details/88946900
kong簡介及概念
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協議轉換之後,吞吐量明顯提升,與上文長連接測試結果一致 |
網關+服務+logstash日誌服務記憶體/CPU變化曲線
從上圖不難看出,在客戶端訪問結束(3.5分鐘)時,CPU佔用就開始明顯下降,但是由於日誌服務處理效率跟不上,網關記憶體卻繼續上升,最高佔用70%左右,隨後下降。從這裡不難看出,logstash日誌處理方案,在大吞吐量時會成為瓶頸,進而影響網關機器。
網關+服務+filebeat日誌服務記憶體/CPU變化曲線
從上圖看,filebeat對於網關記憶體幾乎沒有影響,實際測試中,filebeat日誌吞吐量約為4200/s,滯後網關吞吐量,但是並不會造成額外的記憶體開銷。
網關+服務記憶體/CPU曲線
日誌相關橫向對比
從上圖不難看出,就網關本身的吞吐量看,三者基本是一致的。logstash日誌服務,會有較大的額外記憶體開銷和較小的CPU開銷;filebeat幾乎沒有額外的記憶體開銷,僅有少量的CPU開銷。 綜上在大吞吐量及日誌需求下,filebeat是個不錯的選擇。
性能結果
經過對比和統計測試數據,發現kong本身,在啟用插件的情況下,額外的性能損耗約為0.11ms。
需要注意的是,由於我們使用的是阿里雲的SLB,在https和短連接並發的情況下,會帶來比較嚴重的性能損失,因此在實際應用中,需要根據API安全級別去考慮策略。
並發測試
1、測試方案
基本配置與吞吐量測試一致。資源所限,很難達到nginx的訪問瓶頸(這也從側面說明了nginx內核的強大).我們修改了kong的nginx配置項,將連接上限改為100.
nginx_work_processes=1
nginx_events_work_connections=100
2、測試結論
我們以100並發訪問後端應用,後端應用耗時在3~10秒之間隨機。測試中發現當並發數達到40左右就達到了上限。這時網關其他服務也不可用,範文均返回502;直至測試結束才逐步恢復。 因此可以推斷出,在規模化場景中,低質的後端服務會對網關自身的運行造成影響,嚴重的情況下會是致命的。我們在設計網關的高可用方案時要考慮此類情況。
kong高可用
部署方案
參考《部署架構》章節,我們採用集群模式部署。該模式允許我們水平的擴展集群大小,以應對不同的流量。從kong的設計上講其水平擴展是平滑且簡單的。唯一的影響就是,它是基於資料庫做的一致性,為了提高效率,所有數據是快取在記憶體中的,因此在一致性上會存在一定的延遲(5S左右)。集群前端我們採用阿里雲的SLB作為負載均衡,以保證整個集群的高可用。
運行監控
結合prometheuse以及告警平台實現網關集群運行狀態的監控。
具體來說就是啟用prometheuse插件,將Kong與上游服務的相關指標,以prometheuse exposition的形式公開。prometheuse集群會對這些指標進行抓取。主要指標包括:
- 節點記憶體佔用情況
- API服務請求數
- API響應耗時
- 當前活躍連接數
- 數據存儲是否可達
- 基於指標,指定相關告警規則,通過告警平台,實現集群運行狀態監控。
服務管理
上文提到了,上游低質服務會對網關本身的可用性造成影響,嚴重情況下會導致網關宕機。作為服務中樞的網關一旦宕機,後果將是災難性的。因此對於上游服務的管理和監控是必要的。目前主要從以下三個方面著手:
啟用健康檢查
我們通過啟用上游的健康檢查,來實現對後端服務可用性的實時監測,以便kong及時發現異常服務,並終止到其的路由。kong提供兩類健康檢查:
1.主動健康檢查(active)
主動健康檢查是指,上游服務提供一個心跳介面,由空定時調用,當達到指定閾值時,就認定服務不可用;
同時根據設置的閾值,一旦服務達到健康閾值,kong會自動恢復對該服務的路由。
優點:與實際運行無關,由kong主動探查服務,可以及時發現異常,並能自動恢復。
缺點:該方案會對上游服務帶來額外的流量消耗。
2.被動健康檢查(passive)
被動健康檢查是指,kong不會主動心跳上游服務,而是根據實際路由情況,結合設置的閾值來判斷服務是否可用。
優點:不會對上游服務帶來任何影響
缺點:一旦異常,服務不能自動恢復,而且異常的發現取決於實際的路由訪問情況,不能及時發現
啟用限流插件(rate limiting)
限流插件,顧名思義就是對後端服務的訪問流量進行限制。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配置文件
logstash青島集群服務部署在容器雲內, 所有配置文件都使用配置文件掛載的形式,方便修改配置。
kong日誌結構
官方文檔地址://docs.konghq.com/hub/kong-inc/http-log/
每次請求都會以JSON形式的內容記錄,格式如下:
{
"request": {
"method": "GET",
"uri": "/get",
"url": "//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時間戳
filter插件
Pre Filter
配置一個webhook,網關根據返迴響應碼決定是否繼續執行路由。
在Service啟用插件
通過發出以下請求在Service上配置次插件
$ curl -X POST //kong:8001/services/{service}/plugins \
--data "name=pre-filter" \
--data "config.http_endpoint=//mockbin.org/bin/:id" \
--data "config.header_names=headers" \
--data "config.timeout=1000" \
--data "config.keepalive=1000"
{service}是此插件配置將定位的Service的id或name
在Route上啟用插件
$ curl -X POST //kong:8001/routes/{route}/plugins \
--data "name=pre-filter" \
--data "config.http_endpoint=//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
kong 搭建手冊
環境檢查
作業系統版本
lsb_release -a
內核版本
uname -a
記錄好系統版本
kong安裝
在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 //dl.fedoraproject.org/pub/epel/epel-release-latest-${EL_VERSION%.*}.noarch.rpm
安裝Kong 對應的packages可以從//docs.konghq.com/install/centos/#packages 對照系統版本選擇:
$ sudo yum install -y //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負載,至此集群部署完成。
在k8s上部署kong
組件 | 版本 |
---|---|
kubectl | 1.16.9 |
kong | 2.0 |
Kong Gateway中的流量
默認情況下,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
更新kong Deployment資源
要使用自定義插件,需要新增自定義插件環境變數,並且將上述生成的插件程式碼以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和自定義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空間。
aliyun上使用kong
創建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
...
安裝官方插件之prometheus插件
綜合demo/custom-plugins/README.md 以及manifests/base/kong-ingress-dbless.yaml和manifests/base/service.yaml