
一弹性扩缩容背景分析1背景弹性伸缩是根据用户的业务需求和策略自动 “调整” 其 “弹性资源” 的管理服务。通过弹性伸缩功能用户可设置定时、周期或监控策略恰到好处地增加或减少 “弹性资源”并完成实例配置保证业务平稳健康运行。在实际工作中我们常常需要做一些扩容缩容操作如电商平台在 618 和双十一搞秒杀活动。由于资源紧张、工作负载降低等都需要对服务实例数进行扩缩容操作。2K8s扩缩容分为两种在 k8s 中扩缩容分为两种Node 层面对 K8s 物理节点扩容和缩容根据业务规模实现物理节点自动扩缩容。阿里的ack可以实现Node方面的扩容但是得买人家的云服务加购一个扩缩容服务。底层用的是OpenStack。Pod 层面我们一般会使用 Deployment 中的 replicas 参数设置多个副本集来保证服务的高可用但是这是一个固定的值比如我们设置 10 个副本就会启动 10 个 pod 同时 running 来提供服务。如果这个服务平时流量很少的时候也是 10 个 pod 同时在 running而流量突然暴增时又可能出现 10 个 pod 不够用的情况。针对这种情况怎么办就需要扩容和缩容。二K8s当中自动伸缩方案一般情况下我们在生产当中使用的最多的就是HPA。毕竟cpu和内存使用率是最好的度量指标。1HPAHPA水平自动伸缩。通过此功能只需简单的配置便可以利用监控指标cpu 使用率、磁盘、自定义的等自动的扩容或缩容服务中 Pod 数量当业务需求增加时系统将无缝地自动增加适量 pod 容器提高系统稳定性。要想实现自动扩容需要先考虑如下几点1通过哪些指标决定扩容缩容HPA v1 版本只能基于 CPU 使用率来进行自动扩容但是并非所有的系统都可以仅依靠 CPU 或者 Memory 指标来扩容对于大多数 Web 应用的后端来说基于每秒的请求数量进行弹性伸缩来处理突发流量会更加的靠谱所以对于一个自动扩容缩容系统来说我们不能局限于 CPU、Memory 基础监控数据每秒请求数 RPS 等自定义指标也是十分重要。HPA v2 版本可以根据自定义的指标进行自动扩容。hpa v2 可以基于内存和自定义的指标做扩容和缩容。2如何采集资源指标如果我们的系统默认依赖 Prometheus自定义的 Metrics 指标则可以从各种数据源或者 exporter 中获取基于拉模型的 Prometheus 会定期从数据源中拉取数据。也可以基于 metrics-server 自动获取节点和 pod 的资源指标。3如何实现自动扩缩容HPA controller 已实现简单的自动扩缩容逻辑。默认每 30 秒检测一次指标当检测到配置的 HPA 目标值时计算预期副本数并执行扩缩容操作。为避免过于频繁默认 5 分钟内未重新扩缩容才会触发。HPA 算法较保守可能不适用于部分场景。例如快速流量突发时若处于 5 分钟 HPA 稳定期可能导致无法扩容。2KPAKPA 基于请求数对 Pod 实现自动扩缩容其主要限制是不支持基于 CPU 的自动扩缩容。根据并发请求数实现自动扩缩容设置扩缩容边界实现自动扩缩容扩缩容边界指应用程序提供服务的最小和最大 Pod 数量。通过设置应用程序提供服务的最小和最大 Pod 数量实现自动扩缩容。相比 HPAKPA 会考虑更多的场景其中一个比较重要的是流量突发的时候。3VPAKubernetes VPAVertical Pod Autoscaler垂直 Pod 自动扩缩容VPA 会基于 Pod 的资源使用情况自动为集群设置资源占用的限制从而让集群将 Pod 调度到有足够资源的最佳节点上。VPA 也会保持最初容器定义中资源 request 和 limit 的占比。它会根据容器资源使用率自动设置 pod 的 CPU 和内存的 requests从而允许在节点上进行适当的调度以便为每个 Pod 提供适当的可用的节点。它既可以缩小过度请求资源的容器也可以根据其使用情况随时提升资源不足的容量。三基于HPA的CPU指标实现Pod的自动伸缩HPAHorizontal Pod AutoscalerPod 水平自动伸缩基于 CPU 利用率自动扩缩容 Deployment 中的 Pod 数量也支持自定义指标。不适用于无法缩放的对象DaemonSets。无状态副本集Deployment有状态副本集StatefulSet。由Kubernetes API 资源和控制器实现控制器定期获取平均 CPU 利用率与目标值对比后调整副本数。1HPA工作原理1指标从哪里来从 K8s 1.8 版本开始CPU、内存等资源的 metrics 信息可通过Metrics API获取用户可直接获取这些 metrics 信息如通过kubectl top命令HPA 会使用这些 metrics 信息实现动态伸缩2Metrics serverMetrics server 是 K8s 集群资源使用情况的聚合器。从 1.8 版本开始Metrics server 可通过 yaml 文件的方式进行部署。Metrics server 收集所有 node 节点的 metrics 信息。3HPA 如何运作HPA 的实现是一个控制循环由 controller manager 的--horizontal-pod-autoscaler-sync-period参数指定周期默认值为 15 秒。每个周期内controller manager 根据每个HorizontalPodAutoscaler定义中指定的指标查询资源利用率。controller manager 可从 resource metrics APIPod 资源指标和 custom metrics API自定义指标获取指标。kubectl top nodes 可以查看Node资源指标同样kubectl top pods podname查看。Metric Server就是提供这个命令支撑的。然后通过现有 pods 的 CPU 使用率的平均值计算方式是最近的 pod 使用量最近一分钟的平均值从 metrics-server 中获得除以设定的每个 Pod 的 CPU 使用率限额跟目标使用率进行比较并且在扩容时还要遵循预先设定的副本数限制MinReplicas Replicas MaxReplicas。计算扩容后 Pod 的个数sum (最近一分钟内某个 Pod 的 CPU 使用率的平均值)/CPU 使用上限的整数 1。4HPA 工作流程创建 HPA 资源设定目标 CPU 使用率限额以及最大、最小实例数。收集一组中PodSelector每个 Pod 最近一分钟内的 CPU 使用率并计算平均值。读取 HPA 中设定的 CPU 使用限额。计算平均值之和 / 限额求出目标调整的实例个数。目标调整的实例数不能超过 1 中设定的最大、最小实例数如果没有超过则扩容。超过则扩容至最大的实例个数。回到 2不断循环。5核心计算简化目标实例数 平均 CPU 使用率 / 目标 CPU 使用率限额最终实例数会被钳制在最小实例数与最大实例数之间。2创建数据采集组件MetricServermetrics-server 是集群范围内的资源数据集和工具仅用于显示数据不提供数据存储服务核心聚焦于资源度量 API 的实现如 CPU、文件描述符、内存、请求延时等指标。它收集数据供 Kubernetesk8s集群内部组件使用例如 kubectl、HPA、调度器scheduler等。我们之前已经创建过了。查看一下。[rootk8s-node1 ~]# kubectl get pods -n kube-system -w NAME READY STATUS RESTARTS AGE coredns-75944bc9b-w9p2v 1/1 Running 6 (87s ago) 14d coredns-75944bc9b-zxrsd 1/1 Running 12 (83s ago) 36d etcd-k8s-node1 1/1 Running 33 (93s ago) 189d kube-apiserver-k8s-node1 1/1 Running 10 (93s ago) 26d kube-controller-manager-k8s-node1 1/1 Running 35 (93s ago) 189d kube-proxy-cgn9t 1/1 Running 32 (83s ago) 189d kube-proxy-jxkfh 1/1 Running 33 (93s ago) 189d kube-proxy-qdp9p 1/1 Running 33 (86s ago) 189d kube-proxy-vhhhs 1/1 Running 19 (76s ago) 58d kube-scheduler-k8s-node1 1/1 Running 35 (93s ago) 189d metrics-server-589dbffcf9-h54f7 0/1 Running 10 (82s ago) 14d tigera-operator-5d6845b496-rdbg2 1/1 Running 25 (83s ago) 36d metrics-server-589dbffcf9-h54f7 1/1 Running 10 (85s ago) 14d我们确实已经成功部署过了。3创建测试PodapiVersion: apps/v1 kind: Deployment metadata: name: hpatest spec: replicas: 1 selector: matchLabels: app: hpatest template: metadata: labels: app: hpatest spec: containers: - name: hpatest image: nginx imagePullPolicy: IfNotPresent command: [/bin/sh] args: [-c, /usr/sbin/nginx; while true; do echo hostname -I /usr/share/nginx/html/index.html; sleep 120; done] ports: - containerPort: 80 resources: limits: cpu: 500m requests: cpu: 200m --- apiVersion: v1 kind: Service metadata: name: hpatest-svc spec: selector: app: hpatest ports: - port: 80 targetPort: 80 protocol: TCP4顺便验证一个问题Node节点上访问svc的name:80是访问不通的因为Node上没有在host中配置coredns的解析地址。Pod中curl name:80直接就通了因为Pod创建的时候内部就植入了coredns的ip地址。[rootk8s-node1 test]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE hpatest-svc ClusterIP 10.102.178.236 none 80/TCP 9s kubernetes ClusterIP 10.96.0.1 none 443/TCP 189d new-nginx ClusterIP 10.109.4.182 none 80/TCP 5d15h nginx NodePort 10.105.226.103 none 80:30010/TCP 13d old-nginx ClusterIP 10.96.83.158 none 80/TCP 5d15h readiness-http NodePort 10.96.106.97 none 80:30080/TCP 16d tomcat ClusterIP 10.99.11.198 none 8080/TCP 6d19h tomcat-https ClusterIP 10.108.91.114 none 8080/TCP 5d17h [rootk8s-node1 test]# curl 10.102.178.236:80 !DOCTYPE html html head titleWelcome to nginx!/title style html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } /style /head body h1Welcome to nginx!/h1 pIf you see this page, the nginx web server is successfully installed and working. Further configuration is required./p pFor online documentation and support please refer to a hrefhttp://nginx.org/nginx.org/a.br/ Commercial support is available at a hrefhttp://nginx.com/nginx.com/a./p pemThank you for using nginx./em/p /body /html [rootk8s-node1 test]# curl hpatest-svc curl: (6) Could not resolve host: hpatest-svc; Unknown error [rootk8s-node1 test]# curl hpatest-svc curl: (6) Could not resolve host: hpatest-svc; Unknown error [rootk8s-node1 test]# kubectl exec -it my-nginx-654f997cd5-jtf5q -- bash rootmy-nginx-654f997cd5-jtf5q:/# curl hpatest-svc !DOCTYPE html html head titleWelcome to nginx!/title style html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } /style /head body h1Welcome to nginx!/h1 pIf you see this page, the nginx web server is successfully installed and working. Further configuration is required./p pFor online documentation and support please refer to a hrefhttp://nginx.org/nginx.org/a.br/ Commercial support is available at a hrefhttp://nginx.com/nginx.com/a./p pemThank you for using nginx./em/p /body /html rootmy-nginx-654f997cd5-jtf5q:/#5创建HPAWeb 服务正在运行使用kubectl autoscale创建自动缩放器实现对 Web 这个 deployment 创建的 pod 自动扩缩容。下面的命令将会创建一个 HPAHPA 将会根据 CPU、内存等资源指标增加或减少副本数创建一个可以实现如下目的的 hpa让副本数维持在 1-10 个之间这里副本数指的是通过 deployment 部署的 pod 的副本数将所有 Pod 的平均 CPU 使用率维持在 50%通过kubectl top pods看到的每个 pod 如果是 200 毫核这意味着平均 CPU 利用率为 100 毫核创建这种资源可以使用命令但是更推荐使用yaml资源文件。可以留痕。1查看当前pod的资源利用率[rootk8s-node1 test]# kubectl top pod hpatest-68d7ccdc85-p672c NAME CPU(cores) MEMORY(bytes) hpatest-68d7ccdc85-p672c 0m 2Mi2定义Hpa资源文件apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: hpatest spec: minReplicas: 1 maxReplicas: 10 scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: hpatest metrics: - type: Resource resource: name: cpu target: averageUtilization: 50 type: Utilization3压测查看扩容状态四基于HPA的内存指标实现Pod的扩缩容1创建测试PodapiVersion: apps/v1 kind: Deployment metadata: name: nginx-hpa spec: selector: matchLabels: app: nginx replicas: 1 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest imagePullPolicy: IfNotPresent ports: - containerPort: 80 name: http protocol: TCP resources: requests: cpu: 0.01 memory: 25Mi limits: cpu: 0.05 memory: 60Mi --- apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: selector: app: nginx type: NodePort ports: - name: http protocol: TCP port: 80 targetPort: 802创建HPAapiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: nginx-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx-hpa minReplicas: 1 maxReplicas: 10 metrics: - type: Resource resource: name: memory target: type: Utilization averageUtilization: 603同时监控CPU和内存的。apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: nginx-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx-hpa minReplicas: 1 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 60这个也有 3 种Utilization使用率百分比你现在用的CPU 50% → 超过就扩。AverageValue平均值比如 平均每个 Pod 500m CPU不是百分比是绝对值Value单值极少用。Utilization 百分比的分母永远是 requests不是 limits