k8s 自动伸缩应用 ¶
什么是 HPA 和 VPA ? ¶
什么是 HPA 和 VPA ?
HPA(Horizontal Pod Autoscaler)和 VPA(Vertical Pod Autoscaler)都是 kuberntes 的自动伸缩 pods 的能力,但它们的作用对象和扩展方式不同。
-
HPA(Horizontal Pod Autoscaler)是 Kubernetes 提供的一种自动扩展机制,它根据预设的阈值自动调整 Pod 的数量。HPA 会监控 Pod 的 CPU 和内存使用率,或者应用程序提供的自定义度量。当这些度量超过预设的阈值时,HPA 会自动增加 Pod 的数量;反之,当度量低于阈值时,HPA 就会自动减少 Pod 的数量。这种机制可以在应用程序负载增加时提供高性能,在负载减小时节省资源。
-
一个 HPA 对象用来监控 pods 的资源使用情况,通过对比实际的资源情况与理想的资源情况,来控制应用的自动伸缩。 例如,一个应用初始化时有两个 pods ,当前 CPU 的平均使用率达到 100% ,但是我们想每个 pod 的 CPU 使用率为 20%。HPA 会计算应该有
2 * (100 / 20) = 10
个 pods 来到理想的 CPU 利用率。 将会调整这个应用的 pod 数量为 10,kubernetes 负责调度 8个 新的 pods。
- VPA,也就是垂直 Pod 自动缩放器,也是 Kubernetes 提供的一种可以自动调整 Pod 资源的机制。但与 HPA 不同的是,VPA 不是通过调整 Pod 副本数量来调整资源,而是直接改变每个 Pod 的 CPU 或内存资源。VPA 会持续监控 Pod 的资源使用情况和需求,并在必要时自动调整 Pod 的资源请求和资源上限。这样可以确保每个 Pod 都有足够的资源来满足其需求,同时避免了资源的浪费。
安装和配置资源指标收集 Kubernets Metrics Server ¶
资源指标管道
-
对于 Kubernetes,Metrics API 提供了一组基本的指标,以支持自动伸缩和类似的用例。 该 API 提供有关节点和 Pod 的资源使用情况的信息, 包括 CPU 和内存的指标。如果将 Metrics API 部署到集群中, 那么 Kubernetes API 的客户端就可以查询这些信息,并且可以使用 Kubernetes 的访问控制机制来管理权限。
-
HorizontalPodAutoscaler (HPA) 和 VerticalPodAutoscaler (VPA) 使用 metrics API 中的数据调整工作负载副本和资源,以满足客户需求。
a. 你也可以通过 kubectl top 命令来查看资源指标。
-
cAdvisor: 用于收集、聚合和公开 Kubelet 中包含的容器指标的守护程序。
-
kubelet: 用于管理容器资源的节点代理。 可以使用 /metrics/resource 和 /stats kubelet API 端点访问资源指标。
-
节点层面资源指标: kubelet 提供的 API,用于发现和检索可通过 /metrics/resource 端点获得的每个节点的汇总统计信息。
-
metrics-server: 集群插件组件,用于收集和聚合从每个 kubelet 中提取的资源指标。 API 服务器提供 Metrics API 以供 HPA、VPA 和 kubectl top 命令使用。Metrics Server 是 Metrics API 的参考实现。
-
Metrics API: Kubernetes API 支持访问用于工作负载自动缩放的 CPU 和内存。 要在你的集群中进行这项工作,你需要一个提供 Metrics API 的 API 扩展服务器。
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
...
template:
metadata:
labels:
k8s-app: metrics-server
spec:
hostNetwork: true ## add this line 开启hostNetwork模式
containers:
- args:
- --cert-dir=/tmp
- --secure-port=4443
- --kubelet-insecure-tls ## add this line
image: registry.k8s.io/metrics-server/metrics-server:v0.7.1
...
[root@k8smaster002 metrics-server]# kubectl apply -f components.yaml
serviceaccount/metrics-server unchanged
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader unchanged
clusterrole.rbac.authorization.k8s.io/system:metrics-server unchanged
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader unchanged
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator unchanged
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server unchanged
service/metrics-server unchanged
deployment.apps/metrics-server configured
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io unchanged
[root@k8smaster002 metrics-server]# kubectl get deployment -n kube-system
NAME READY UP-TO-DATE AVAILABLE AGE
metrics-server 1/1 1 1 26d
[root@k8smaster002 metrics-server]# kubectl get apiservice v1beta1.metrics.k8s.io -o yaml
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"apiregistration.k8s.io/v1","kind":"APIService","metadata":{"annotations":{},"labels":{"k8s-app":"metrics-server"},"name":"v1beta1.metrics.k8s.io"},"spec":{"group":"metrics.k8s.io","groupPriorityMinimum":100,"insecureSkipTLSVerify":true,"service":{"name":"metrics-server","namespace":"kube-system"},"version":"v1beta1","versionPriority":100}}
creationTimestamp: "2024-03-11T10:00:25Z"
labels:
k8s-app: metrics-server
name: v1beta1.metrics.k8s.io
resourceVersion: "5069190"
uid: 443cafea-f9c7-4015-b90a-bd556d07f5c0
spec:
group: metrics.k8s.io
groupPriorityMinimum: 100
insecureSkipTLSVerify: true
service:
name: metrics-server
namespace: kube-system
port: 443
version: v1beta1
versionPriority: 100
status:
conditions:
- lastTransitionTime: "2024-04-05T12:27:55Z"
message: all checks passed
reason: Passed
status: "True"
type: Available
...
[root@k8smaster002 metrics-server]# kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
k8smaster001 367m 7% 2971Mi 79%
k8smaster002 154m 5% 2702Mi 72%
k8sworker001 116m 5% 2697Mi 72%
...
...
[root@k8smaster002 metrics-server]# kubectl top pod
NAME CPU(cores) MEMORY(byt和 Pod es)
canary-7d97679b67-klfq7 1m 4Mi
nfs-client-provisioner-94f889d79-nxmjk 2m 32Mi
production-64cfc46b65-6wkqx 1m 3Mi
...
cat > metrics-server-csr.json <<"EOF"
{
"CN": "metrics",
"hosts": [
"127.0.0.1",
"192.168.3.100"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [{
"C": "CN",
"ST": "Beijing",
"L": "Beijing",
"O": "deployment",
"OU": "CN"
}]
}
EOF
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes metrics-server-csr.json | cfssljson -bare metrics-server
cp metrics-server*.pem /etc/kubernetes/ssl
scp metrics-server*.pem datarc@192.168.1.99:~/
--requestheader-client-ca-file=/etc/kubernetes/ssl/ca.pem \
--requestheader-extra-headers-prefix=X-Remote-Extra- \
--requestheader-group-headers=X-Remote-Group \
--requestheader-username-headers=X-Remote-User \
--proxy-client-cert-file=/etc/kubernetes/ssl/metrics-server.pem \
--proxy-client-key-file=/etc/kubernetes/ssl/metrics-server-key.pem \
--runtime-config=api/all=true
# systemctl daemon-reload
# systemctl enable kube-apiserver
# systemctl restart kube-apiserver
--horizontal-pod-autoscaler-use-rest-clients=true
# systemctl daemon-reload
# systemctl enable kube-controller-manager
# systemctl restart kube-controller-manager
需切换至 kubeadm 部署章节,下载资源并部署
HPA ¶
HPA
概念详解? ¶
Horizontal Pod Autoscaler
如何工作?
HPA(纵向)的作用对象是 Pod 的数量。可针对 CPU 使用率、内存使用率进行扩缩容配置,会根据期望指标,会触发扩容或者缩容,若同时有多个指标,会取 Max 值。
-
设计 HPA 资源,包含实现扩容的条件
-
cAdvisor 作为一个容器资源利用监控服务,它运行在每个节点的 kubelet 中
-
监控的 CPU 利用率被 cAdvisor 收集,然后被 heapster 聚合
-
Heapster 是运行在集群上的服务,它监控并且聚合指标
-
Heapster 从每个 cAdvisor 中查询指标
-
当 HPA 部署之后,controller 会持续观察被 Heapster 报告的指标,根据要求自动伸缩。
-
基于配置的指标,HPA 决定是否需要伸缩。
算法解析
desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]
(当前指标值 ➗ 期望指标值) ✖️ 当前副本数 ,结果再向上取整,最终结果就是期望的副本数量
例一:
假设目前有 10 个 Pods(currentReplicas = 10),每个 Pod 的 CPU 利用率都是 50%(currentMetricValue = 50%),而我们期望每个 Pod 的 CPU 利用率是 40%(desiredMetricValue = 40%)。 根据公式,我们可以计算出新的期望的 Pod 数量为 ceil[10 * (50% / 40%)] = ceil[10 * 1.25] = ceil[12.5] = 13。也就是说,我们需要增加 3 个 Pod,使得每个 Pod 的 CPU 利用率降低到期望的 40%。
例二:
假设目前有 5 个 Pods(currentReplicas = 5),每个 Pod 的内存利用率都是 70%(currentMetricValue = 70%),而我们期望每个 Pod 的内存利用率是 80%(desiredMetricValue = 80%)。 根据公式,我们可以计算出新的期望的 Pod 数量为 ceil[5 * (70% / 80%)] = ceil[5 * 0.875] = ceil[4.375] = 5。也就是说,我们不需要增加或减少 Pod,当前的 Pod 数量就可以满足我们的期望。
例三:
假设当前副本数:10 ,目前 CPU 利用率 70% ,期望指标:CPU 利用率 60% , 期望副本数:ceil(10*(70/60))=12 , 最终总的 Pod 副本数应该是 12,即扩容数量为 2 ,注意扩容和缩容幅度不能超过 HorizontalPodAutoscaler 资源中的副本上下限
基于 CPU 自动伸缩 ¶
创建 Horizontal Pod Autoscaler(HPA)基于 CPU 来自动伸缩应用。 ¶
首先需要有一个metrics server服务安装,运行在Kubernetes集群上。Horizontal Pod Autoscaler使用API来收集指标。 当然也可以使用自定义的metrics server,例如,Prometheus, Grafana等等。
创建示例 deployment 应用。 ¶
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
...
[root@k8smaster002 metrics-server]# kubectl apply -f apache-hpa-deploy.yaml
deployment.apps/php-apache created
service/php-apache created
...
...
[root@k8smaster002 metrics-server]# kubectl get deployment php-apache
NAME READY UP-TO-DATE AVAILABLE AGE
php-apache 1/1 1 1 3m55s
...
创建 Horizontal Pod Autoscaler ¶
解释
使用 kubectl 创建自动扩缩器。 kubectl autoscale 子命令是 kubectl 的一部分, 可以帮助你执行此操作。你将很快运行一个创建 HorizontalPodAutoscaler 的命令, 该 HorizontalPodAutoscaler 维护由你在这些说明的第一步中创建的 php-apache Deployment 控制的 Pod 存在 1 到 10 个副本。粗略地说,HPA 控制器将增加和减少副本的数量 (通过更新 Deployment)以保持所有 Pod 的平均 CPU 利用率为 50%。 Deployment 然后更新 ReplicaSet —— 这是所有 Deployment 在 Kubernetes 中工作方式的一部分 —— 然后 ReplicaSet 根据其 .spec 的更改添加或删除 Pod。由于每个 Pod 通过 kubectl run 请求 200 milli-cores,这意味着平均 CPU 使用率为 100 milli-cores。 有关算法的更多详细信息, 有关算法的更多详细信息, 请参阅算法(详细信息)[https://kubernetes.io/zh-cn/docs/tasks/run-application/horizontal-pod-autoscale/#algorithm-details]。
[root@k8smaster002 metrics-server]# kubectl autoscale deployment php-apache --cpu-percent=10 --min=1 --max=10
horizontalpodautoscaler.autoscaling/php-apache autoscaled
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 10 # Pod 副本数下限
maxReplicas: 20 # Pod 副本数上限
metrics:
- type: Resource
resource:
name: cpu # cpu
target:
type: Utilization
averageUtilization: 60 # 当 CPU 利用率大于 60% 或者内存占用大于 60% 的时候,执行调整
...
[root@k8smaster002 ~]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache 0%/10% 1 10 2 3m52s
...
# 默认是 15 秒轮训运行
# 默认的 HPA 同步间隔可以通过如下参数进行调整: --horizontal-pod-autoscaler-sync-period
...
[root@k8smaster002 ~]# kubectl get pods |grep php-apache
php-apache-598b474864-qnn95 1/1 Running 0 9m27s
4. 验证 kubernetes 自动伸缩应用,手动增加压力来增加 CPU利用率,使用 dd 命令增加 CPU 压力。
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"
...
[root@k8smaster002 ~]# kubectl get hpa php-apache --watch
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache 0%/10% 1 10 10 9m38s
php-apache Deployment/php-apache 16%/10% 1 10 10 9m48s
php-apache Deployment/php-apache 32%/10% 1 10 10 10m
php-apache Deployment/php-apache 33%/10% 1 10 10 10m
...
[root@k8smaster002 ~]# kubectl get pod |grep php
php-apache-598b474864-2z7c5 1/1 Running 0 9m52s
php-apache-598b474864-62nq4 1/1 Running 0 10m
php-apache-598b474864-66dnb 1/1 Running 0 10m
php-apache-598b474864-88rg7 1/1 Running 0 9m52s
php-apache-598b474864-fxm8j 1/1 Running 0 10m
php-apache-598b474864-l2bcx 1/1 Running 0 10m
php-apache-598b474864-lq6n2 1/1 Running 0 10m
php-apache-598b474864-qnn95 1/1 Running 0 21m
php-apache-598b474864-sbr5p 1/1 Running 0 10m
php-apache-598b474864-xxtc9 1/1 Running 0 10m
...
[root@k8smaster002 ~]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache 32%/10% 1 10 10 11m
php-apache Deployment/php-apache 32%/10% 1 10 10 12m
php-apache Deployment/php-apache 15%/10% 1 10 10 12m
[root@k8smaster002 ~]# kubectl get pod |grep php
php-apache-598b474864-qnn95 1/1 Running 0 22m
...
[root@k8smaster002 ~]# kubectl describe hpa php-apache
Name: php-apache
Namespace: default
CreationTimestamp: Sun, 07 Apr 2024 18:34:20 +0800
Reference: Deployment/php-apache
Metrics: ( current / target )
resource cpu on pods (as a percentage of request): 0% (1m) / 10%
Min replicas: 1
Max replicas: 10
Deployment pods: 1 current / 1 desired
Conditions:
Type Status Reason Message
---- ------ ------ -------
AbleToScale True ReadyForNewScale recommended size matches current size
ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from cpu resource utilization (percentage of request)
ScalingLimited True TooFewReplicas the desired replica count is less than the minimum replica count
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulRescale 23m horizontal-pod-autoscaler New size: 2; reason: Current number of replicas below Spec.MinReplicas
Normal SuccessfulRescale 20m horizontal-pod-autoscaler New size: 4; reason: cpu resource utilization (percentage of request) above target
Normal SuccessfulRescale 20m horizontal-pod-autoscaler New size: 8; reason: cpu resource utilization (percentage of request) above target
Normal SuccessfulRescale 20m horizontal-pod-autoscaler New size: 10; reason: cpu resource utilization (percentage of request) above target
Normal SuccessfulRescale 9m29s (x5 over 25m) horizontal-pod-autoscaler New size: 1; reason: All metrics below target
...