1. 概述
Kubernetes (K8s) 是一種編排器,它自動化了軟件開發和部署,並且是當今流行的 API 託管方案,可在本地部署或雲服務(如 Google Cloud Kubernetes Service (GKS) 或 Amazon Elastic Kubernetes Service (EKS))上運行。另一方面,Spring 已經成為最流行的 Java 框架之一。
在本教程中,我們將演示如何設置一個受保護的環境,以便在 Kubernetes 上部署我們的 Spring Boot 應用程序,使用 Kong Ingress Controller (KIC)。 此外,我們還將通過在不編寫任何代碼的情況下實施一個簡單的速率限制器來演示 KIC 的高級用法。
2. 增強的安全與訪問控制
現代應用程序部署,尤其是API,面臨諸多挑戰,例如:隱私法規(例如GDPR)、安全問題(DDoS攻擊)和使用跟蹤(API配額和速率限制等)。在這種情況下,現代應用程序和API需要針對這些挑戰採取額外的保護級別,例如防火牆、反向代理、速率限制器和相關服務。儘管K8s環境可以保護我們的應用程序免受許多威脅,但我們仍然需要採取一些措施來確保應用程序的安全。其中一種措施是在您的應用程序上部署Ingress控制器並設置其訪問規則。
Ingress是一個對象,用於管理對K8s集羣及其上部署的應用程序的外部訪問,通過將HTTP/HTTPS路由暴露到部署的應用程序中,並強制執行對該應用程序的訪問規則。為了將應用程序暴露出來以允許外部訪問,我們需要定義Ingress規則並使用Ingress控制器,Ingress控制器是一種專門的反向代理和負載均衡器。通常,Ingress控制器由第三方公司提供,功能各異,如Kong Ingress Controller,該文章中使用的就是該控制器。
3. 環境搭建
為了演示使用 Kong Ingress Controller (KIC) 與 Spring Boot 應用程序的結合,我們需要訪問一個 K8s 集羣,可以使用完整的本地部署 Kubernetes 或雲提供,或者使用 Minikube 開發我們的示例應用程序。 在啓動我們的 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 集羣。為了生成一個簡單的 HTTP 服務器應用程序,並且至少暴露一個 Web 資源,我們可以這樣做:
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 target/*.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-image6. 部署應用程序
現在是時候將應用程序部署到我們的 K8s 集羣上。我們需要創建一些 K8s 對象來部署和測試我們的應用程序,所有必需的文件都可以在演示倉庫中找到:
- 一個用於我們應用程序的部署對象,包含容器規範
- 一個定義服務,為我們的 Pod 分配集羣 IP 地址
- 一個 ingress 規則,使用 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 ,因為我們不使用鏡像註冊服務器,因此我們不想讓 Kubernetes 嘗試下載鏡像,而是使用其內部 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 集羣之外),我們需要創建 Ingress 規則,在本例中,我們將其指向路徑 /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.07. 演示速率限制器
我們成功地在 Kubernetes 上部署了一個 Spring Boot 應用程序,並使用 Kong Ingress Controller 提供對其訪問權限。但 KIC 遠不止於此:它還提供身份驗證、負載均衡、監控、速率限制以及其他功能。為了展示 Kong 的強大功能,我們將實現一個簡單的速率限制器,限制應用程序的訪問請求為每分鐘五次。為此,我們需要在我們的 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 stop9. 結論
在本文中,我們演示瞭如何使用 Kong Ingress Controller 管理部署在 K8s 集羣上的 Spring Boot 應用程序的訪問。