Kong Ingress Controller与Spring Boot

2025/03/22

1. 概述

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环境可以保护我们的应用程序免受许多此类威胁,但我们仍需要采取一些措施来确保应用程序的安全,其中一项措施是部署入口控制器并设置其对应用程序的访问规则。

入口是一个对象,它通过向已部署的应用程序公开HTTP/HTTPS路由并对其强制执行访问规则来管理对K8s集群及其上部署的应用程序的外部访问。为了公开应用程序以允许外部访问,我们需要定义入口规则并使用入口控制器,这是一种专门的反向代理和负载均衡器。通常,入口控制器由第三方公司提供,功能各不相同,例如本文中使用的Kong Ingress Controller

3. 设置环境

为了演示如何在Spring Boot应用程序中使用Kong Ingress Controller(KIC),我们需要访问K8s集群,这样我们就可以使用完整的Kubernetes、本地安装或云提供的,或者使用Minikube开发我们的示例应用程序。启动K8s环境后,我们需要在集群上部署Kong Ingress Controller。Kong公开了一个外部IP,我们需要使用该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 target/*.jar

为了测试该应用程序,我们需要打开另一个终端并输入此命令:

curl -i http://localhost:8080/actuator/health

响应必须是应用程序的健康状态,由Actuator提供:

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

插件配置允许我们为应用程序指定额外的访问规则,并且我们将访问限制为每分钟5个请求。让我们应用此配置并测试结果:

kubectl apply -f rate-limiter.yaml

为了测试它,我们可以在一分钟内重复我们之前使用的CURL命令超过5次,我们就会收到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. 清理资源

为了清理演示,我们需要按后进先出的顺序删除所有对象:

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应用程序的访问。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章