NGINX.COM
Web Server Load Balancing with NGINX Plus

注:本教程是 Microservices June 2022 微服务之月项目第一单元“为高流量网站建构 Kubernetes 集群”的配套实验手册,您可点此报名参与这一免费线上教学项目以获取更多学习资源。

您的企业在 Kubernetes 中搭建了一个应用,现在它吸引了越来越多的用户!访问者数量从每天只有几个增长到数百(有时甚至数千)。此时出现一个问题……急剧增加的流量引发瓶颈,导致客户访问延迟并出现超时错误。如果您无法改善访问体验,用户将停止使用您的应用。

作为一名 Kubernetes 工程师,只要您敢大胆尝试,就能化解危机。您可以部署 Ingress controller 来路由流量并设置自动扩展策略,从而根据流量的波动即时增减 Ingress controller pod 的数量。现在,您的 Ingress controller pod 可以无缝处理激增的流量了 ——“再见了,延迟!”不仅如此,这样做还能够在流量下降时减少 pod 的数量,从而节省资源 —— “你好,节省成本!”是不是自己都佩服自己?!

 

实验和教程概述

本文是“ Microservices June 2022 微服务之月”第一单元“为高流量网站构建 Kubernetes 集群”的实验配套文档,但您也可以在自己的环境中将其当作教程使用(您可以从我们的 GitHub 仓库中获取示例)。它演示了如何使用 NGINX Ingress Controller 来暴露应用,然后通过自动扩展 Ingress controller pod 来响应高并发流量。

为了完成实验,您需要一台具有以下配置的电脑:

  • 至少 2 个 CPU
  • 2GB 可用内存
  • 20GB 可用磁盘空间
  • 互联网连接
  • 容器或虚拟机管理器,例如 Docker、Hyperkit、Hyper-V、KVM、Parallels、Podman、VirtualBox 或 VMware Fusion/Workstation
  • 装有 minikube
  • 装有 Helm
  • 能够访问gcr.io, github, docker.io等镜像源站

注:本文提到的 minikube 需在可以启动浏览器窗口的台式/笔记本电脑上运行。如果您所处的环境做不到这一点,那么您需要解决如何通过浏览器访问服务的问题。

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

本教程使用了以下技术:

本教程涉及四个挑战:

  1. 在 Kubernetes 集群上配置简单的应用
  2. 使用 NGINX Ingress Controller 将流量路由到 Podinfo 应用
  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 文件,该文件应包含以下内容。它定义了带有一个副本和 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 
  2. 部署应用:

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

    $ kubectl get pods  
    NAME                       READY   STATUS   RESTARTS   AGE 
    podinfo-5d76864686-rd2s5   1/1     Running  0          3m38s
  4. 使用 minikube service podinfo 在浏览器中打开 Podinfo。下一页表示 Podinfo 正在运行。

 

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

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

部署 NGINX Ingress Controller

安装 NGINX 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 pods  
    NAME                                 READY   STATUS    RESTARTS   AGE 
    main-nginx-ingress-779b74bb8b-mtdkr  1/1     Running   0          18s 
    podinfo-5d76864686-fjncl             1/1     Running   0          2m36s

将流量路由到您的应用

  1. 使用您选择的文本编辑器,创建一个名为 2-ingress.yaml 的 YAML 文件,该文件应包含以下内容。它定义了将流量路由到 Podinfo 所需的 Ingress manifest。

    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:生成和监控流量

在这项挑战中,您可以在不同的流量负载下观察 NNGINX Ingress Controller 的性能。在开始之前,您需要列出 NGINX Ingress Controller 的可用指标部署 Prometheus,并安装 Locust。之后,您可以使用 Locust 模拟流量激增,并在 Prometheus 中跟踪其对性能的影响

正如您所发现的那样,Ingress controller 是一个常规的 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。(为方便阅读,输出结果分成了两行。)

    $ kubectl get pods -o wide 
    NAME                                  READY   STATUS    RESTARTS   AGE    ... 
    main-nginx-ingress-779b74bb8b-6hdwx   1/1     Running   0          3m43s  ...   
    podinfo-5d76864686-nl8ws              1/1     Running   0          5m49s  ... 
    
          ... IP           NODE       NOMINATED NODE   READINESS GATES 
          ... 172.17.0.4   minikube   <none>          <none> 
          ... 172.17.0.3   minikube   <none>          <none>
  2. 在 Kubernetes 集群内的主机上创建一个带 shell 的临时 pod:

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

    /# wget -qO- <IP_address>:9113/metrics
  4. 退出 shell,返回 Kubernetes 服务器。

    /# exit 

部署 Prometheus

现在您已知道 NGINX Ingress Controller 跟踪 nginx_connections_active,接下来您需要借助工具来收集 (“scrape”) 该指标 —— 本教程中使用的是 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 命令之后,验证命令只运行了几秒钟,我们可以看到安装正在进行中,其中 STATUS 字段中报告一些 Prometheus pod 正在 ContainerCreating。当所有 pod 的状态都为 Running 时,即表示安装完成。(为方便阅读,我们删除了输出结果中的 RESTARTS 列;所有 pod 的值都为 0。)

    $ kubectl get pods
    NAME                                            READY  STATUS             ...  AGE
    main-nginx-ingress-779b74bb8b-mtdkr             1/1    Running            ...  3m23s
    podinfo-5d76864686-fjncl                        1/1    Running            ...  5m41s
    prometheus-alertmanager-d6d94cf4b-85ww5         0/2    ContainerCreating  ...  7s 
    prometheus-kube-state-metrics-7cd8f95c7b-86hhs  0/1    Running            ...  7s 
    prometheus-node-exporter-gqxfz                  1/1    Running            ...  7s 
    prometheus-pushgateway-56745d8d8b-qnwcb         0/1    ContainerCreating  ...  7s 
    prometheus-server-b78c9449f-kwhzp               0/2    ContainerCreating  ...  7s 
    
  4. 打开 Prometheus。在 minikube 环境中,这是通过

    $ minikube service prometheus-server

    完成的,它会在默认浏览器中打开 Prometheus 仪表盘。一个类似以下截图的页面确认服务器正在工作。

  5. 在搜索栏中输入 nginx_ingress_nginx_connections_active,查看当前活动连接指标的值。因为您部署了一个 NGINX Ingress Controller pod,所以您会看到一个活动连接,这是正常的。

安装 Locust

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

  1. 使用您选择的文本编辑器,创建一个名为 3-locust.yaml 的 YAML 文件,该文件应包含以下内容。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. 使用

    $ minikube service locust

    在浏览器中打开 Locust。

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

    • Number of users – 1000
    • Spawn rate – 10
    • Host – http://main-nginx-ingress
  3. 点击 Start swarming 按钮,将流量发送到 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 Ingress Controller

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

安装 KEDA

KEDA是 Kubernetes 事件驱动的自动扩展器,它集成了指标服务器(存储和转换 Kubernetes 指标的组件),可以直接使用来自 Prometheus(及其他工具)的指标。 它使用这些指标创建了 Horizontal Pod Autoscaler (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 运行。(为方便阅读,我们删除了输出结果中的 RESTARTS列;所有 pod 的值都为 0。)

    $ kubectl get pods 
    NAME                                             READY   STATUS    AGE 
    keda-operator-8644dcdb79-492x5                   1/1     Running   59s 
    keda-operator-metrics-apiserver-66d6c4454-dp6lq  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-8gzq2          2/2     Running   37m 
    prometheus-kube-state-metrics-7cd8f95c7b-9hsbm   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

创建自动扩展策略

现在我们来定义扩展参数,该参数将指示 NGINX Ingress Controller 如何使用 KEDA 对象 ScaledObject进行扩展。配置如下:

  • 基于 Prometheus 收集的 nginx_connections_active 指标的值触发自动扩展
  • 当每个现有 pod 达到 100 个活动连接时,部署一个新的 pod
  • 将 NGINX Ingress Controller pod 从一个 pod 自动扩展到 20 个 pod
  1. 使用您选择的文本编辑器,创建一个名为 4-scaled-object.yaml 的 YAML 文件,该文件应包含以下内容。它定义了 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 服务器。在以下字段中输入以下值,然后点击 Start swarming 按钮:

  2. 返回到 Prometheus 和 Locust 仪表盘。该 Prometheus 图下的粉色框展示了 NGINX Ingress Controller pod 增减的数量。

    手动检查 KEDA HPA

  3. 切换回您的终端,并手动检查 KEDA HPA。输出结果中的 REPLICAS 字段显示了当前部署的 pod 副本的数量。(为方便阅读,输出结果分成了两行。)

    $ kubectl get hpa  
    
    NAME                   REFERENCE                       TARGETS            ...    
    keda-hpa-nginx-scale   Deployment/main-nginx-ingress   101500m/100 (avg)  ...
    
          ... MINPODS   MAXPODS   REPLICAS   AGE
          ... 1         20        10         2m45s
    

 

后续步骤

如果您仅根据活动连接的数量自动扩展,那么可能会存在限制。如果(即使在扩展后)NGINX Ingress Controller 变得非常繁忙,以至于必须丢弃一些连接,自动扩展器会看到活动连接减少,并将其解释为请求减少了,因而减少副本数量。这可能会导致性能进一步下降,但利用指标组合可确保这种情况不会发生。举例来说,nginxplus_connections_droppedNGINX Plus 中提供)可以跟踪那些被丢弃的客户端连接。

如欲继续深入了解和本实验相关的知识技能,您可以加入到 Microservices June 2022 微服务之月项目中来,并继续浏览本项目第一单元“为高流量网站建构 Kubernetes 集群” 的其他学习资源。

如欲试用适用于 Kubernetes 且基于 NGINX Plus 的 NGINX Ingress Controller 和 NGINX App Protect,请立即下载 30 天免费试用版或者 联系我们讨论您的用例

如欲试用 NGINX 开源版 NGINX Ingress Controller,您可以获取源代码进行编译,或者从 DockerHub 下载预构建的容器。

Hero image
Kubernetes:
从测试到生产

通过多种流量管理工具提升弹性、可视性和安全性

关于作者

Daniele Polencic

Managing Director

关于作者

NGINX 中文社区官方团队

NGINX

关于 F5 NGINX

F5, Inc. 是备受欢迎的开源软件 NGINX 背后的商业公司。我们为现代应用的开发和交付提供一整套技术。我们的联合解决方案弥合了 NetOps 和 DevOps 之间的横沟,提供从代码到用户的多云应用服务。访问 nginx-cn.net 了解更多相关信息。