博客 | NGINX

NGINX 教程: 通过自动扩展减少 Kubernetes 延迟

Daniele Polencic 缩略图
丹尼尔·波伦契奇
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 控制器 pod。

要运行本教程,您需要一台具有以下配置的机器:

  • 2 个或更多 CPU
  • 2 GB 可用内存
  • 20 GB 可用磁盘空间
  • 互联网连接
  • 容器或虚拟机管理器,例如 Docker、Hyperkit、Hyper‑V、KVM、Parallels、Podman、VirtualBox 或 VMware Fusion/Workstation
  • minikube安装
  • 安装Helm
  • 允许您启动浏览器窗口的配置。 如果不可能的话,您需要弄清楚如何通过浏览器获取相关服务。

为了充分利用实验室和教程,我们建议您在开始之前:

本教程使用了以下技术:

每个挑战的说明都包括用于配置应用程序的 YAML 文件的完整文本。 您也可以从我们的GitHub repo复制文本。 每个 YAML 文件的文本都附带有 GitHub 链接。

本教程包括四个挑战:

  1. 在 Kubernetes 集群上配置一个简单的应用程序
  2. 使用 NGINX Ingress Controller 将流量路由到应用程序
  3. 生成和监控流量
  4. 自动缩放 NGINX 入口控制器

挑战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 复制)。 它定义了具有单个副本和服务的部署。

    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 
    
  2. 部署应用程序:

    $ kubectl apply -f 1-deployment.yaml deployment.apps/podinfo created 
    service/podinfo created
    
  3. 确认 Podinfo pod 已部署,如STATUS列中的值Running所示。

    $ kubectl get podsNAME                       READY   STATUS   RESTARTS   AGE 
    podinfo-5d76864686-rd2s5   1/1     Running  0          3m38s
    
  4. 在浏览器中打开 Podinfo。 podinfo 页面的问候语表明 Podinfo 正在运行。

    $ minikube service podinfo
    

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

在这个挑战中,您将部署 NGINX Ingress Controller并将其配置为将流量路由到 Podinfo 应用程序

部署 NGINX Ingress 控制器

安装 NGINX Ingress Controller 最快的方法是使用Helm

  1. 将 NGINX 存储库添加到 Helm:

    $ helm repo add nginx-stable https://helm.nginx.com/stable 
    
  2. 下载并安装基于 NGINX 开源的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.
    
  3. 确认 NGINX Ingress Controller pod 已部署,如STATUS列中的Running值所示(为了便于阅读,输出分布在两行)。

    $ 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 
    
  2. 部署 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 开源模型的 8 个指标和基于 NGINX Plus模型的 80 多个指标。

  1. 获取 NGINX Ingress Controller pod 的 IP 地址,以便查询其指标列表。 该地址出现在IP字段中,如下所示172.17.0.4。 (为了易读,省略了RESTARTSAGE列,并将输出分布在两行。)

    $ 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>
    
  2. 在 Kubernetes 集群内的主机上创建一个带有 shell 的临时BusyBox pod:

    $ kubectl run -ti --rm=true busybox --image=busyboxIf you don't see a command prompt, try pressing enter. 
    / # 
    
  3. 列出 NGINX Ingress Controller 生成的指标,并验证它是否包含nginx_connections_active 。 为了 <IP 地址> 替换步骤 1 中的值。

    /# wget -qO- <IP_address>:9113/metrics
    
  4. 退出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
    
  2. 下载并安装 Prometheus:

    $ helm install prometheus prometheus-community/prometheus \ 
    --set server.service.type=NodePort --set server.service.nodePort=30010
    
  3. 验证安装,通常需要 60 秒才能完成。 在下面的示例输出中,验证命令在helm install命令之后仅运行了几秒钟,因此我们看到安装正在进行中,并且某些 Prometheus pod 的STATUS字段报告了ContainerCreating 。 当所有 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
    
  4. 打开 Prometheus。 在 minikube 环境中,运行以下命令,它将在您的默认浏览器中打开 Prometheus 仪表板。

    $ minikube service prometheus-server
    

    如下页面确认服务器正在运行。

  5. 在搜索栏中输入nginx_ingress_nginx_connections_active以查看活动连接指标的当前值。 您会看到一个活动连接,这是有道理的,因为您已经部署了一个 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 
    
  2. 部署 Locust:

    $ kubectl apply -f 3-locust.yaml configmap/locust-script created 
    deployment.apps/locust created 
    service/locust created 
    

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

  1. 在浏览器中打开 Locust。

    $ minikube service locust
    

  2. 在字段中输入以下值:

    • 用户数量– 1000
    • 生成率— 10
    • 主机– http://main-nginx-ingress
  3. 单击“开始群集”按钮将流量发送到 Podinfo 应用程序。

  4. 返回 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 入口控制器

在最后的挑战中,您将构建一个随着流量增加而自动扩展资源的配置。 本教程使用 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 
    
  2. 安装 KEDA:

    $ helm install keda kedacore/keda NAME: keda 
    NAMESPACE: default 
    STATUS: deployed 
    REVISION: 1 
    TEST SUITE: None
    
  3. 验证 KEDA 是否作为两个 pod 运行。 (为了易读, NAME列中的某些值被缩短了。 此外,省略了RESTARTS列;该值为0适用于所有 Pod。)

    $ 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 从单个 Pod 扩缩至最多 20 个 Pod

执行以下步骤:

  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" 
    
  2. 部署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 Ingress Controller 与 NGINX Plus 和 NGINX App Protect,请立即开始30 天免费试用联系我们讨论您的用例

要使用 NGINX 开源尝试 NGINX Ingress Controller,您可以获取发布源代码,或从DockerHub下载预构建的容器。


“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”