NGINX教程:通过自动扩缩容降低Kubernetes延迟

NGINX | 2022年3月15日

本教程是将以下内容中的概念付诸实践的四篇教程之一:2022年3月微服务专题:Kubernetes网络:

想了解如何使用NGINX支持更多Kubernetes网络用例的详细指南?下载免费电子书《使用NGINX管理Kubernetes流量:实用指南》。

贵组织在Kubernetes中构建了一款应用,现在越来越受欢迎!每日访问量从寥寥数人增至数百人,有时甚至达到数千人。但问题也随之而来……流量增长遭遇瓶颈,导致客户访问时出现延迟和超时。如果无法改善体验,用户将不再使用这款应用。

您勇敢的Kubernetes工程师已经找到了解决方案。部署Ingress控制器来路由流量,并设置自动扩缩策略,使Ingress控制器Pod的数量能够根据流量波动即时增减。现在,Ingress控制器Pod可以从容应对流量激增,“延迟,再见!”,并在流量下降时缩容以节省资源,“成本节省,你好!”做得好!

实验与教程概述

本博客是“2022年3月微服务”第1单元实验的配套内容,主题为“面向高流量网站设计Kubernetes集群架构”,演示如何使用NGINX Ingress Controller公开应用,并根据高流量自动扩缩Ingress Controller Pod。

要完成本教程,需要准备一台满足以下条件的计算机:

  • 2 个或更多 CPU
  • 2 GB可用内存
  • 20 GB可用磁盘空间
  • 互联网连接
  • 容器或虚拟机管理器,例如Docker、Hyperkit、Hyper‑V、KVM、Parallels、Podman、VirtualBox或VMware Fusion/Workstation
  • minikube 已安装
  • Helm 已安装
  • 一种可启动浏览器窗口的配置。如果无法启动,则需要确定如何通过浏览器访问相关服务。

为充分利用实验和教程,建议在开始前:

本教程使用以下技术:

每项挑战的说明均包含用于配置应用的YAML文件全文。也可以从我们的GitHub仓库复制这些内容。每个YAML文件的文本旁均提供GitHub链接。

本教程包含4项挑战:

  1. 在Kubernetes集群上配置简单应用
  2. 使用NGINX Ingress Controller将流量路由到应用
  3. 生成并监控流量
  4. 自动扩缩 NGINX Ingress Controller

挑战 1:在Kubernetes集群上配置一个简单应用

在本挑战中,您将创建minikube集群,并安装Podinfo作为示例应用。

创建Minikube集群

创建一个minikube集群。几秒钟后,系统会显示一条消息,确认部署成功。

$ minikube start 🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default 

安装Podinfo应用

Podinfo是一个“使用Go构建的Web应用,用于展示在Kubernetes中运行微服务的最佳实践”。由于它占用的资源较少,我们将其用作示例应用。

  1. 使用任意文本编辑器创建一个名为“1-deployment.yaml”的YAML文件,并添加以下内容(也可以从GitHub复制)。该文件定义了一个包含单个副本的Deployment和一个Service。
apiVersion: apps/v1 kind: Deployment 
metadata: 
  name: podinfo 
spec: 
  selector: 
    matchLabels: 
      app: podinfo 
  template: 
    metadata: 
      labels: 
        app: podinfo 
    spec: 
      containers: 
      - name: podinfo 
        image: stefanprodan/podinfo 
        ports: 
        - containerPort: 9898 
--- 
apiVersion: v1 
kind: Service 
metadata: 
  name: podinfo 
spec: 
  ports: 
    - port: 80 
      targetPort: 9898 
      nodePort: 30001 
  selector: 
    app: podinfo 
  type: LoadBalancer 
  1. 部署应用:
$ kubectl apply -f 1-deployment.yaml deployment.apps/podinfo created 
service/podinfo created
  1. 确认Podinfo Pod已部署,依据是Running值显示在STATUS列中。
$ kubectl get podsNAME                       READY   STATUS   RESTARTS   AGE 
podinfo-5d76864686-rd2s5   1/1     Running  0          3m38s
  1. 在浏览器中打开Podinfo。页面上的“greetings from podinfo”表示Podinfo正在运行。
$ minikube service podinfo

挑战2:使用NGINX Ingress Controller将流量路由到应用

在本挑战中,您将部署NGINX Ingress Controller,并将其配置为把流量路由到Podinfo应用。

部署NGINX Ingress Controller

安装NGINX Ingress Controller最快捷的方式是使用Helm。

  1. 将NGINX仓库添加到Helm:
$ helm repo add nginx-stable https://helm.nginx.com/stable 
  1. 下载并安装基于NGINX Open Source的NGINX Ingress Controller,该控制器由F5 NGINX维护。输出的最后一行用于确认安装成功。
$ helm install main nginx-stable/nginx-ingress \ --set controller.watchIngressWithoutClass=true \ --set controller.service.type=NodePort \ --set controller.service.httpPort.nodePort=30005 
NAME: main 
LAST DEPLOYED: Tue Mar 15 09:49:17 2022 
NAMESPACE: default 
STATUS: deployed 
REVISION: 1 
TEST SUITE: None 
NOTES: The NGINX Ingress Controller has been installed.
  1. 确认NGINX Ingress Controller Pod已部署,依据是Running值显示在STATUS列中(为便于阅读,输出分为两行显示)。
$ kubectl get podsNAME                                   READY   STATUS    ...
main-nginx-ingress-779b74bb8b-mtdkr    1/1     Running   ...
podinfo-5d76864686-fjncl               1/1     Running   ...

       ... RESTARTS   AGE
       ... 0          18s 
       ... 0        2m36s

将流量路由到您的应用

  1. 使用任意文本编辑器创建一个名为2-ingress.yaml的YAML文件,并填入以下内容(也可以从GitHub复制)。该文件定义了将流量路由到Podinfo所需的Ingress清单。
apiVersion: networking.k8s.io/v1 kind: Ingress 
metadata: 
  name: podinfo 
spec: 
  ingressClassName: nginx 
  rules: 
    - host: "example.com" 
      http: 
        paths: 
          - backend: 
              service: 
                name: podinfo 
                port: 
                  number: 80 
            path: / 
            pathType: Prefix 
  1. 部署Ingress资源:
$ kubectl apply -f 2-ingress.yaml ingress.networking.k8s.io/podinfo created 

挑战 3:生成并监控流量

在本挑战中,您将观察NGINX Ingress Controller在不同流量负载下的性能。准备工作包括:列出指标,即NGINX Ingress Controller提供的指标;部署Prometheus;以及安装Locust。然后,使用Locust模拟流量激增,并在Prometheus中跟踪其对性能的影响。

正如您已经了解到的,Ingress控制器是一个常规的Kubernetes Pod,其中包含一个反向代理(在本例中为NGINX)以及一些用于与Kubernetes集成的代码。如果应用收到大量流量,可能需要增加NGINX Ingress Controller Pod的副本数量,以避免NGINX Ingress Controller因负载过高而导致延迟。

列出可用指标

要确定何时扩缩容以及扩缩容的幅度,需要掌握有关NGINX Ingress Controller性能的准确信息。本教程使用NGINX的活动连接数指标(nginx_connections_active)来确定何时扩缩容。接下来,验证NGINX Ingress Controller是否跟踪该指标。

NGINX Ingress Controller可公开多个指标:本教程使用基于NGINX Open Source的模型,可公开8个指标;基于NGINX Plus的模型则可公开80多个指标。

  1. 获取NGINX Ingress Controller Pod的IP地址,以便查询其指标列表。该地址显示在IP字段中,此处为172.17.0.4。(为便于阅读,省略了RESTARTS和AGE列,并将输出分为两行显示。)
$ kubectl get pods -o wide NAME                                  READY   STATUS    ...
main-nginx-ingress-779b74bb8b-6hdwx   1/1     Running   ...
podinfo-5d76864686-nl8ws              1/1     Running   ...

    ... IP           NODE       NOMINATED NODE  READINESS GATES 
    ... 172.17.0.4   minikube   <none>          <none> 
    ... 172.17.0.3   minikube   <none>          <none>
  1. 在Kubernetes集群内的主机上创建一个带有shell的临时BusyBox Pod:
$ kubectl run -ti --rm=true busybox --image=busyboxIf you don't see a command prompt, try pressing enter. 
/ # 
  1. 列出NGINX Ingress Controller生成的指标,并确认其中包含nginx_connections_active。将<IP_address>替换为步骤1中获取的值。
/# wget -qO- <IP_address>:9113/metrics
  1. 退出shell,返回Kubernetes服务器。
/# exit 

部署Prometheus

现在,您已经知道NGINX Ingress Controller会跟踪nginx_connections_active指标,接下来需要使用工具来收集(“抓取”)这些指标。本教程使用Prometheus。

对于NGINX Ingress Controller,使用Helm可以快速安装Prometheus。

  1. 将Prometheus存储库添加到Helm:
$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
  1. 下载并安装Prometheus:
$ helm install prometheus prometheus-community/prometheus \ --set server.service.type=NodePort --set server.service.nodePort=30010
  1. 验证安装情况。安装通常最多需要60秒才能完成。在以下示例输出中,验证命令是在helm install命令运行几秒后执行的,因此可以看到安装仍在进行,部分Prometheus Pod的ContainerCreating状态显示在STATUS字段中。当所有Pod的状态均为Running时,安装即完成。(为便于阅读,输出分为两行显示。)
$ kubectl get podsNAME                                           READY  ...
main-nginx-ingress-779b74bb8b-mtdkr            1/1    ...
podinfo-5d76864686-fjncl                       1/1    ...
prometheus-alertmanager-d6d94cf4b-85ww5        0/2    ...
prometheus-kube-state-metrics-7cd8f95cb-86hhs  0/1    ...
prometheus-node-exporter-gqxfz                 1/1    ...
prometheus-pushgateway-56745d8d8b-qnwcb        0/1    ...
prometheus-server-b78c9449f-kwhzp              0/2    ...

      ... STATUS             RESTARTS  AGE 
      ... Running            0         3m23s 
      ... Running            0         5m41s 
      ... ContainerCreating  0         7s
      ... Running            0         7s
      ... Running            0         7s
      ... ContainerCreating  0         7s
      ... ContainerCreating  0         7s
  1. 打开Prometheus。在minikube环境中运行以下命令,即可在默认浏览器中打开Prometheus仪表板。
$ minikube service prometheus-server
  1. 如下所示的页面表示服务器运行正常。
  2. 在搜索栏中输入nginx_ingress_nginx_connections_active,查看活动连接指标的当前值。此时会看到1个活动连接,这是因为已部署1个NGINX Ingress Controller Pod。

安装Locust

在下一部分中,将使用Locust这一开源负载测试工具来模拟流量激增,以便在Prometheus中观察NGINX Ingress Controller的性能。现在部署Locust。

  1. 使用任意文本编辑器创建一个名为“3-locust.yaml”的YAML文件,并添加以下内容(也可以从GitHub复制)。Deployment和Service对象用于定义Locust Pod。ConfigMap对象用于定义一个名为“locustfile.py”的脚本,该脚本会生成发送到Pod的请求,并包含正确的标头。
apiVersion: v1 
kind: ConfigMap 
metadata: 
  name: locust-script 
data: 
  locustfile.py: |- 
    from locust import HttpUser, task, between 

    class QuickstartUser(HttpUser): 
        wait_time = between(0.7, 1.3) 

        @task 
        def hello_world(self): 
            self.client.get("/", headers={"Host": "example.com"}) 
--- 
apiVersion: apps/v1 
kind: Deployment 
metadata: 
  name: locust 
spec: 
  selector: 
    matchLabels: 
      app: locust 
  template: 
    metadata: 
      labels: 
        app: locust 
    spec: 
      containers: 
        - name: locust 
          image: locustio/locust 
          ports: 
            - containerPort: 8089 
          volumeMounts: 
            - mountPath: /home/locust 
              name: locust-script 
      volumes: 
        - name: locust-script 
          configMap: 
            name: locust-script 
--- 
apiVersion: v1 
kind: Service 
metadata: 
  name: locust 
spec: 
  ports: 
    - port: 8089 
      targetPort: 8089 
      nodePort: 30015 
  selector: 
    app: locust 
  type: LoadBalancer 
  1. 部署Locust:
$ kubectl apply -f 3-locust.yaml configmap/locust-script created 
deployment.apps/locust created 
service/locust created 

模拟流量激增并观察其对性能的影响

  1. 在浏览器中打开Locust。
$ minikube service locust
  1. 在各字段中输入以下值:
    • 用户数:1000
    • 生成速率:10
    • 主机:http://main-nginx-ingress
  2. 点击“开始群发流量”按钮,将流量发送到Podinfo应用。
  3. 返回Prometheus仪表板,查看NGINX Ingress Controller的响应情况。您可能需要重新查询nginx_ingress_nginx_connections_active,才能看到变化。如下方屏幕输出所示,随着大量连接建立,单个NGINX Ingress Controller Pod难以在不增加延迟的情况下处理增长的流量。Prometheus图表显示,每个NGINX Ingress Controller Pod约有100个活动连接时,延迟会开始激增。您可以根据此信息判断何时需要增加NGINX Ingress Controller Pod的数量,以避免延迟增加。

挑战 4:自动扩缩 NGINX Ingress Controller

在最后一项挑战中,您将构建一个配置,使资源能够随着流量增加而自动扩缩容。本教程使用KEDA实现自动扩缩容,因此首先需要安装KEDA并创建策略,定义何时以及如何进行扩缩容。与挑战3一样,随后使用Locust模拟流量激增,并使用Prometheus观察启用自动扩缩容后NGINX Ingress Controller的性能。

安装 KEDA

KEDA是一款Kubernetes事件驱动型自动扩缩器,集成了指标服务器(用于存储和转换Kubernetes指标的组件),并可直接使用Prometheus及其他工具中的指标。它使用这些指标创建水平Pod自动扩缩器(HPA),将Prometheus收集的指标接入并提供给Kubernetes。

与NGINX Ingress Controller和Prometheus一样,本教程使用Helm安装KEDA。

  1. 将KEDA添加到Helm仓库:
$ helm repo add kedacore https://kedacore.github.io/charts 
"kedacore" has been added to your repositories 
  1. 安装KEDA:
$ helm install keda kedacore/keda NAME: keda 
NAMESPACE: default 
STATUS: deployed 
REVISION: 1 
TEST SUITE: None
  1. 验证KEDA是否以两个Pod运行。(为便于阅读,NAME列中的部分值已缩短。此外,RESTARTS列已省略;所有Pod的该值均为0。)
$ kubectl get pods NAME                                    READY  STATUS     AGE 
keda-operator-8644dcdb79-492x5 1/1 Running 59s keda-operator-metrics-apiserver-66d... 1/1 Running 59s 
locust-77c699c94d-dvb5n                 1/1    Running  8m59s 
main-nginx-ingress-779b74bb8b-v7ggw     1/1    Running    48m 
podinfo-5d76864686-c98rb                1/1    Running    50m 
prometheus-alertmanager-d6d94cf4b-8...  2/2    Running    37m 
prometheus-kube-state-metrics-7cd8f...  1/1    Running    37m 
prometheus-node-exporter-j4qf4          1/1    Running    37m 
prometheus-pushgateway-56745d8d8b-9n4nl 1/1    Running    37m 
prometheus-server-b78c9449f-6ktn9       2/2    Running    37m

创建自动扩缩策略

现在,使用KEDA的ScaledObject自定义资源定义(CRD)来定义控制NGINX Ingress Controller扩缩容方式的参数。以下配置:

  • 根据Prometheus收集的nginx_connections_active指标值触发自动扩缩容
  • 当每个现有pod的活动连接数达到100时,部署一个新pod
  • 将NGINX Ingress Controller Pod从1个自动扩缩至最多20个

执行以下步骤:

  1. 使用您选择的文本编辑器创建一个名为4-scaled-object.yaml的YAML文件,并填入以下内容(也可以从GitHub复制)。该文件定义了一个KEDA ScaledObject。
apiVersion: keda.sh/v1alpha1 kind: ScaledObject 
metadata: 
 name: nginx-scale 
spec: 
 scaleTargetRef: 
   kind: Deployment 
   name: main-nginx-ingress 
minReplicaCount: 1 
maxReplicaCount: 20 
cooldownPeriod: 30 
pollingInterval: 1 
triggers: 
- type: prometheus 
  metadata: 
    serverAddress: http://prometheus-server 
    metricName: nginx_connections_active_keda 
    query: | 
      sum(avg_over_time(nginx_ingress_nginx_connections_active{app="main-nginx-ingress"}[1m])) 
    threshold: "100" 
  1. 部署ScaledObject:
$ kubectl apply -f 4-scaled-object.yaml scaledobject.keda.sh/nginx-scale created 

模拟流量激增并观察自动扩缩容对性能的影响

为了充分测试自动扩缩容的效果,将连接数增加到挑战 3 中的两倍。

  1. 在浏览器中返回Locust服务器。在各字段中输入以下值,然后点击“开始生成负载”按钮:
    • 用户数:2000
    • 生成速率:10
    • 主机:http://main-nginx-ingress
  2. 返回Prometheus和Locust仪表板。Prometheus图表下方的粉色框显示NGINX Ingress Controller Pod扩缩容时的数量变化。
  3. 切换回终端,手动检查KEDA HPA。输出中的REPLICAS字段显示当前已部署的Pod副本数。(为便于阅读,输出分为两行显示。)
$ kubectl get hpa
NAME                  REFERENCE                      ... 
keda-hpa-nginx-scale  Deployment/main-nginx-ingress  ... 

    ... TARGETS           MINPODS   MAXPODS   REPLICAS   AGE 
    ... 101500m/100 (avg) 1         20        10         2m45s

后续步骤

仅根据活动连接数进行自动扩缩容存在一个潜在限制。如果NGINX Ingress Controller负载过高,以至于即使扩容后仍不得不丢弃连接,自动扩缩容器会看到活动连接数减少,将其解读为请求量下降,并减少副本数。这可能导致性能进一步下降,但结合使用多项指标可以避免这种情况。例如,nginxplus_connections_dropped(适用于基于NGINX Plus的NGINX Ingress Controller)可跟踪这些被丢弃的客户端连接。

要试用搭配NGINX Plus和NGINX App Protect的NGINX Ingress Controller,请立即开始30天免费试用,或联系我们,讨论您的用例。

要试用搭配NGINX Open Source的NGINX Ingress Controller,可以获取发布版源代码,也可以从DockerHub下载预构建容器。


分享
标签: F5 NGINX, 2022, Tech

相关博客文章

NGINX Plus R26 正式发布
NGINX | 2022/02/15

NGINX Plus R26 正式发布

NGINX Plus R26通过缓存JSON Web密钥集加快JWT验证,并强化TLS握手,从而提升安全性。NGINX JavaScript的新功能包括增强对异步函数的支持,以及实现WebCrypto API。

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击
NGINX | 2022/02/10

使用NGINX App Protect DoS保护gRPC应用,抵御严重的DoS攻击

gRPC具备开发人员设计和部署现代应用所需的速度与灵活性,但其开放性也使其极易受到第7层DoS攻击。NGINX App Protect DoS可保护gRPC应用免受此类破坏性攻击。

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划
NGINX | 2021/09/13

Ingress Controller 选型指南(第 2 部分):风险与面向未来的规划

了解选择错误的Ingress控制器可能带来的风险,以及如何从关键方面着手,让您的选择更好地适应未来需求。

NGINX Plus R19 正式发布
NGINX | 2019/09/03

NGINX Plus R19 正式发布

NGINX Plus R19扩展了监控功能,不仅提供更多指标,还新增了指标分析方式;增加试运行模式,用于测试限速效果;增强键值存储,以支持IP地址范围;并使限速更加动态。

NGINX现已正式加入F5
NGINX | 2019/05/09

NGINX现已正式加入F5

NGINX现已正式成为F5的一部分。Gus Robertson现任F5 NGINX业务部门负责人。他阐述了两家公司在人才、文化和愿景方面融合的价值,以及双方将如何携手增强NGINX的开源产品和商业产品。

使用NGINX和NGINX Plus实现高性能缓存
NGINX | 2016/08/24

使用NGINX和NGINX Plus实现高性能缓存

我将介绍NGINX在内容缓存和性能方面的工作原理,并分享一些控制NGINX内容缓存方式的技巧。