帶有 Spring Boot 的 Kong 入口控制器
一、概述
Kubernetes (K8s) 是一種自動化軟件開發和部署的編排器,是當今流行的 API 託管選擇,可在本地或云服務上運行,例如 Google Cloud Kubernetes Service (GKS) 或 Amazon Elastic Kubernetes Service (EKS)。另一方面,Spring 已成為最流行的 Java 框架之一。
在本教程中,我們將演示如何設置受保護的環境,以使用 Kong Ingress Controller (KIC) 在 Kubernetes 上部署 Spring Boot 應用程序。我們還將通過為我們的應用程序實現一個簡單的速率限制器來演示 KIC 的高級使用,而無需任何編碼。
2. 改進的安全和訪問控制
現代應用程序部署,尤其是 API,需要處理許多挑戰,例如:隱私法(例如 GPDR)、安全問題 (DDOS) 和使用跟踪(例如 API 配額和速率限制)。在這種情況下,現代應用程序和 API 需要針對所有這些挑戰的額外保護級別,例如防火牆、反向代理、速率限制器和相關服務。儘管 K8s 環境可以保護我們的應用程序免受這些威脅,但我們仍然需要採取一些措施來確保我們的應用程序安全。其中一項措施是部署入口控制器並設置其對您的應用程序的訪問規則。
Ingress 是一個對象,它通過向已部署的應用程序公開 HTTP / HTTPS 路由並對其執行訪問規則來管理對 K8s 集群和部署在其上的應用程序的外部訪問。為了公開應用程序以允許外部訪問,我們需要定義入口規則並使用入口控制器,這是一個專門的反向代理和負載均衡器。通常,入口控制器由第三方公司提供,並且功能各不相同,例如本文中使用的Kong Ingress Controller 。
3. 設置環境
為了演示在 Spring Boot 應用程序中使用 Kong Ingress Controller (KIC),我們需要訪問 K8s 集群,因此我們可以使用完整的 Kubernetes、本地安裝或云提供,或者使用以下方式開發示例應用程序迷你庫。啟動 K8s 環境後,我們需要在集群上部署 Kong Ingress Controller。 Kong 公開了一個外部 IP,我們需要使用它來訪問我們的應用程序,因此最好使用該地址創建一個環境變量:
export PROXY_IP=$(minikube service -n kong kong-proxy --url | head -1)
而已! Kong Ingress Controller 已安裝,我們可以通過訪問該PROXY_IP
來測試它是否正在運行:
curl -i $PROXY_IP
響應應該是 404 錯誤,沒錯,因為我們還沒有部署任何應用程序,所以應該說沒有與這些值匹配的路由。是時候創建一個示例應用程序了,但在此之前,如果Docker不可用,我們可能需要安裝它。為了將我們的應用程序部署到 K8s,我們需要一種創建容器鏡像的方法,我們可以使用 Docker 來做到這一點。
4. 創建示例 Spring Boot 應用程序
現在我們需要一個 Spring Boot 應用程序並將其部署到 K8s 集群。要生成一個包含至少一個公開 Web 資源的簡單 HTTP 服務器應用程序,我們可以這樣做:
curl https://start.spring.io/starter.tgz -d dependencies=webflux,actuator -d type=maven-project | tar -xzvf -
一件重要的事情是選擇默認的 Java 版本。如果我們需要使用舊版本,則需要一個javaVersion
屬性:
curl https://start.spring.io/starter.tgz -d dependencies=webflux,actuator -d type=maven-project -d javaVersion=11 | tar -xzvf -
在這個示例應用程序中,我們選擇webflux,
它使用 Spring WebFlux 和 Netty 生成一個響應式 Web 應用程序。但是添加了另一個重要的依賴項。 actuator,
它是一個 Spring 應用的監控工具,已經暴露了一些 web 資源,這正是我們需要用 Kong 測試的。這樣,我們的應用程序已經公開了一些我們可以使用的 Web 資源。讓我們構建它:
./mvnw install
生成的 jar 是可執行的,因此我們可以通過運行它來測試應用程序:
java -jar 目標/*.jar
要測試應用程序,我們需要打開另一個終端並輸入以下命令:
curl -i http://localhost:8080/actuator/health
響應必須是應用程序的健康狀態,由執行器提供:
HTTP/1.1 200 OK
Content-Type: application/vnd.spring-boot.actuator.v3+json
Content-Length: 15
{"status":"UP"}
5. 從應用程序生成容器鏡像
將應用程序部署到 Kubernetes 集群的過程涉及創建容器映像並將其部署到集群可訪問的存儲庫。在現實生活中,我們會將我們的鏡像推送到 DockerHub 或我們自己的私有容器鏡像註冊表。但是,當我們使用 Minikube 時,讓我們將 Docker 客戶端環境變量指向 Minikube 的 Docker:
$(minikube docker-env)
我們可以構建應用程序鏡像:
./mvnw spring-boot:build-image
6. 部署應用程序
現在是時候在我們的 K8s 集群上部署應用程序了。我們需要創建一些 K8s 對象來部署和測試我們的應用程序,所有需要的文件都可以在演示的存儲庫中找到:
- 具有容器規範的應用程序的部署對象
- 為我們的 Pod 分配集群 IP 地址的服務定義
- 在我們的路由中使用 Kong 的代理 IP 地址的入口規則
部署對像只是創建運行我們的鏡像所必需的 pod,這是創建它的 YAML 文件:
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: demo
name: demo
spec:
replicas: 1
selector:
matchLabels:
app: demo
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: demo
spec:
containers:
- image: docker.io/library/demo:0.0.1-SNAPSHOT
name: demo
resources: {}
imagePullPolicy: Never
status: {}
我們指向在 Minikube 中創建的圖像,並獲得它的全名。請注意,必須將imagePullPolicy
屬性指定為Never
,因為我們沒有使用鏡像註冊服務器,因此我們不希望 K8s 嘗試下載鏡像,而是使用其內部 Docker 存檔中已經存在的鏡像。我們可以使用kubectl
部署它:
kubectl apply -f serviceDeployment.yaml
如果部署成功,我們可以看到消息:
deployment.apps/demo created
為了讓我們的應用程序有一個統一的 IP 地址,我們需要創建一個服務,它為它分配一個內部集群範圍的 IP 地址,這是創建它的 YAML 文件:
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: demo
name: demo
spec:
ports:
- name: 8080-8080
port: 8080
protocol: TCP
targetPort: 8080
selector:
app: demo
type: ClusterIP
status:
loadBalancer: {}
現在我們也可以使用kubectl
部署它:
kubectl apply -f clusterIp.yaml
請注意,我們正在選擇指向我們部署的應用程序的標籤demo
。為了能夠被外部訪問(在 K8s 集群之外),我們需要創建一個入口規則,在我們的例子中,我們將它指向路徑/actuator/health
和端口 8080:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: kong
rules:
- http:
paths:
- path: /actuator/health
pathType: ImplementationSpecific
backend:
service:
name: demo
port:
number: 8080
最後,我們使用kubectl
部署它:
kubectl apply -f ingress-rule.yaml
現在我們可以使用 Kong 的代理 IP 地址進行外部訪問:
$ curl -i $PROXY_IP/actuator/health
HTTP/1.1 200 OK
Content-Type: application/vnd.spring-boot.actuator.v3+json
Content-Length: 49
Connection: keep-alive
X-Kong-Upstream-Latency: 325
X-Kong-Proxy-Latency: 1
Via: kong/3.0.0
7. 演示速率限制器
我們設法在 Kubernetes 上部署了一個 Spring Boot 應用程序,並使用 Kong Ingress Controller 來提供對它的訪問。但 KIC 做的遠不止這些:身份驗證、負載平衡、監控、速率限制和其他功能。為了展示 Kong 的真正威力,我們將在我們的應用程序中實現一個簡單的速率限制器,將訪問限制為每分鐘僅 5 個請求。為此,我們需要在 K8s 集群中創建一個名為KongClusterPlugin
的對象。 YAML 文件執行此操作:
apiVersion: configuration.konghq.com/v1
kind: KongClusterPlugin
metadata:
name: global-rate-limit
annotations:
kubernetes.io/ingress.class: kong
labels:
global: true
config:
minute: 5
policy: local
plugin: rate-limiting
插件配置允許我們為我們的應用程序指定額外的訪問規則,我們將對它的訪問限制為每分鐘五個請求。讓我們應用此配置並測試結果:
kubectl apply -f rate-limiter.yaml
為了測試它,我們可以在一分鐘內重複我們之前使用的 CURL 命令超過五次,我們會得到一個 429 錯誤:
curl -i $PROXY_IP/actuator/health
HTTP/1.1 429 Too Many Requests
Date: Sun, 06 Nov 2022 19:33:36 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
RateLimit-Reset: 24
Retry-After: 24
X-RateLimit-Remaining-Minute: 0
X-RateLimit-Limit-Minute: 5
RateLimit-Remaining: 0
RateLimit-Limit: 5
Content-Length: 41
X-Kong-Response-Latency: 0
Server: kong/3.0.0
{
"message":"API rate limit exceeded"
}
我們可以看到響應 HTTP 標頭通知客戶端有關速率限制。
8.清理資源
為了清理演示,我們需要按照 LIFO 順序刪除所有對象:
kubectl delete -f rate-limiter.yaml
kubectl delete -f ingress-rule.yaml
kubectl delete -f clusterIp.yaml
kubectl delete -f serviceDeployment.yaml
並停止 Minikube 集群:
minikube stop
9. 結論
在本文中,我們演示了使用 Kong Ingress Controller 來管理對部署在 K8s 集群上的 Spring Boot 應用程序的訪問。
與往常一樣,可以在 GitHub 上找到源代碼。