目录
K8s 原生 hpa
K8s 原生 hpa 的文档为 Horizontal Pod Autoscaling。 hpa 依赖 metrics server提供指标(或者 prometheus-adapter),安装方式为
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 非安全模式,否则可能无法启动
kubectl patch -n kube-system deployment metrics-server --type=json \
-p '[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]'
# 安装完成之后,可以使用 top 命令查看 pod cpu 利用率。
kubectl top pod local-path-provisioner-684f458cdd-r2j5q -n local-path-storage
快速入手
先通过一个例子,大概看下 hpa 的工作过程。这部分可以参考官方文档 HorizontalPodAutoscaler Walkthrough,思路就是创建一个 deployment,然后是创建针对这个 deployment 的 hpa 资源,然后增加负载,观察扩缩容效果。
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
template:
metadata:
labels:
run: php-apache
spec:
containers:
- name: php-apache
image: registry.k8s.io/hpa-example
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
requests:
cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
name: php-apache
labels:
run: php-apache
spec:
ports:
- port: 80
selector:
run: php-apache
创建针对上述 deployment 的 hpa。指定当平均 cpu 利用率超过 50% 时进行扩容。
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
下一步是增加这个 php-apache 的负载,通过下面命令执行,即每隔 10 ms 访问 php-apache 服务,其中 php-apache 是我们上面创建的 deployment 对应的 service。
kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never \
-- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"
观察扩缩容效果,可以看到在上强度之后,先是扩容;负载降下来之后,然后又进行了缩容。
lr90@mo hpa % kubectl get hpa php-apache --watch
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache 0%/50% 1 5 1 3m35s
php-apache Deployment/php-apache 168%/50% 1 5 1 4m
php-apache Deployment/php-apache 250%/50% 1 5 4 4m15s
php-apache Deployment/php-apache 250%/50% 1 5 5 4m30s
php-apache Deployment/php-apache 236%/50% 1 5 5 5m
php-apache Deployment/php-apache 102%/50% 1 5 5 5m15s
php-apache Deployment/php-apache 9%/50% 1 5 5 5m30s
php-apache Deployment/php-apache 0%/50% 1 5 5 5m45s
php-apache Deployment/php-apache 0%/50% 1 5 5 10m
php-apache Deployment/php-apache 0%/50% 1 5 1 10m
原生 hpa 是怎么工作的
工作过程
K8s 中的 ControllerManager hpa 控制器会周期性的评估 pod 资源使用情况,并决定是否扩缩容,这个周期由 kube-controller-manager 的参数 --horizontal-pod-autoscaler-sync-period
决定,默认是 15s,也就是说最快负载变化 15s 后开始扩缩容。
在每个周期中,hpa控制器首先根据 hpa 资源中配置的 scaleTargetRef 找到一组 pod(根据其 .spec.selector 字段),然后根据 metrics api 获取 pod 的平均资源使用率,结合 hpa 中配置的期望资源利用率计算出一个期望副本数,并与当前副本数进行比较,以扩容或者缩容。计算公式参考下面的扩容算法
。
扩容算法
官方文档 algorithm-details 有说明,这里概述一下。 从大致思路上来讲,该算法希望将容器的平均资源使用率维持在一个特定的数值,如果高于此利用率,则扩容;如果低于此利用率,则缩容。auto-scaler 控制器通过下面公式计算期望副本数。具体是:
desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]
该公式的计算过程为:
- 计算当前 metrics 指标与期望 metrics 的比率。
- 用这个比率乘以当前副本数,并向上取整。
结合我们上边的例子,这个公式的效果是使 cpu 利用率大致在 50% 左右。我们通过几个例子来解释这个公式:假设当前有两个副本,每个副本利用率是 80%,那期望副本数是 ceil(2*(8/5))=4
即要扩容两个副本出来;假设当前有两个副本,每个副本利用率是 30%,那期望副本数是 ceil(2*(3/5))=2
,可以发现当前既不用扩容,也不用缩容;那如果每个副本利用率是 20%,则 ceil(2*(2/5))=1
,则要缩容一个副本。
除了这个公式带来的设计思路,auto-scaler 控制器还有一些原则(或者 case 要处理):
- currentMetricValue 是负载所属 pod 的平均值,比如同属一个 deploy 的所有 pod的利用率平均值。利用率是使用值跟 request 的比值,因此当资源使用量大于 request 时(比如允许超配),可能会出现资源使用率大于 100% 的情况。
- 选择 pod 时,不考虑 deletiontimestamp 不为 nil,或者 failed 状态的 pod。
- 如果 pod 的指标缺失,不会被纳入统计。对于缺失的指标,hpa 处理比较谨慎,在通过公式计算出是该扩容还是缩容之后,再通过这些指标缺失的 pod 来进行简单校准。在计算出来要进行缩容时,认为指标缺失的 pod 利用了 100% 资源;在扩容时,认为缺失的 pod 利用了 0% 的资源,尽量避免扩缩容,其思想是在出现指标缺失时,尽量避免做出扩缩容动作,以免误判。
配置扩缩容行为
在使用 hpa 进行扩缩容时,有时候业务的资源使用率会导致 hpa 控制器在扩容、缩容之间不停切换,这种情况称为 flapping
,hpa 提供一些参数可以优化这种行为。
扩缩容策略(scaling policies)
hpa 资源的 behavior
字段允许我们配置扩缩容策略,下面的配置配置了两个缩容策略:1)在一分钟内最多缩容 4 个 pod;2)在一分钟内最多缩容 10% 的 pod。当有多个扩缩容策略存在时,hpa 的策略 selectPolicy: Max
是:选择会导致最多副本数变化的策略
。假设此 hpa CR 对应的 deployment 少于 40 个副本,那么 10% 小于 4,因此会选择策略 1);当副本数大于 40 时,将会选择策略2。(注意文档里提到了一个 case,如果有 72 个副本,72 的 10% 是 7.2,但在计算时,会 round up 到 8,因此会选择最多缩容 8 个副本。)
我们可以将 selectPolicy: Min
来实现 选择会导致最少副本数变化的策略
;配置 selectPolicy: Disabled
为禁用扩容或者缩容。另外 peroidSeconds
的最大配置是 1800,也就是半小时。
spec:
behavior:
scaleDown:
policies:
- type: Pods
value: 4
periodSeconds: 60
- type: Percent
value: 10
periodSeconds: 60
selectPolicy: Max
stabilizationWindowSeconds: 180
稳定窗口(stabilization window)
稳定窗口配置是为了缓解 flapping
也就是波动行为。具体配置是上面 yaml 中的 stabilizationWindowSeconds: 180
配置,这个配置是说:如果要进行缩容,请参考过去 5 分钟(180秒)计算出来的期望状态,并选择一个会导致副本数变化最大的配置。
默认行为(default behavior)
默认行为是不配置 behavior 时的默认参数,这个参考 Default Behavior。
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 100
periodSeconds: 15
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
hpa 指标
hpa 获取指标是通过 K8s apiserver aggregation api 接口进行的,简单的说,当你访问 aggregation api 时,apiserver 实际是将你的请求转发到了集群里的一个应用服务。是扩展 apiserver 的一种方式。metrics-server 注册了一个 apiservices metrics.k8s.io
,我们可以通过下面命令查看:
lr90@mo hpa % kubectl get apiservices | grep metrics
v1beta1.metrics.k8s.io kube-system/metrics-server True 10m
我们通过查看这个 apiservice 具体配置可以查看其指向的具体 service,比如上面的 metrics-server,其最终访问的是 kube-system 下面的 metrics-server 这个 service。
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
name: v1beta1.metrics.k8s.io
spec:
group: metrics.k8s.io
groupPriorityMinimum: 100
insecureSkipTLSVerify: true
service:
name: metrics-server
namespace: kube-system
port: 443
version: v1beta1
versionPriority: 100
除了 metrics.k8s.io
api, hpa 还支持自定以 api custom.metrics.k8s.io
以及外部metrics api external.metrics.k8s.io
,metrics-server 没有提供后面两种 apiservices,不过其替代品 metrics。prometheus-adapter 实现了,后者可以将 prometheus 的指标转换为 hpa 能认识的指标。
metrics server
集群部署 metrics server 之后,可以通过 metrics server 提供的内存和 cpu 指标来进行扩缩容。我们可以通过下面命令了解 metrics server 给我们提供的 api:
kubectl get --raw /apis/metrics.k8s.io/v1beta1/namespaces/default/pods/php-apache-5b56f9df94-jw6tw
返回的结果是 json 格式,内容如下。
{
"kind": "PodMetrics",
"apiVersion": "metrics.k8s.io/v1beta1",
"metadata": {
"name": "php-apache-5b56f9df94-jw6tw",
"namespace": "default",
"creationTimestamp": "2024-04-06T14:13:43Z",
"labels": {
"pod-template-hash": "5b56f9df94",
"run": "php-apache"
}
},
"timestamp": "2024-04-06T14:13:34Z",
"window": "14.888s",
"containers": [
{
"name": "php-apache",
"usage": {
"cpu": "107804n",
"memory": "12108Ki"
}
}
]
}
自定义指标(custom metrics)
项目 prometheus-adapter 提供了可用 hpa 使用的自定义 metrics。prometheus-adapter 是 metrics-server 的可替代品,如果集群中已经部署了 prometheus,那么可以不用部署 metrics-server,而是部署 prometheus-adapter,该组件可将 prometheus 收集的指标转换为 hpa 可使用的指标。
文章《Kubernetes自定义指标HPA》写的很细致,值得学习。
本文概述了如何使用 hpa 自动扩缩容应用,后面介绍下怎么使用 keda 来扩缩容应用。