你是否聽說過網關,代理(正向和反向),負載平衡器,API網關?你可能做到了,即使你沒有聽說過,也可能聽說過nginx,HAProxy,Envoy,Traefik,Gloo,Kong,Ambassador,Tyk等產品。你可能每次都使用網關,甚至都不知道。網關通常位於客戶端與支持應用程式或服務之間。網關的工作是代理或「協商」客戶端與伺服器之間的通信。想像一下通過正門走進購物中心。當你走進時,可能會遇到以下其中一種情況:
購物中心目錄。無論你去哪個購物中心,你都將遇到一個顯示所有商店名稱及其位置的目錄,並且可能還包括地圖。假設你想參觀樂高商店。你知道這家商店在購物中心內,但你不知道確切的地址。幸運的是,知道商店的名稱並使用目錄查找商店在購物中心內的位置就足夠了。
現在,如果我們將購物中心視為伺服器(或伺服器集群),那麼購物中心中的商店就是在該伺服器上運行的服務或應用程式。在這種情況下,客戶端是你或你的計算機。如果購物中心中只有一家商店,那麼問題就不那麼重要了-只有一個地址,你知道去哪裡。
但是,我們都知道那不是現實。就像購物中心裡有數百家商店一樣,伺服器上也可以運行數百個或更多應用程式。我們可以說,記住所有地址的客戶端至少是不實際的,更不用說在伺服器上只運行一個應用程式了。
回到類比-你可以將Mall目錄視為軟體世界中的網關。該網關知道所有應用程式所在的位置。它知道伺服器上運行的每個應用程式的實際地址(例如IP或完全限定的域名)。
就像你不需要知道商店的確切地址一樣,客戶端也不需要通過網關發出請求。
如果你想到達lego商店或致電應用程式,則可以請求stores.example.com/lego,網關將知道將請求轉發或代理到實際地址。可以在客戶端和應用程式之間放置一個用於傳入流量的網關,因此稱為入口網關。客戶端不需要發出請求來分離應用程式,而只需要了解網關並向網關發出請求。路由傳入的請求並通過公共端點公開API僅是網關可以承擔的部分職責。網關執行的其他典型任務是速率限制,SSL終止,負載平衡等。
什麼是限速?
將速率限制視為一個漏鬥,它僅允許每單位時間一定數量的請求通過應用程式。如果我將購物中心的類比與黑色星期五結合在一起,則商店已滿,因此你需要限制可以進入商店的人數。
速率限制器的作用非常相似-它限制了一定時間內可以發出的請求數量。例如,對於每秒10個請求的速率限制,客戶端每秒只能發出10個請求。如果客戶端嘗試每秒發出10個以上的請求,則表示它們受到伺服器的速率限制。在這種情況下,伺服器的HTTP響應為429:Too Many Requests。
什麼是SSL終止?
SSL代表安全套接字層協議。SSL終止或也稱為SSL卸載是解密加密流量的過程。SSL終止與網關模式完美配合。當加密的流量到達網關時,它將在那裡解密,然後傳遞到後端應用程式。在網關級別執行SSL終止還可以減輕伺服器的負擔,因為你僅在網關級別執行一次,而不是在每個應用程式中執行一次。
你可以在每個應用程式或服務上實現這些功能,如下圖所示。
但是,如果在每個應用程式級別執行SSL終止和速率限制,則都會「花費」時間和資源。網關可以幫助卸載此功能,並在網關級別執行一次。
這是一些可以在網關級別上卸載和執行的功能的列表:
認證方式
SSL終止
負載均衡
限速
斷路
基於客戶端的響應轉換
什麼是斷路?
斷路是可以幫助提高服務彈性的一種模式。一旦應用程式已經失敗,它可以防止對應用程式進行不必要的請求。你可以檢查「什麼是電路斷路?」 找到更多詳細信息。
網關方法也有其缺點。它是你必須開發,維護或至少配置(如果使用現有網關解決方案)的附加軟體。你還需要確保網關不會成為瓶頸-如果不需要,不要嘗試將太多的東西卸載到網關上。
出口網關
另一方面(或另一端),出口網關在你的專用網絡內部運行,並且可以用作退出網絡的流量的出口點。例如,如果你的應用程式與外部API(例如,Github)進行交互,則對https://api.github.com的任何請求都將首先通過出口網關,然後出口網關可以將調用代理到外部服務。
你為什麼要使用出口網關?出口網關用於控制所有退出網絡的流量。例如,如果你知道自己的外部依賴關係(例如Github API),則可以阻止任何其他出站連接。萬一你的服務受到威脅,阻止所有出站連接將阻止潛在的攻擊者進行進一步的攻擊。如果我們更進一步,則可以在專用計算機上運行出口網關,在其中可以應用更嚴格的安全策略並分別監視計算機。另一個常見的情況是你的伺服器無法訪問外部IP或公共Internet。在這種情況下,你的出口網關(可訪問網絡中的服務)充當所有外部請求的出口點。
實踐中的網關
讓我們以一個簡單的示例來結束此示例,該示例顯示網關的一些基本功能。我將使用HAProxy,但其他代理也可以實現相同的功能。你可以從GitHub存儲庫中獲取原始碼。
我創建了一個名為Square的服務,該服務公開了一個API。API從URL(一個數字)中獲取一個參數,然後返回該數字的平方。該服務打包在Docker映像中。要在你的機器上運行它,你將必須下載並安裝Docker。你可以按照說明下載和安裝Docker Desktop。
安裝Docker Desktop後,打開終端窗口,然後運行learnloudnative/square:0.1.0Docker映像。
第一次運行上述命令時,可能需要花費一些時間,因為Docker需要下載(或使用Docker術語提取)鏡像。由於Square服務公開了API,因此我們需要在要訪問API的位置提供埠號。因此-p 8080:8080-第一個8080是說我們要在本地計算機的埠8080上公開該服務,第二個8080是該服務正在偵聽的埠號。
下載映像並運行容器後,你將看到以下消息:
讓我們嘗試向服務發送請求。打開第二個終端窗口,以使服務保持運行,並運行以下命令
該服務將返回結果(625),你將在上一個終端窗口中注意到請求也已記錄:
你可以按CTRL + C停止運行該程序。
添加代理
為了使事情更容易運行,我將使用同時運行Square服務和HAProxy實例的Docker Compose。如果您不熟悉Docker Compose,請不要擔心,它只是同時運行多個Docker容器的一種方式。
該docker-compose.yaml文件定義了兩個服務- haproxy和和square-service。該docker-compose.yaml文件如下所示:
除了撰寫文件之外,我們還需要一個配置文件來配置HAProxy應該做什麼。記住,我們不會直接調用square-serviceDirect,而是將請求發送到代理,代理會將請求傳遞給square-service。
使用haproxy.cfg具有以下內容的文件配置HAProxy :
我們對兩個部分感興趣- frontend和backend。我們正在調用前端部分api_gateway,這是將代理綁定到地址和埠以及路由傳入流量的位置。我們只是在前端部分之後定義default_backend的be_square後端設置a 即可。
在後端部分,我們將創建一個s1帶有端點的單個伺服器square-service:8080-這是我們為docker-compose.yaml文件中的Square服務定義的名稱。
讓我們使用Docker compose來運行這兩個服務。請確保您從你的文件夾運行以下命令docker-compose.yaml和haproxy.cfg文件包括:
Docker compose完成工作,創建一個新網絡和兩個服務。從第二個終端,讓我們再次運行curl命令:
請注意,這次,我們使用的埠5000是HAProxy公開的埠(請查看docker-compose.yaml文件中的ports部分)。和之前一樣,你可以從Square服務獲得響應。這次的區別是請求首先通過了代理。
您可以再次按CTRL + C停止運行Docker compose。
在HAProxy上啟用統計信息
由於每個請求都通過代理,因此它可以收集有關請求,前端和後端伺服器的統計信息。
讓我們在HAProxy中啟用統計信息,方法是在haproxy.cfg文件末尾添加以下幾行:
上面啟用了port 8404和URI的統計信息/stats。由於我們要從代理訪問統計信息,因此我們還需要在中公開它docker-compose.yaml。在文件"8404:8404"的ports鍵下添加以下行docker-compose.yaml:
ports:
停止docker-compose如果它正在運行(按CTRL + C),然後運行docker-compose down以刪除服務,然後docker-compose up再次啟動它們。
容器啟動後,即可http://localhost:8404/stats在瀏覽器中打開。通過運行curl localhost:5000/square/25以生成一些數據來提出幾個請求。你將在HAProxy的統計信息報告中注意到會話數。
啟用健康檢查
HAProxy還支持運行狀況檢查。可以將HAProxy配置為定期向後端服務發出TCP請求,以確保它們「有效」。要啟用運行狀況檢查,你可以check在haproxy.cfg文件中定義伺服器後端的同一行上添加單詞。像這樣:
更新配置文件後,停止Docker compose(CTRL + C),然後docker-compose up再次運行以重新啟動容器。
如果你打開或刷新stats頁面http://localhost:8404/stats,你會注意到be_square表中的行現在變為綠色,這意味著代理正在執行運行狀況檢查,並且該服務運行正常。在報告圖例中,你將看到已active UP使用的。此外,該LastChk列還將顯示運行狀況檢查的結果。
拒絕要求
假設我們要保護我們的Square服務,並要求用戶在發出請求時提供API密鑰。如果他們沒有API密鑰,則我們不想允許他們調用該服務。
使用HAProxy進行此操作的一種方法是對其進行配置,以使其拒絕所有未設置API標頭的請求。為此,你可以bind在haproxy.cfg文件的前端部分中的命令之後添加以下行:
此行告訴代理拒絕所有請求,除非有一個名為api-keyset 的標頭。讓我們重新啟動容器(CTRL + C和docker-compose up),看看它是如何工作的。
如果你在未api-key設置標頭的情況下發出請求,則會返回403響應,如下所示:
但是,如果你包含api-key標頭,則代理將使請求通過,然後你將獲得服務的響應,就像之前一樣:
限速請求
最後,我們還要實現一個速率限制器,這樣一個用戶就不能發出太多請求,也不會給服務帶來不必要的壓力。
我們將不得不在haproxy.cfg文件中定義幾件事。我將首先分別解釋它們,然後我們將它們放在一起。
存儲/計數請求
為了使速率限制器正常工作,我們需要一種計數和存儲所發出請求數量的方法。我們將使用HAProxy稱為stick table的內存中存儲。使用stick表,你可以存儲請求數,然後在一定時間(在我們的情況下為5分鐘)後自動使請求過期(刪除):
設置請求限制
我們還需要設置一個限制。這個限制是一個數字,從這一點開始,我們將拒絕(或限制)請求。我們將使用訪問控制列表或ACL來測試條件(例如,請求數量是否大於X)並基於該條件執行操作(例如,拒絕請求):
上一行檢查具有特定api-key值的請求數是否大於10。如果未超出限制,我們將跟蹤請求並允許其繼續:
否則,如果超出限制,我們將拒絕該請求:
所有這些更改都需要frontend api_gateway在haproxy.cfg文件的部分中進行。這應該是這樣的:
是時候嘗試一下了!重新啟動容器,並向該服務發出10個請求。在第11個請求上,你將獲得429 Too Many Requests響應,如下所示:
您可以等待5分鐘以使速率限制器信息失效,或者嘗試使用其他方法api-key,您會發現請求將通過
最後,您可以再次檢查stats頁面,特別是表中的Denied列api_gateway。「 拒絕」列將顯示被拒絕的請求數。
總結
在本文中,我解釋了什麼是網關或代理,並展示了一些實用的示例,說明了如何使用網關來實現速率限制或拒絕請求。