跳转至

k8s 自动伸缩应用

什么是 HPA 和 VPA ?

什么是 HPA 和 VPA ?

HPA(Horizontal Pod Autoscaler)和 VPA(Vertical Pod Autoscaler)都是 kuberntes 的自动伸缩 pods 的能力,但它们的作用对象和扩展方式不同。

  1. HPA(Horizontal Pod Autoscaler)是 Kubernetes 提供的一种自动扩展机制,它根据预设的阈值自动调整 Pod 的数量。HPA 会监控 Pod 的 CPU 和内存使用率,或者应用程序提供的自定义度量。当这些度量超过预设的阈值时,HPA 会自动增加 Pod 的数量;反之,当度量低于阈值时,HPA 就会自动减少 Pod 的数量。这种机制可以在应用程序负载增加时提供高性能,在负载减小时节省资源。

  2. 一个 HPA 对象用来监控 pods 的资源使用情况,通过对比实际的资源情况与理想的资源情况,来控制应用的自动伸缩。 例如,一个应用初始化时有两个 pods ,当前 CPU 的平均使用率达到 100% ,但是我们想每个 pod 的 CPU 使用率为 20%。HPA 会计算应该有 2 * (100 / 20) = 10 个 pods 来到理想的 CPU 利用率。 将会调整这个应用的 pod 数量为 10,kubernetes 负责调度 8个 新的 pods。

  1. VPA,也就是垂直 Pod 自动缩放器,也是 Kubernetes 提供的一种可以自动调整 Pod 资源的机制。但与 HPA 不同的是,VPA 不是通过调整 Pod 副本数量来调整资源,而是直接改变每个 Pod 的 CPU 或内存资源。VPA 会持续监控 Pod 的资源使用情况和需求,并在必要时自动调整 Pod 的资源请求和资源上限。这样可以确保每个 Pod 都有足够的资源来满足其需求,同时避免了资源的浪费。

安装和配置资源指标收集 Kubernets Metrics Server

资源指标管道

  1. 对于 Kubernetes,Metrics API 提供了一组基本的指标,以支持自动伸缩和类似的用例。 该 API 提供有关节点和 Pod 的资源使用情况的信息, 包括 CPU 和内存的指标。如果将 Metrics API 部署到集群中, 那么 Kubernetes API 的客户端就可以查询这些信息,并且可以使用 Kubernetes 的访问控制机制来管理权限。

  2. HorizontalPodAutoscaler (HPA) 和 VerticalPodAutoscaler (VPA) 使用 metrics API 中的数据调整工作负载副本和资源,以满足客户需求。

    a. 你也可以通过 kubectl top 命令来查看资源指标。

image-20240620102111080

  • 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 扩展服务器。

1. 部署 metrics-server
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
2. 在 components.yaml 文件中添加参数 --kubelet-insecure-tls hostNetwork: 开启 hostNetwork 模式
...
  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
...
3. 基于 components.yaml 文件部署 metrics-server
[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
4. 查看 metrics-server 服务
[root@k8smaster002 metrics-server]# kubectl get deployment -n kube-system
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
metrics-server   1/1     1            1           26d
5. 验证连接状态
[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
6. 现在就可以查看每个节点和 Pod 的 CPU 和 内存 使用
...
[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 
...
1. 创建 metrics-server 使用的证书
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
2. 创建相关文件
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes metrics-server-csr.json | cfssljson -bare metrics-server
3. 将生成的证书拷贝至 所有 master node 节点
cp  metrics-server*.pem /etc/kubernetes/ssl
scp metrics-server*.pem datarc@192.168.1.99:~/
4. 修改 kubernetes 控制平面组件的配置以支持 metrics-server ,修改 kube-apiserver 文件
  --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 
5. 重启服务
# systemctl daemon-reload
# systemctl enable kube-apiserver
# systemctl restart kube-apiserver
6. 修改 kube-controller-manager 文件
--horizontal-pod-autoscaler-use-rest-clients=true
7. 重启服务
# systemctl daemon-reload

# systemctl enable kube-controller-manager

# systemctl restart kube-controller-manager

需切换至 kubeadm 部署章节,下载资源并部署

HPA

HPA 概念详解?

Horizontal Pod Autoscaler 如何工作?

HPA(纵向)的作用对象是 Pod 的数量。可针对 CPU 使用率、内存使用率进行扩缩容配置,会根据期望指标,会触发扩容或者缩容,若同时有多个指标,会取 Max 值。

image-20240619182603407

  1. 设计 HPA 资源,包含实现扩容的条件

  2. cAdvisor 作为一个容器资源利用监控服务,它运行在每个节点的 kubelet 中

  3. 监控的 CPU 利用率被 cAdvisor 收集,然后被 heapster 聚合

  4. Heapster 是运行在集群上的服务,它监控并且聚合指标

  5. Heapster 从每个 cAdvisor 中查询指标

  6. 当 HPA 部署之后,controller 会持续观察被 Heapster 报告的指标,根据要求自动伸缩。

  7. 基于配置的指标,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 应用。

1. 编写 deployment 资源 apache-hpa-deploy.yaml
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
2. 使用 kubectl 命令创建这个资源 apache-hpa-deploy.yaml
...
[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]。

1. 如果 CPU 的利用率达到 10% ,那么会自动伸缩 1 个 deployment 到 10 个 deployment 创建 HPA
[root@k8smaster002 metrics-server]# kubectl autoscale deployment php-apache --cpu-percent=10 --min=1 --max=10
horizontalpodautoscaler.autoscaling/php-apache autoscaled
1. 假设当前指标:CPU利用率 70% ,期望指标:CPU利用率60% , 假设当前副本数:10 ,期望副本数:ceil(10*(70/60))=12 , 最终总的 Pod 副本数应该是 12,即扩容数量为 2 ,注意扩容和缩容幅度不能超过 HorizontalPodAutoscaler 资源中的副本上下限
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% 的时候,执行调整
2. 检查 HPA 的状态
...
[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
...
3. 现在只有一个 php pod 的副本
[root@k8smaster002 ~]# kubectl get pods |grep php-apache
php-apache-598b474864-qnn95              1/1     Running   0              9m27s

4. 验证 kubernetes 自动伸缩应用,手动增加压力来增加 CPU利用率,使用 dd 命令增加 CPU 压力。

image-20240407185254818

1. 打开第一个终端: 输入下面的指令
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"
2. 打开第二个终端: 观察 hpa 与 pod ,会增加 CPU 压力,HPA 会自动再创建 9 个 pods ,因为最大的 pods 数量是 10。
...
[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
...
3. 第一个终端中停止产生负载: 按 + C 停止,CPU 压力就会降下来,当 CPU 压力降低后,5 分钟之后,副本的数量就降为 1。
[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
5. 使用 kubectl describe 来检查事件
...
[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
...