注:本教程是 Microservices June 2022 微服务之月项目第一单元“为高流量网站建构 Kubernetes 集群”的配套实验手册,您可点此报名参与这一免费线上教学项目以获取更多学习资源。
- 第一单元:通过自动扩展减少 Kubernetes 延迟(本文)
- 第二单元:通过速率限制保护 Kubernetes API
- 第三单元:通过灰度部署改善正常运行时间和弹性
- 第四单元:保护 Kubernetes 应用免遭 SQL 注入攻击
您的企业在 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 需在可以启动浏览器窗口的台式/笔记本电脑上运行。如果您所处的环境做不到这一点,那么您需要解决如何通过浏览器访问服务的问题。
为了充分利用实验和教程,我们建议在您开始实验之前:
-
观看直播回放
-
观看答疑课视频回放
本教程使用了以下技术:
本教程涉及四个挑战:
- 在 Kubernetes 集群上配置简单的应用
- 使用 NGINX Ingress Controller 将流量路由到 Podinfo 应用
- 生成和监控流量
- 自动扩展 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-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
-
部署应用:
$ kubectl apply -f 1-deployment.yaml deployment.apps/podinfo created service/podinfo created
-
确认 Podinfo pod 已经部署成功,如
STATUS
列中的值Running
所示。$ kubectl get pods NAME READY STATUS RESTARTS AGE podinfo-5d76864686-rd2s5 1/1 Running 0 3m38s
-
使用
minikube
service
podinfo
在浏览器中打开 Podinfo。下一页表示 Podinfo 正在运行。
挑战 2:使用 NGINX Ingress Controller 将流量路由到 Podinfo 应用
在这项挑战中,您需要部署 NGINX Ingress Controller,并将其配置为将流量路由到 Podinfo 应用。
部署 NGINX Ingress Controller
安装 NGINX NGINX Ingress Controller 最快的方法是使用 Helm。
-
将 NGINX 仓库添加到 Helm:
$ helm repo add nginx-stable https://helm.nginx.com/stable
-
下载并安装基于 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.
-
确认 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
将流量路由到您的应用
-
使用您选择的文本编辑器,创建一个名为 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
-
部署 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 多个指标。
-
获取 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>
-
在 Kubernetes 集群内的主机上创建一个带 shell 的临时 pod:
$ kubectl run -ti --rm=true busybox --image=busybox If you don't see a command prompt, try pressing enter. / #
-
列出 NGINX Ingress Controller 生成的指标,并验证其是否包含
nginx_connections_active
。对于<IP_address>
,替换步骤 1 中的值。/# wget -qO- <IP_address>:9113/metrics
-
退出 shell,返回 Kubernetes 服务器。
/# exit
部署 Prometheus
现在您已知道 NGINX Ingress Controller 跟踪 nginx_connections_active
,接下来您需要借助工具来收集 (“scrape”) 该指标 —— 本教程中使用的是 Prometheus。
对于 NGINX Ingress Controller,Helm 是安装 Prometheus 最快的方式。
-
将 Prometheus 仓库添加到 Helm:
$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
-
下载并安装 Prometheus:
$ helm install prometheus prometheus-community/prometheus \ --set server.service.type=NodePort --set server.service.nodePort=30010
-
验证安装,通常需要 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
-
打开 Prometheus。在 minikube 环境中,这是通过
$ minikube service prometheus-server
完成的,它会在默认浏览器中打开 Prometheus 仪表盘。一个类似以下截图的页面确认服务器正在工作。
-
在搜索栏中输入
nginx_ingress_nginx_connections_active
,查看当前活动连接指标的值。因为您部署了一个 NGINX Ingress Controller pod,所以您会看到一个活动连接,这是正常的。
安装 Locust
在下一节中,您将使用开源负载测试工具 Locust 模拟流量激增,以便观察 NGINX Ingress Controller 在 Prometheus 中的性能。现在开始部署 Locust。
-
使用您选择的文本编辑器,创建一个名为 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
-
部署 Locust:
$ kubectl apply -f 3-locust.yaml configmap/locust-script created deployment.apps/locust created service/locust created
模拟流量激增并观察其对性能的影响
-
使用
$ minikube service locust
在浏览器中打开 Locust。
-
在以下字段中输入以下值:
- Number of users – 1000
- Spawn rate – 10
- Host – http://main-nginx-ingress
-
点击 Start swarming 按钮,将流量发送到 Podinfo 应用。
-
返回到 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。
-
将 KEDA 添加到 Helm 仓库中:
$ helm repo add kedacore https://kedacore.github.io/charts "kedacore" has been added to your repositories
-
安装 KEDA:
$ helm install keda kedacore/keda NAME: keda NAMESPACE: default STATUS: deployed REVISION: 1 TEST SUITE: None
-
验证 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
-
使用您选择的文本编辑器,创建一个名为 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"
-
部署
ScaledObject
:$ kubectl apply -f 4-scaled-object.yaml scaledobject.keda.sh/nginx-scale created
模拟流量激增并观察自动扩展对性能的影响
为了真正测试自动化的有效性,您需要将连接数翻倍(与挑战 3 相比)。
-
返回到浏览器中的 Locust 服务器。在以下字段中输入以下值,然后点击 Start swarming 按钮:
- Number of users – 2000
- Spawn rate – 10
- Host – http://main-nginx-ingress
-
返回到 Prometheus 和 Locust 仪表盘。该 Prometheus 图下的粉色框展示了 NGINX Ingress Controller pod 增减的数量。
手动检查 KEDA HPA
-
切换回您的终端,并手动检查 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_dropped
( NGINX Plus 中提供)可以跟踪那些被丢弃的客户端连接。
如欲继续深入了解和本实验相关的知识技能,您可以加入到 Microservices June 2022 微服务之月项目中来,并继续浏览本项目第一单元“为高流量网站建构 Kubernetes 集群” 的其他学习资源。
如欲试用适用于 Kubernetes 且基于 NGINX Plus 的 NGINX Ingress Controller 和 NGINX App Protect,请立即下载 30 天免费试用版或者 联系我们讨论您的用例。
如欲试用 NGINX 开源版 NGINX Ingress Controller,您可以获取源代码进行编译,或者从 DockerHub 下载预构建的容器。