K8S之HPA与VPA的应用部署

Kubernetes安装Metrics-server

Metrics Server 简介

Metrics Server 是 Kubernetes 监控组件中的重要一部分,Metrics Server 主要分为 API 和 Server 两大部分。其中 Metrics API 部分主要通过 APIServer 对外暴露 Pod 资源使用情况,比如:HPA、kubectl top、Kubernetes dashboard 等。Metrics Server 是根据 Kubernetes 监控架构进行实施,该组件会定期通过 Summary API 从 Kubelet 所在集群节点获取服务指标,然后将指标汇总、存储到内存中,仅仅存储指标最新状态,一旦重启组件数据将会丢失。现在通过 Metrics Server 采集到了数据,也暴露了 API 那么通过 kube-aggregator 统一把 API Server(/apis/metrics) 数据转发给 Metrics Server,最后通过 metrics api 统一暴露出去。

Metrics Server 抽象了 HorizontalPodAutoscaler 资源对象,通过观察 Pod CPU、内存或者其它自定义指标自动缩放 Controller、Deployment、StatefulSet中的 Pod 数量,注意 HorizontalPodAutoscaler 不支持无法缩放的对象,比如 DaemonSet。

下载并修改配置

最好下载下来运行
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/high-availability-1.21+.yaml

#1.由于网络原因,修改资源文件中的镜像地址
image: registry.k8s.io/metrics-server/metrics-server:v0.7.1
修改为
image: registry.aliyuncs.com/google_containers/metrics-server:v0.7.1

#2.修改如下两处地方,否则启动会报错
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
修改为
- --kubelet-preferred-address-types=InternalIP


#增加配置
- --kubelet-insecure-tls

《K8S之HPA与VPA的应用部署》

应用配置
kubectl apply -f high-availability-1.21+.yaml

查看是否运行

[root@k8s-master01 software]# kubectl top node
NAME           CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
k8s-master01   134m         6%     2507Mi          79%
k8s-worker01   125m         6%     2222Mi          76%
k8s-worker02   134m         6%     2498Mi          79%

[root@k8s-master01 software]# kubectl top pod
NAME                         CPU(cores)   MEMORY(bytes)
nginx-demo-7c8655954-92cmh   1m           43Mi
nginx-demo-7c8655954-zzgv7   1m           43Mi

《K8S之HPA与VPA的应用部署》

HPA

HPA与VPA简介

前提要有metrics-server插件组件,metrics-server定期的(默认为15s)收集Pod资源的平均CPU负载情况。

  • HPA: 根据Pod的CPU或内存的使用率为控制器管理的Pod资源副本数量实现自动扩缩容。
  • VPA: 根据Pod容器的CPU和内存的使用率自动设置Pod容器的CPU和内存的requests资源量限制。

两个的差别
– HPA: 主要关注整个应用程序水平方向的伸缩,通过调整 Pod 的副本数量来应对负载变化;
– VPA 则关注 Pod 内部容器的垂直伸缩,通过调整容器的资源限制来优化资源利用和性能。

策略 缩放方向 实现手段 CPU 或内存资源
HPA  水平缩放 (HPA) 增加 Pod数量 减少现有的Pod的CPU或资源
VPA  垂直缩放 (VPA)  删除 pod    增加现有的Pod的CPU或资源

HPA自动扩容缩容测试

部署测试应用

手动拉取镜像,防止拉不下来
crictl pull mirrorgooglecontainers/hpa-example

cat > hpa-pod.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: php-apache
  name: php-apache
spec:
  replicas: 1
  selector:
    matchLabels:
      run: php-apache
  template:
    metadata:
      labels:
        run: php-apache
    spec:
      containers:
      - image: mirrorgooglecontainers/hpa-example
        name: php-apache
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
  name: php-apache
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: php-apache
EOF
kubectl apply -f hpa-pod.yaml

创建hpa控制器

HorizontalPodAutoscaler 对象,默认最小副本数为 1,cpu 或者 内存达到定义的限制开始扩容,最大副本数量为 4

cat > hpa.yml << EOF
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  creationTimestamp: "2024-05-22T23:37:58Z"
  name: php-apache
  namespace: default
  resourceVersion: "681529"
  uid: 47495c14-d34e-41c5-9857-c0aedc178e90
spec:
  maxReplicas: 10
  metrics:
  - resource:
      name: cpu
      target:
        averageUtilization: 50
        type: Utilization
    type: Resource
  minReplicas: 1
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache

EOF
kubectl apply -f hpa.yml

或者使用命令创建HPA
kubectl autoscale deployment php-apache –cpu-percent=50 –min=1 –max=10

--min=<最小副本数>: 指定自动伸缩时的最小副本数。
--max=<最大副本数>: 指定自动伸缩时的最大副本数。
--cpu-percent=<requests资源量百分比阈值>: 指定自动伸缩的CPU利用率阈值百分比。当控制器资源的CPU利用率达到阈值时,将自动扩展副本数。

查看hpa
[root@k8s-master01 hpa]# kubectl get hpa

NAME         REFERENCE               TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   <unknown>/50%   1         10        0          5s

部署一个容器来给HPA测试容器压力

首先开另一个窗口监控

kubectl get hpa -w
NAME         REFERENCE               TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   0%/50%    1         10        1          6m5s
创建busybox容器不段访问目标容器给与压力
kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"

观察到随着压力pod数量逐渐增加
《K8S之HPA与VPA的应用部署》

最终稳定在8个容器,平均cpu在50以下
《K8S之HPA与VPA的应用部署》

删除压力测试pod load-generator

[root@k8s-master01 hpa]# kubectl delete pod load-generator
pod “load-generator” deleted

删除压力测试pod后,可以看到很长时间pod的数量才逐渐减小
HPA增加pod的策略比较积极,减少的策略比较消极,这是为了实际需求考虑,防止一次性减少的pod过多导致pod的数量又不够,还要再次增加pod,如此反复肯定不行

《K8S之HPA与VPA的应用部署》

VPA

VPA简介

VPA主要由三个组件组成,分别为recommender、updater、admission-controller

1)recommender:引入VerticalPodAutoscaler对象,其由 Pod 的标签选择器、资源策略(控制 VPA 如何计算资源)、更新策略(控制如何将更改应用于 Pod)和推荐的 Pod 资源组成,其根据metric-server获取到的容器指标并观测 OOM 事件,计算推荐指标,最终更新VerticalPodAutoscaler对象

2)updater:其是负责Pod更新的组件。如果 Pod 在 “Auto” 模式下使用 VPA,则 Updater 可以决定使用推荐器资源对其进行更新。这只是通过驱逐Pod以便使用新资源重新创建它来实现的。简单来说,其是根据pod的request中设置的指标和recommend计算的推荐指标,在一定条件下驱逐pod,

3)admission-controller:这是一个webhook组件,所有 Pod 创建请求都通过 VPA Admission Controller,如果Pod与VerticalPodAutoscaler 对象匹配,把recommend计算出的指标应用到pod的request和limit,如果 Recommender 不可用,它会回退到 VPA 对象中缓存的推荐。

VPA四种运行模式

  • “Auto”:VPA 在创建 pod 时分配资源请求,并使用首选更新机制在现有 pod 上更新它们。目前这相当于”Recreate”(见下文)。一旦 pod 请求的免重启(“就地”)更新可用,它可能会被该”Auto”模式用作首选的更新机制。注意:VPA 的此功能是实验性的,可能会导致您的应用程序停机,当目前运行的pod的资源达不到VPA的推荐值,就会执行pod驱逐,重新部署新的足够资源的服务
  • “Recreate”:VPA 在创建 Pod 时分配资源请求,并在现有 Pod 上更新它们,当请求的资源与新建议有很大差异时(尊重 Pod 中断预算,如果定义)。这种模式应该很少使用,只有当您需要确保在资源请求发生变化时重新启动 Pod 时。否则,更喜欢这种”Auto”模式,一旦它们可用,就可以利用重新启动免费更新。注意:VPA 的此功能是实验性的,可能会导致您的应用程序停机
  • “Initial”:VPA 仅在创建 pod 时分配资源请求,以后不会更改它们
  • “Off”:VPA 不会自动更改 Pod 的资源需求。这些建议是经过计算的,并且可以在 VPA 对象中进行检查。这种模式仅获取资源推荐值,但是不更新Pod(这种用的比较多)

安装VPA

首先升级openssl

编译安装OpenSSL
因为vpa的要求,openssl必须不低于1.1版本

cd /usr/local/src
wget https://www.openssl.org/source/openssl-1.1.1k.tar.gz
解压源码包:
tar -zxvf openssl-1.1.1k.tar.gz
编译安装OpenSSL:

cd openssl-1.1.1k
./config --prefix=/usr/local/openssl
make
make install
更新系统库链接:

mv /usr/bin/openssl /usr/bin/openssl.old
ln -s /usr/local/openssl/bin/openssl /usr/bin/openssl
echo "/usr/local/openssl/lib" >> /etc/ld.so.conf
ldconfig -v

验证新版本:
openssl version

提前下载镜像

首先下载镜像,不然下不下来,注意版本可能不同,需要根据vertical-pod-autoscaler的版本来

 ctr -n k8s.io images  pull docker.io/giantswarm/vpa-admission-controller:1.1.2
 ctr -n k8s.io images  pull docker.io/giantswarm/vpa-recommender:1.1.2
 ctr -n k8s.io images  pull docker.io/giantswarm/vpa-updater:1.1.2

ctr -n k8s.io images tag docker.io/giantswarm/vpa-admission-controller:1.1.2 registry.k8s.io/autoscaling/vpa-admission-controller:1.1.2
ctr -n k8s.io images tag docker.io/giantswarm/vpa-recommender:1.1.2 registry.k8s.io/autoscaling/vpa-recommender:1.1.2
ctr -n k8s.io images tag docker.io/giantswarm/vpa-updater:1.1.2 registry.k8s.io/autoscaling/vpa-updater:1.1.2

ctr -n k8s.io   image rm docker.io/giantswarm/vpa-admission-controller:1.1.2
ctr -n k8s.io   image rm docker.io/giantswarm/vpa-recommender:1.1.2
ctr -n k8s.io   image rm docker.io/giantswarm/vpa-updater:1.1.2

应用VPA并验证

git clone https://github.com/kubernetes/autoscaler.git

cd autoscaler/vertical-pod-autoscaler/deploy
sed -i 's/Always/IfNotPresent/g'  recommender-deployment.yaml
sed -i 's/Always/IfNotPresent/g'  admission-controller-deployment.yaml
sed -i 's/Always/IfNotPresent/g'  updater-deployment.yaml

cd ../hack
./vpa-up.sh

验证VPA是否安装上了
《K8S之HPA与VPA的应用部署》

[root@k8s-master01 hack]# kubectl get customresourcedefinition | grep verticalpodautoscalers
verticalpodautoscalers.autoscaling.k8s.io 2024-05-23T02:54:50Z

VPA测试

cat > vpa.yml <<EOF
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: nginx-vpa-test
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: php-apache
  updatePolicy:
    updateMode: "Off"
  resourcePolicy:
    containerPolicies:
    - containerName: "php-apache"
      minAllowed:
        cpu: "250m"
        memory: "100Mi"
      maxAllowed:
        cpu: "2000m"
        memory: "2048Mi"
      controlledResources: ["cpu", "memory"]
EOF
kubectl apply -f vpa.yml

[root@k8s-master01 hpa]# kubectl get vpa
NAME MODE CPU MEM PROVIDED AGE
nginx-vpa-test Off 250m 262144k True 21m

首先删除hap防止干扰,两者冲突,不要放在一起使用
kubectl delete hpa php-apache

开一个窗口监视
kubectl describe vpa nginx-vpa-test |tail -n 20

Conditions:
    Last Transition Time:  2024-05-23T03:25:27Z
    Status:                True
    Type:                  RecommendationProvided
  Recommendation:
    Container Recommendations:
      Container Name:  php-apache
      Lower Bound:
        Cpu:     250m
        Memory:  262144k
      Target:
        Cpu:     250m
        Memory:  262144k
      Uncapped Target:
        Cpu:     25m
        Memory:  262144k
      Upper Bound:
        Cpu:     2
        Memory:  332193153
Events:          <none>
运行压力测试pod
kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://php-apache; done"

可以看到Uncapped Target变大了
《K8S之HPA与VPA的应用部署》

《K8S之HPA与VPA的应用部署》
ctrl +c结束 load-generator

high-availability-1.21+.yaml文件内容

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    k8s-app: metrics-server
    rbac.authorization.k8s.io/aggregate-to-admin: "true"
    rbac.authorization.k8s.io/aggregate-to-edit: "true"
    rbac.authorization.k8s.io/aggregate-to-view: "true"
  name: system:aggregated-metrics-reader
rules:
- apiGroups:
  - metrics.k8s.io
  resources:
  - pods
  - nodes
  verbs:
  - get
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    k8s-app: metrics-server
  name: system:metrics-server
rules:
- apiGroups:
  - ""
  resources:
  - nodes/metrics
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - pods
  - nodes
  verbs:
  - get
  - list
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server-auth-reader
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: extension-apiserver-authentication-reader
subjects:
- kind: ServiceAccount
  name: metrics-server
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server:system:auth-delegator
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
subjects:
- kind: ServiceAccount
  name: metrics-server
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    k8s-app: metrics-server
  name: system:metrics-server
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:metrics-server
subjects:
- kind: ServiceAccount
  name: metrics-server
  namespace: kube-system
---
apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
spec:
  ports:
  - name: https
    port: 443
    protocol: TCP
    targetPort: https
  selector:
    k8s-app: metrics-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
spec:
  replicas: 2
  selector:
    matchLabels:
      k8s-app: metrics-server
  strategy:
    rollingUpdate:
      maxUnavailable: 1
  template:
    metadata:
      labels:
        k8s-app: metrics-server
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchLabels:
                k8s-app: metrics-server
            namespaces:
            - kube-system
            topologyKey: kubernetes.io/hostname
      containers:
      - args:
        - --cert-dir=/tmp
        - --secure-port=10250
        - --kubelet-preferred-address-types=InternalIP
        - --kubelet-insecure-tls
        - --kubelet-use-node-status-port
        - --metric-resolution=15s
        image: registry.aliyuncs.com/google_containers/metrics-server:v0.7.1
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /livez
            port: https
            scheme: HTTPS
          periodSeconds: 10
        name: metrics-server
        ports:
        - containerPort: 10250
          name: https
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /readyz
            port: https
            scheme: HTTPS
          initialDelaySeconds: 20
          periodSeconds: 10
        resources:
          requests:
            cpu: 100m
            memory: 200Mi
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          readOnlyRootFilesystem: true
          runAsNonRoot: true
          runAsUser: 1000
          seccompProfile:
            type: RuntimeDefault
        volumeMounts:
        - mountPath: /tmp
          name: tmp-dir
      nodeSelector:
        kubernetes.io/os: linux
      priorityClassName: system-cluster-critical
      serviceAccountName: metrics-server
      volumes:
      - emptyDir: {}
        name: tmp-dir
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  labels:
    k8s-app: metrics-server
  name: metrics-server
  namespace: kube-system
spec:
  minAvailable: 1
  selector:
    matchLabels:
      k8s-app: metrics-server
---
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  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

问题及解决

kubectl apply -f hpa.yml

error: resource mapping not found for name: “php-apache” namespace: “default” from “hpa.yml”: no matches for kind “HorizontalPodAutoscaler” in version “autoscaling/v2beta1”
ensure CRDs are installed first
原因apiVersion不对
1.26.8版本应该是

apiVersion: autoscaling/v2

而不是

apiVersion: autoscaling/v2beta1

安装VPA报错”unknown option -addext”

ERROR: Failed to create CA certificate for self-signing. If the error is “unknown option -addext”, update your openssl version or deploy VPA from the vpa-release-0.8 branch.

原因是openssl版本太低,要 version 1.1.1 or higher
切换到低版本的VPA安装

git checkout origin/vpa-release-0.8
./hack/vpa-up.sh

参考

浅谈 Kubernetes Metrics Server
【云原生-Kubernetes篇】HPA 与 Rancher管理工具
K8s降本增效之VPA上篇
一文带你掌握Kubernetes VPA(Pod纵向自动扩缩)

点赞

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注