# 自动伸缩
- Pod 的业务负载可能有时大、有时小,因此占用的 CPU、内存等资源量也会变化。
- 如果一直给 Pod 分配较多资源,则负载较低时, Pod 会浪费资源。
- 如果一直给 Pod 分配较少资源,则负载较高时, Pod 会资源不足,导致处理速度慢,甚至服务中断。
- 为了自动调整 Pod 数量、资源配额,k8s 提供了 HPA、VPA、CA 等功能。
- 在离线混合部署:在线业务一般运行时间长,比如需要 24 小时供用户使用。但是存在低峰期,比如晚上的负载较低。此时可在同一服务器上运行一些耗时短的离线业务,比如 k8s Job ,从而提高服务器的 CPU、内存等资源的利用率。
# HPA
:横向的 Pod 自动伸缩(Horizontal Pod Autoscaling),即自动增减 Pod 数量。
用于控制 Deployment、StatefulSet 类型的 Pod 数量,相当于自动执行
kubectl scale
命令。例如当全部 Pod 的平均 CPU 使用量高于期望值时,自动增加 Pod 数量,从而降低平均 CPU 使用量。- DaemonSet 不支持改变 Pod 数量,因此不支持 HPA 。
原理:
- 用户创建一个 HPA 对象,监控 Pod 的一些 metrics 指标。
- kube-controller-manager 执行 HPA 伸缩规则,自动调整 Pod 的 replicas 数量,使得 metrics 指标接近期望值。算法为:
rate = metrics_当前值 / metrics_期望值 replicas_期望值 = ceil(replicas_当前值 * rate ) # ceil 即向上取整
- kube-controller-manager 默认每隔
--horizontal-pod-autoscaler-sync-period=15
秒执行一次 HPA 。 - 如果 rate 减去 1 的差值小于
--horizontal-pod-autoscaler-tolerance=0.1
,则不会向上取整到 2 ,避免 replicas 抖动。
- kube-controller-manager 默认每隔
一个 HPA 对象的配置示例:
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: test-hpa namespace: default spec: maxReplicas: 10 # Pod 自动伸缩的最大数量 minReplicas: 1 # Pod 自动伸缩的最小数量 metrics: # 选择监控指标 - resource: name: cpu target: # 期望值,这里为全部 Pod 的平均 cpu 使用量 averageValue: 100m type: AverageValue - resource: name: memory target: # 期望值,这里为全部 Pod 的平均 memory 使用率,即实际使用量占 requests 的百分比 averageUtilization: 80 type: Utilization type: Resource # - containerResource: # 只监控某个容器的资源使用率,而不考虑 Pod 中其它容器 # name: cpu # container: container-0 # target: # type: Utilization # averageUtilization: 80 scaleTargetRef: # 选择要控制的 Pod apiVersion: apps/v1 kind: Deployment name: nginx # behavior: # 配置 HPA 的行为策略,主要用于避免 replicas 抖动 # scaleDown: # 减少 replicas 时的策略 # stabilizationWindowSeconds: 300 # 如果连续 n 秒都想减少 replicas ,才允许减少。实际算法:统计最近 n 秒内 desiredReplicas 的最大值,作为 scaleDown 的依据 # policies: # - type: Percent # value: 100 # periodSeconds: 15 # 每次减少 replicas 时,限制在 15s 内最多减少 100% 的幅度 # selectPolicy: Max # Max 表示,存在多个策略时,会采用使得 replicas 更大的那个策略。如果改为 Min ,则会采用使得 replicas 更小的那个策略。如果改为 Disabled ,则禁止 scaleUp # scaleUp: # 增加 replicas 时的策略 # stabilizationWindowSeconds: 0 # 如果连续 n 秒都想增加 replicas ,才允许增加。实际算法:统计最近 n 秒内 desiredReplicas 的最小值,作为 scaleUp 的依据 # policies: # - type: Percent # value: 100 # periodSeconds: 15 # 每次增加 replicas 时,限制在 15s 内最多增加 100% 的幅度 # - type: Pods # value: 4 # periodSeconds: 15 # 每次增加 replicas 时,限制在 15s 内最多增加 4 # selectPolicy: Max status: currentMetrics: # 记录 metrics 的当前值 - resource: current: averageUtilization: 50 averageValue: "52618582" name: memory type: Resource - resource: current: averageValue: 1m name: cpu type: Resource currentReplicas: 1 # 当前的 replicas desiredReplicas: 1 # 期望的 replicas
关于监控指标。
- HPA 原生的 metrics 种类少,只监控了 Pod 的 cpu、memory 负载。而且当 Pod 没有运行时就不能获取 metrics ,因此不能缩减到 minReplicas=0 。
- 计算全部 Pod 的平均指标时,只会统计 Ready 状态的 Pod ,排除不健康的 Pod 、正在被删除的 Pod 。
- 计算全部 Pod 的平均指标时,不能考虑到负载特别大的个别 Pod 。比如某个 Pod 内存不足,但全部 Pod 的平均内存负载不大,则不会增加 replicas 。
- 可选在 k8s 安装 prometheus-adapter (opens new window) ,将 Prometheus 存储的 metrics 传给 apiserver ,从而允许 HPA 读取多种多样的 metrics ,而且能缩减到 minReplicas=0 。
- 可选在 k8s 安装 keda (opens new window) ,从 Prometheus、Kafka 等数据源监听 event 来触发 HPA 。相当于 prometheus-adapter 的超集,支持更多数据源,而且能更及时地自动伸缩,甚至在负载升高之前就增加 replicas 。
- HPA 原生的 metrics 种类少,只监控了 Pod 的 cpu、memory 负载。而且当 Pod 没有运行时就不能获取 metrics ,因此不能缩减到 minReplicas=0 。
关于 replicas 字段的修改。
- 用 HPA 管理 Deployment 或 DaemonSet 时,如果手动修改 replicas 的值,而且与 HPA 的 desiredReplicas 值不同,则等到 kube-controller-manager 下一次执行 HPA 规则时,会自动将 replicas 赋值为 desiredReplicas 。这会导致一些 Pod 在短时间内启动、停止,增加开销。
- 同理,用
kubectl apply -f xx.yml
命令修改被 HPA 管理的 Deployment 或 DaemonSet 的配置文件时,应该省略 replicas 字段。 - 滚动更新 Deployment 时,会创建新旧两个 ReplicaSet ,分别配置一个 replicas 字段。而 HPA 修改的是 Deployment 中的 replicas 字段,也就是新的 ReplicaSet 中的 replicas 字段。
关于 replicas 字段的抖动。
- metrics 的值可能每分钟变化两三次,导致 HPA 经常修改 replicas 。为了避免 replicas 抖动,建议配置 HPA behavior 。
- 配置了 HPA behavior 时,HPA 每次修改 replicas (包括首次修改),都需要遵守限制条件。
- 对于重要的业务程序 Pod ,优先保障 Pod 服务质量。当负载升高时,迅速增加 replicas 。当负载降低时,缓慢减少 replicas 。
- 对于不重要的业务程序 Pod ,优先节省 CPU、内存资源。当负载升高时,缓慢增加 replicas 。当负载降低时,迅速减少 replicas 。
- 为了避免 replicas 取值过大,耗尽 k8s 资源,建议设置合适的 maxReplicas ,还可设置整个 namespace 的 ResourceQuota 。
# VPA
:纵向的 Pod 自动伸缩(Vertical Pod Autoscaler),即自动增减 Pod 的 requests、limits 资源配额。
- 目前 Pod 的资源配额是静态配置,想修改的话只能创建新 Pod ,导致 Pod 内应用程序重启。有的公司修改了 k8s 源代码,能在 Pod 运行时动态修改资源配额。
# CA
:k8s 集群的自动伸缩(cluster-autoscaler),即自动增减集群的 node 数量,从而增减整个集群的 CPU、内存等资源。