kong in kubernetes
阿新 • • 發佈:2020-10-31
# 閘道器
這裡提到的閘道器特指API閘道器。API閘道器是在微服務架構的演進過程中產生的,其核心功能是聚合後端服務,為客戶端呼叫提供統一的門戶。由於閘道器的集中式管理,在其上又衍生了限流、負載、路由管理、安全防護等新的需求和功能。基於應用系統現狀,我們將閘道器進一步的細分為帶有業務邏輯的業務閘道器和專注於服務聚合、路由的中臺閘道器。具體來說,業務閘道器一般是指某一個業務系統的閘道器,其除了聚合本系統的後端服務之外,還會額外承擔一些業務邏輯,比如通用的使用者鑑權、基於業務的路由規則等。中臺閘道器,是跨系統的、是將已有的平臺能力抽象、聚合,統一包裝成API服務,以便各平臺、業務複用;中臺閘道器關注的重點是服務的路由、抽象,提供基本的身份認證、限流等功能即可,不會嵌入具體的業務邏輯。注意這裡的身份認證和業務閘道器裡的是不一樣的,業務閘道器身份認證一般是具體的終端使用者,中臺閘道器裡的身份認證是對呼叫方的識別、鑑權,不涉及具體終端使用者。
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603676432703-70ca3671-e813-4629-b04d-88155d2f5b92.png)
# 閘道器產品對比
目前比較流行的API閘道器主要分為三類:
1、 基於NGINX的反向代理
2、 基於網路程式設計框架(netty、socket)自開發
3、 基於元件的API閘道器框架,主要有:spring cloud gateway、zuul1、zuul2
基於網路程式設計框架的自開發不在我們考慮範圍內,主要原因有:自開發週期長,未經過實戰驗證可靠性需要長時間的磨合,而且自開發效能不會比已有框架表現的更好。因此我們不考慮此類情況。下面我們將分析1和3兩種情況。
nginx與spring cloud gateway、zuul對比
## nginx
nginx由核心和模組組成,核心的設計非常微小和簡潔,完成的工作也非常簡單,僅僅通過查詢配置檔案與客戶端請求進行URL匹配,然後啟動不同的模組去完成相應的工作。下圖反映了HTTP請求處理的常規流程:
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603676600695-447ff068-fa6d-46ad-8af5-b72a6a11c14c.png)
## spring cloud gateway
spring cloud gateway是在spring boot基礎上構建的,用於快速構建分散式系統的通用模式的工具集。其核心也是基於filter的,可以實現類似於zuul的特性功能,但是使用spring cloud 開發的應用程式非常適合在Docker或者Paas上部署。
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603676798302-cf6d6237-234f-48f9-b191-a28220c54f81.png)
## zuul
zuul是Netflix開源的微服務閘道器元件,它可以和Euraka、Ribbon、Hystrix等元件配合使用。其核心是一系列的過濾器,通過這些過濾器我們可以實現身份認證、審查、監控、動態路由、壓力測試、負載分配、靜態影響處理、多區域彈性等。
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603676884299-7694ba99-ef2a-4015-a51e-b4bdbf010883.png)
## 對比
不難看出三者在處理請求的思想上是一致的,都是基於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閘道器實現元件對比:https://blog.csdn.net/squirrelanimal0922/article/details/88946900
# kong簡介及概念
Kong是Mashape開源的高效能高可用API閘道器和API服務管理層,在Mashape 管理了超過15,000個API,為200,000開發者提供了每月數十億的請求支援。
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603679417225-ffb38206-0e85-4fcb-9470-15ab5b5ea2e8.png)
在微服務架構之下,按照康威定律,我們系統架構會拆的很散,系統由一堆服務組成,降低了耦合度的同時也給服務的統一管理增加了難度。 上圖左邊描述了在舊的服務治理體系之下,鑑權,限流,日誌,監控等通用功能需要在每個服務中單獨實現,這使得系統維護者沒有一個全域性的檢視來統一管理這些功能。 Kong致力於解決的問題便是為微服務納管這些通用的功能,在此基礎上提高系統的可擴充套件性。如右圖所示,微服務搭配上 Kong,可以使得服務本身更專注於自己的領域,很好地對服務呼叫者和服務提供者做了隔離。
閘道器所需要的基本特性,Kong 都如數支援:
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603679531311-5f340a3a-c639-445e-9e60-1288cdf8f489.png)
> - 雲原生 : 與平臺無關,Kong 可以從裸機執行到 Kubernetes
> - 動態路由 :Kong 的背後是 OpenResty+Lua,所以從 OpenResty 繼承了動態路由的特性
> - 熔斷
> - 健康檢查
> - 日誌 : 可以記錄通過 Kong 的請求和響應。
> - 鑑權 : 許可權控制,IP 黑白名單
> - 監控 : 提供了實時監控外掛
> - 認證 : 如數支援 HMAC, JWT, Basic, OAuth2.0 等常用協議
> - 限流
> - REST API: 通過 Rest API 進行配置管理,從繁瑣的配置檔案中解放
> - 可用性 : 天然支援分散式
> - 高效能 : 背靠非阻塞通訊的nginx,效能高
> - 外掛機制 : 提供眾多開箱即用的外掛,且有易於擴充套件的自定義外掛介面,使用者可以使用 Lua 自行開發外掛
Kong整體架構如下所示:
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603679824243-d7313f76-2d51-42a0-9975-edded7d876e7.png)
從技術的角度講,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等,他們之間的關係如下圖所示 :
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603679954307-a53f3697-0943-404e-9f99-f778ff2254d7.png)
> - Route 路由相當於nginx 配置中的location Route實體定義匹配客戶端請求的規則. 每個路由都與一個服務相關聯,而服務可能有多個與之相關聯的路由. 每一個匹配給定路線的請求都將被提交給它的相關服務. 路由和服務的組合提供了強大的路由機制, 可以在Kong中定義細粒度的入口點,從而引導訪問到不同upstream服務
> - service 是抽象層面的服務,他可以直接對映到一個物理服務 (host 指向 ip + port),也可以指向一個 upstream 來做到負載均衡,一個Service可以有很多Route,匹配到的Route就會轉發到Service中
> - upstream 是對上游伺服器的抽象;target 代表了一個物理服務,是 ip + port 的抽象
> - Consumer 物件表示服務的使用者或者使用者。最簡單的理解和配置consumer的方式是,將其於使用者進行一一對映,即一個consumer代表一個使用者(或應用),但如果你將幾個應用定義統一個consumer,這些都可以。
# 外掛機制與常用外掛說明
openresty定義的請求生命週期如下:
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603680164089-2b4af149-a644-4eb2-87d2-793047cc8605.png)
Kong外掛遵循嚴格的檔案結構,即包命,類名,檔案位置等組織程式碼的方式是固定的,詳細的檔案結構如下圖所示:
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603680223224-90f5216e-d7ad-4c83-a474-6cf5cfa48233.png)
Kong 提供了一個基類,允許開發者覆蓋類中提供的方法,這些方法的本質是openresty定義的請求生命週期,可以在request/response 的生命週期中的幾個入口點注入自定義邏輯。每一個方法有一個config引數,這個引數即schema.lua 中宣告的,在使用外掛時的配置。詳細的邏輯如下圖所示:
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603680314954-7e522638-dd3b-451d-8aaa-a7dd67ed3c2d.png)
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 |
# 部署架構
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603681607106-3c93deb1-5860-4828-a951-80c69838576b.png)
# 壓力測試
## 基礎配置
| 服務 | 配置說明 |
| :------- | --------------------------------------- |
| 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秒鐘,該值為隨機值
## 測試網路拓撲
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603682159562-2aa1469f-0faa-4118-aad7-f3cb1e306420.png)
## 吞吐量測試
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變化曲線
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1604141298658-cc870208-1d5f-459d-9b6f-6b58c48584f8.png)
從上圖不難看出,在客戶端訪問結束(3.5分鐘)時,CPU佔用就開始明顯下降,但是由於日誌服務處理效率跟不上,閘道器記憶體卻繼續上升,最高佔用70%左右,隨後下降。從這裡不難看出,logstash日誌處理方案,在大吞吐量時會成為瓶頸,進而影響閘道器機器。
### 閘道器+服務+filebeat日誌服務記憶體/CPU變化曲線
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1604141369619-6c4e7f57-52fe-4ce7-ad2d-682e28dcfb19.png)
從上圖看,filebeat對於閘道器記憶體幾乎沒有影響,實際測試中,filebeat日誌吞吐量約為4200/s,滯後閘道器吞吐量,但是並不會造成額外的記憶體開銷。
### 閘道器+服務記憶體/CPU曲線
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1604141604019-111699f6-1ff6-429b-8848-9e117dc9f19f.png)
### 日誌相關橫向對比
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1604141702128-8a72af18-d191-4dca-a06c-141432ce5cff.png)
從上圖不難看出,就閘道器本身的吞吐量看,三者基本是一致的。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策略,將低質服務全部負載到獨立的閘道器叢集,使其與其他服務在物理上隔離,以避免其可能帶來的雪崩。
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603692670404-43fdcc77-72c7-4ab2-a5d7-7bc9193ab733.png)
# 呼叫日誌收集流程
Kong的日誌外掛中我們選用http-log,原理是設定一個log-server地址,Kong會將日誌通過post請求傳送到設定的log-server,然後log-server把日誌給沉澱下來。 這裡的log-server我們使用logstash實現,將收集到的日誌傳送到ES中。
日誌收集流程如下:
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603692910855-a44a515c-d190-4693-8d9b-37306f523dfa.png)
logstash計劃根據叢集地域不同分別部署,青島叢集共用一套,北京叢集另外搭建。 青島kong叢集分為測試和生產環境,logstash將開放兩個http服務埠,9000對應接收測試環境日誌,9001對應接收生產環境日誌。 根據埠資料來源不同,logstash將日誌儲存到es的不同索引上,用以區分環境資訊。
## logstash配置檔案
logstash青島叢集服務部署在容器雲內, 所有配置檔案都使用配置檔案掛載的形式,方便修改配置。
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1604141784053-6b1f415b-e70c-4079-9846-ad0dd3dd6bd9.png)
## kong日誌結構
官方文件地址: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時間戳
## filter外掛
## Pre Filter
配置一個webhook,閘道器根據返回響應碼決定是否繼續執行路由。
### 在Service啟用外掛
通過發出以下請求在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
### 在Route上啟用外掛
```
$ 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
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 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負載,至此叢集部署完成。
# 在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中的外掛
![image](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603700297073-a3b38db9-9e32-4f50-9168-e24df3f9d417.png)
## 轉發時序圖
```
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 80:32724/TCP,443:31298/TCP,8100:32415/TCP 25m
kong-validation-webhook ClusterIP 10.104.253.149 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/
```
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603705715596-90713d58-caf9-4054-8f2d-dac8980039f7.png)
```
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/
```
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603705822966-1d2adcfb-8ef9-425d-9af7-be69ce2ce006.png)
```
curl -i $PROXY_IP/auth/
```
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603705876090-6825bf8c-4f58-4a7c-85c1-c33efbb1b49c.png)
### 使用官方外掛
設定區域性外掛
> - 注:設定在Ingress或Service,都能使外掛生效。以下以Ingress為例,Service同。
檢視Ingress資源,可以看到剛剛建立的兩個Ingress資源
```
kubectl get ingress
```
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603705973200-1b3a2eb5-e565-4711-94c4-cd315970a5e6.png)
宣告官方外掛
```
$ 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資訊
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603706052668-332df904-c7c8-41a2-a8b4-b4075b4b7c6e.png)
訪問服務,可以看到響應頭多了剛剛外掛的資訊
```
curl -i $PROXY_IP/test/
```
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603706116605-9ff28437-061a-4f71-a697-fe573fdb8630.png)
設定全域性外掛
```
$ 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
```
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603706195298-0dafed63-14f1-49d7-a4b9-992d70def1b4.png)
再次訪問服務,響應頭多了全域性外掛資訊(全域性外掛不需要在指定ingress或service配置註解)
```
curl -i $PROXY_IP/test/
```
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603706268786-2bf8420a-0601-475c-aaa7-ffb153347716.png)
### 安裝自定義外掛
本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
```
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603706383067-ec980a9c-8c69-46d6-b272-d633f8ae9ce9.png)
#### 更新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
```
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603706598103-9e1eb0bc-ad63-4040-a755-976053dfacb1.png)
> > 注意!這裡有一個坑!當使用自定義外掛的時候。我們需要宣告KONG_PLUGINS環境變數,這會導致官方的外掛失效。這個時候需要將官方外掛也加入到宣告的KONG_PLUGINS中。
官方外掛失效後訪問設定了官方外掛註解的服務時返回以下結果
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603706753619-e571fade-9fa1-4655-ad15-2dd2a7f8d0e3.png)
以本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"}}}'
```
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603707000720-7109cd36-423b-4853-8d49-911d8c27ef1f.png)
為auth服務新增my-custom-plugin外掛
```
kubectl patch ingress kong-auth-server -p '{"metadata":{"annotations":{"konghq.com/plugins":"my-custom-plugin"}}}'
```
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603707065972-c1de1468-a365-419e-96ae-85e14269215f.png)
測試自定義外掛是否生效
訪問test服務
```
curl -i $PROXY_IP/test/
```
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603707176285-0e5cb260-3d29-4d13-aa4f-863d448588a2.png)
可以看到/test/路由被"request-uri-pass-auth"外掛攔截
```
curl -i $PROXY_IP/open/
```
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603707234691-7c0a98c4-f88f-4138-8aba-c5ede027c998.png)
可以看到,/open/路由沒有被攔截,因為"request-uri-pass-auth"外掛對/open/路由作了放行。然後還放回了全域性外掛"rate-limit"資訊。自定義外掛和官方對全域性外掛生效。
訪問auth服務
```
curl -i $PROXY_IP/auth/
```
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1603707296812-52ef2d36-0b50-422e-920d-f7ca8a8c6f36.png)
可以看到,返回了"my-custom-plugin"外掛資訊和"rate-limit"外掛資訊。自定義外掛和官方全域性外掛生效。
> > 注意!KongPlugin資源需要跟對應的svc或ingress處於同一個名稱空間。本demo都是宣告在default空間。
## aliyun上使用kong
建立slb
![](https://cdn.nlark.com/yuque/0/2020/png/1143489/1604141898739-2a760a53-bff2-461e-acee-fe6e0fd3cad9.png)
修改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
github:https://github.com/zisefeizhu/konginkubernetes