kubernetes(十六) k8s 弹性伸缩

网友投稿 256 2022-10-27

kubernetes(十六) k8s 弹性伸缩

k8s 弹性伸缩

传统弹性伸缩的困境

弹性伸缩的难点在于及时响应业务的实际负载。

在初始化创建资源之前,提前做好压测,对环境资源的需求上做到资源预留(至少要高出实际20~30%)

kubernetes弹性伸缩布局

常规的做法是给集群资源预留保障集群可用,通常20%左右。这种方式看似没什么问题,但放到Kubernetes中,就会发现如下2个问题。

机器规格不统一造成机器利用率百分比碎片化 在一个Kubernetes集群中,通常不只包含一种规格的机器,假设集群中存在4C8G与16C32G两种规格的机器,对于10%的资源预留,这两种规格代表的意义是完全不同的。

特别是在缩容的场景下,为了保证缩容后集群稳定性,我们一般会一个节点一个节点从集群中摘除,那么如何判断节点是否可以摘除其利用率百分比就是重要的指标。此时如果大规格机器有较低的利用率被判断缩容,那么很有可能会造成节点缩容后,容器重新调度后的争抢。如果优先缩容小规格机器,则可能造成缩容后资源的大量冗余。

机器利用率不单纯依靠宿主机计算 当使用K8s之后,资源申请者无需再关心底层硬件资源了,而对于K8s来说,它通过Request和Limit的方式进行配额,Request表示资源的申请值,Limit表示资源的限制值。

弹性伸缩概念的延伸

不是所有的业务都存在峰值流量,越来越细分的业务形态带来更多成本节省和可用性之间的跳转。

在线负载型:微服务、网站、API 离线任务型:离线计算、机器学习 定时任务型:定时批量计算

不同类型的负载对于弹性伸缩的要求有所不同,在线负载对弹出时间敏感,离线任务对价格敏感,定时任务对调度敏感。

在 Kubernetes 的生态中,在多个维度、多个层次提供了不同的组件来满足不同的伸缩场景。

有三种弹性伸缩:

CA(Cluster Autoscaler):Node级别自动扩/缩容cluster-autoscaler组件 HPA(Horizontal Pod Autoscaler):Pod个数自动扩/缩容 VPA(Vertical Pod Autoscaler):Pod配置自动扩/缩容,主要是CPU、内存,addon-resizer组件

如果在云上建议 HPA 结合 cluster-autoscaler 的方式进行集群的弹性伸缩管理。

Node自动扩缩容

Cluster AutoScaler

扩容:Cluster AutoScaler 定期检测是否有充足的资源来调度新创建的 Pod,当资源不足时会调用 Cloud Provider 创建新的 Node。

缩容:Cluster AutoScaler 也会定期监测 Node 的资源使用情况,当一个 Node 长时间资源利用率都很低时(低于 50%)自动将其所在虚拟机从云服务商中删除。此时,原来的 Pod 会自动调度到其他 Node 上面。

阿里云:

Node节点缩容

查看节点

kubectl get node

设置节点不可调度

$ kubectl cordon k8s-node3 $ kubectl get node NAME STATUS ROLES AGE VERSION k8s-master1 Ready 2d v1.18.8 k8s-node1 Ready 2d v1.18.8 k8s-node2 Ready 2d v1.18.8 k8s-node3 Ready,SchedulingDisabled 81m v1.18.8

驱逐节点上的pod

$ kubectl drain k8s-node3 --ignore-daemonsets

移除节点

$ kubectl delete node k8s-node3

Pod自动扩缩容

Horizontal Pod Autoscaler(HPA,Pod水平自动伸缩),根据资源利用率或者自定义指标自动调整replication controller, deployment 或 replica set,实现部署的自动扩展和缩减,让部署的规模接近于实际服务的负载。HPA不适于无法缩放的对象,例如DaemonSet。

HPA基本原理

在弹性伸缩中,冷却周期是不能逃避的一个话题, 由于评估的度量标准是动态特性,副本的数量可能会不断波动。有时被称为颠簸, 所以在每次做出扩容缩容后,冷却时间是多少。在 HPA 中,默认的扩容冷却周期是 3 分钟,缩容冷却周期是 5 分钟。

可以通过调整kube-controller-manager组件启动参数设置冷却时间:

--horizontal-pod-autoscaler-downscale-delay :扩容冷却 --horizontal-pod-autoscaler-upscale-delay :缩容冷却

HPA的演进历程

目前 HPA 已经支持了 autoscaling/v1、autoscaling/v2beta1和autoscaling/v2beta2 三个大版本 。

$ kubectl api-versions | grep autoscal autoscaling/v1 autoscaling/v2beta1 autoscaling/v2beta2

目前大多数人比较熟悉是autoscaling/v1,这个版本只支持CPU一个指标的弹性伸缩。

而autoscaling/v2beta1增加了支持自定义指标,autoscaling/v2beta2又额外增加了外部指标支持。

而产生这些变化不得不提的是Kubernetes社区对监控与监控指标的认识与转变。从早期Heapster到Metrics Server再到将指标边界进行划分,一直在丰富监控生态。

示例:

v1版本

apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata:   name: php-apache   namespace: default spec:   scaleTargetRef:     apiVersion: apps/v1     kind: Deployment     name: php-apache   minReplicas: 1   maxReplicas: 10   targetCPUUtilizationPercentage: 50

v2beta2版本

apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: php-apache namespace: default spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: php-apache minReplicas: 1 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 - type: Pods pods: metric: name: packets-per-second target: type: AverageValue averageValue: 1k - type: Object object: metric: name: requests-per-second describedObject: apiVersion: networking.k8s.io/v1beta1 kind: Ingress name: main-route target: type: Value value: 10k - type: External external: metric: name: queue_messages_ready selector: "queue=worker_tasks" target: type: AverageValue averageValue: 30

基于CPU指标缩放

Kubernetes API Aggregation

当你访问 apis/metrics.k8s.io/v1beta1 的时候,实际上访问到的是一个叫作 kube-aggregator 的代理。而 kube-apiserver,正是这个代理的一个后端;而 Metrics Server,则是另一个后端 。通过这种方式,我们就可以很方便地扩展 Kubernetes 的 API 了。

如果你使用kubeadm部署的,默认已开启。如果你使用二进制方式部署的话,需要在kube-APIServer中添加启动参数,增加以下配置:

添加apiserver聚合层配置

$ vi /data/kubernetes/cfg/kube-apiserver.conf ... --requestheader-client-ca-file=/data/kubernetes/ssl/ca.pem \ --proxy-client-cert-file=/data/kubernetes/ssl/server.pem \ --proxy-client-key-file=/data/kubernetes/ssl/server-key.pem \ --requestheader-allowed-names=kubernetes \ --requestheader-extra-headers-prefix=X-Remote-Extra- \ --requestheader-group-headers=X-Remote-Group \ --requestheader-username-headers=X-Remote-User \ --enable-aggregator-routing=true \ $ systemctl restart kube-apiserver

部署metrics Server Metrics Server是一个集群范围的资源使用情况的数据聚合器。作为一个应用部署在集群中。Metric server从每个节点上Kubelet公开的摘要API收集指标。 Metrics server通过Kubernetes聚合器注册在Master APIServer中。

$ wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.7/components.yaml $ vim components.yaml containers: - name: metrics-server image: lizhenliang/metrics-server:v0.3.7 imagePullPolicy: IfNotPresent args: - --cert-dir=/tmp - --secure-port=4443 - --kubelet-insecure-tls - --kubelet-preferred-address-types=InternalIP $ kubectl apply -f components.yaml $ kubectl top node NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% k8s-master1 226m 11% 1271Mi 73% k8s-node1 124m 6% 758Mi 43% k8s-node2 176m 8% 895Mi 51% $ kubectl top pod -A NAMESPACE NAME CPU(cores) MEMORY(bytes) default nfs-client-provisioner-6d868b5856-fdtsf 3m 7Mi default weave-scope-agent-k8s-ui-4zh87 38m 68Mi default weave-scope-agent-k8s-ui-trhzv 24m 77Mi default weave-scope-agent-k8s-ui-w5rk5 29m 66Mi default weave-scope-cluster-agent-k8s-ui-5fc9cd4b58-bk6c5 2m 53Mi default weave-scope-frontend-k8s-ui-547488fcbc-glmnd 15m 126Mi ingress-nginx nginx-ingress-controller-766fb9f77-lndpk 8m 89Mi kube-system coredns-5ffbfd976d-nvm2d 6m 24Mi kube-system kube-flannel-ds-amd64-25xm8 3m 10Mi kube-system kube-flannel-ds-amd64-4jgl4 2m 18Mi kube-system kube-flannel-ds-amd64-xcb69 2m 12Mi kube-system metrics-server-7875f8bf59-fbzdh 1m 13Mi kubernetes-dashboard dashboard-metrics-scraper-6b4884c9d5-xs6r2 1m 10Mi kubernetes-dashboard kubernetes-dashboard-7f99b75bf4-2mp6k 4m 17Mi

添加最后两行: kubelet-insecure-tls 访问kubelet忽略tls证书效验 kubelet-preferred-address-types=InternalIP 使用 ip连接kubelet 可通过Metrics API在Kubernetes中获得资源使用率指标,例如容器CPU和内存使用率。这些度量标准既可以由用户直接访问(例如,通过使用kubectl top命令),也可以由集群中的控制器(例如,Horizontal Pod Autoscaler)用于进行决策。

测试

$ kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes $ kubectl top node $ kubectl get apiservice

autoscaling/v1(CPU指标实践)

autoscaling/v1版本只支持CPU一个指标。

首先部署一个应用:

$ vim deploy_web.yml apiVersion: apps/v1 kind: Deployment metadata: name: web spec: replicas: 1 selector: matchLabels: app: java-demo template: metadata: labels: app: java-demo spec: containers: - image: lizhenliang/java-demo name: java resources: requests: memory: "300Mi" cpu: "250m" --- apiVersion: v1 kind: Service metadata: name: web spec: ports: - port: 80 protocol: TCP targetPort: 8080 selector: app: java-demo $ kubectl apply -f deploy_web.yml

创建HPA策略:

$ vim hpa_web.yml apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: web spec: maxReplicas: 5 minReplicas: 1 scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: web targetCPUUtilizationPercentage: 60 $ kubectl apply -f hpa_web.yml $ kubectl get hpa

scaleTargetRef:表示当前要伸缩对象是谁

targetCPUUtilizationPercentage:当整体的资源利用率超过50%的时候,会进行扩容。

开启压测:

$ yum install httpd-tools $ ab -c 1000 -n 100000 为ClusterIP。

检查扩容状态:

$ kubectl get hpa $ kubectl top pods $ kubectl get pods

关闭压测,过一会检查缩容状态。

工作流程:hpa -> apiserver -> kube aggregation -> metrics-server -> kubelet(cadvisor)

autoscaling/v2beta2(多指标)

为满足更多的需求, HPA 还有 autoscaling/v2beta1和 autoscaling/v2beta2两个版本。

这两个版本的区别是 autoscaling/v1beta1支持了 Resource Metrics(CPU)和 Custom Metrics(应用程序指标),而在 autoscaling/v2beta2的版本中额外增加了 External Metrics的支持。

apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: web namespace: default spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: web minReplicas: 1 maxReplicas: 10 metrics: - resource: type: Resource name: cpu target: averageUtilization: 60 type: Utilization

与上面v1版本效果一样,只不过这里格式有所变化。

v2还支持其他另种类型的度量指标,:Pods和Object。

type: Pods pods: metric: name: packets-per-second target: type: AverageValue averageValue: 1k

type: Object object: metric: name: requests-per-second describedObject: apiVersion: networking.k8s.io/v1beta1 kind: Ingress name: main-route target: type: Value value: 2k

metrics中的type字段有四种类型的值:Object、Pods、Resource、External。

Resource:指的是当前伸缩对象下的pod的cpu和memory指标,只支持Utilization和AverageValue类型的目标值。 Object:指的是指定k8s内部对象的指标,数据需要第三方adapter提供,只支持Value和AverageValue类型的目标值。 Pods:指的是伸缩对象Pods的指标,数据需要第三方的adapter提供,只允许AverageValue类型的目标值。 External:指的是k8s外部的指标,数据同样需要第三方的adapter提供,只支持Value和AverageValue类型的目标值。

apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: web namespace: default spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: web minReplicas: 1 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 - type: Pods pods: metric: name: packets-per-second target: type: AverageValue averageValue: 1k - type: Object object: metric: name: requests-per-second describedObject: apiVersion: networking.k8s.io/v1beta1 kind: Ingress name: main-route target: type: Value value: 10k

工作流程:hpa -> apiserver -> kube aggregation -> prometheus-adapter -> prometheus -> pods

基于Prometheus自定义指标扩缩容

部署prometheus

Prometheus(普罗米修斯)是一个最初在SoundCloud上构建的监控系统。自2012年成为社区开源项目,拥有非常活跃的开发人员和用户社区。为强调开源及独立维护,Prometheus于2016年加入云原生云计算基金会(CNCF),成为继Kubernetes之后的第二个托管项目。

Prometheus 特点:

多维数据模型:由度量名称和键值对标识的时间序列数据 PromQL:一种灵活的查询语言,可以利用多维数据完成复杂的查询 不依赖分布式存储,单个服务器节点可直接工作 基于HTTP的pull方式采集时间序列数据 推送时间序列数据通过PushGateway组件支持 通过服务发现或静态配置发现目标 多种图形模式及仪表盘支持(grafana)

Prometheus组成及架构:

Prometheus Server:收集指标和存储时间序列数据,并提供查询接口 ClientLibrary:客户端库 Push Gateway:短期存储指标数据。主要用于临时性的任务 Exporters:采集已有的第三方服务监控指标并暴露metrics Alertmanager:告警 Web UI:简单的Web控制台

部署:只部署prometheus,其他可不用部署

$ cd prometheus $ kubectl create ns ops $ ls prometheus-* |xargs -i kubectl apply -f {} $ kubectl get pods -n ops

访问Prometheus UI:Custom Metrics Adapter

但是prometheus采集到的metrics并不能直接给k8s用,因为两者数据格式不兼容,还需要另外一个组件(k8s-prometheus-adpater),将prometheus的metrics 数据格式转换成k8s API接口能识别的格式,转换以后,因为是自定义API,所以还需要用Kubernetes aggregator在主APIServer中注册,以便直接通过/apis/来访问。

PrometheusAdapter 有一个稳定的Helm Charts,我们直接使用。

先准备下helm环境:

wget https://get.helm.sh/helm-v3.2.4-linux-amd64.tar.gz tar zxvf helm-v3.2.4-linux-amd64.tar.gz mv linux-amd64/helm /usr/bin/ helm repo add stable http://mirror.azure.cn/kubernetes/charts helm repo update helm repo list

部署prometheus-adapter,指定prometheus地址:

$ helm install prometheus-adapter stable/prometheus-adapter --namespace ops --set prometheus.url=Kubernetes cluster unreachable”,请指定:

export KUBERNETES_MASTER=kubectl get pod -n ops

确保适配器注册到APIServer:

$ kubectl get apiservices |grep custom $ kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1"

基于QPS指标实践

部署一个应用:

$ vim qps_demo.yml apiVersion: apps/v1 kind: Deployment metadata: labels: app: metrics-app name: metrics-app spec: replicas: 3 selector: matchLabels: app: metrics-app template: metadata: labels: app: metrics-app annotations: prometheus.io/scrape: "true" prometheus.io/port: "80" prometheus.io/path: "/metrics" spec: containers: - image: lizhenliang/metrics-app name: metrics-app ports: - name: web containerPort: 80 resources: requests: cpu: 200m memory: 256Mi readinessProbe: httpGet: path: / port: 80 initialDelaySeconds: 3 periodSeconds: 5 livenessProbe: httpGet: path: / port: 80 initialDelaySeconds: 3 periodSeconds: 5 --- apiVersion: v1 kind: Service metadata: name: metrics-app labels: app: metrics-app spec: ports: - name: web port: 80 targetPort: 80 selector: app: metrics-app $ kubectl apply -f qps_demo.yml $ kubectl get svc #获取SVC IP $ curl 10.0.0.15/metrics #访问metrics即可获取值

访问 vim qps-hpa-v2.yml apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: metrics-app-hpa namespace: default spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: metrics-app minReplicas: 1 maxReplicas: 10 metrics: - type: Pods pods: metric: name: http_requests_per_second target: type: AverageValue averageValue: 800m # 800m 即0.8个/秒 $ kubectl apply -f qps-hpa-v2.yml

这里使用Prometheus提供的指标测试来测试自定义指标(QPS)的自动缩放.

配置适配器收集特定的指标 指定如何获取prometheus的metrics数据(promql) 映射关系(adapter和prometheus之间的映射) 从prometheus拿到的数据暴露给api

当创建好HPA还没结束,因为适配器还不知道你要什么指标(ConfigMap在default名称空间中编辑prometheus-adapter ,并seriesQuery在该rules: 部分的顶部添加一新的配置

$ kubectl edit cm prometheus-adapter -n ops rules: - seriesQuery: 'http_requests_total{kubernetes_namespace!="",kubernetes_pod_name!=""}' resources: overrides: kubernetes_namespace: {resource: "namespace"} kubernetes_pod_name: {resource: "pod"} name: matches: "^(.*)_total" as: "${1}_per_second" metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)' $ kubectl delete pod $(kubectl get pod -n ops | grep prometheus-adapter | awk '{print $1}') -n ops

测试api

kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/ab -n 100000 -c 100 kubectl get hpa,pod NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE horizontalpodautoscaler.autoscaling/metrics-app-hpa Deployment/metrics-app 90633m/800m 1 10 10 76m NAME READY STATUS RESTARTS AGE pod/metrics-app-b4d7dd845-28wkm 1/1 Running 0 84s pod/metrics-app-b4d7dd845-5z292 1/1 Running 0 100s pod/metrics-app-b4d7dd845-cnzbb 1/1 Running 0 84s pod/metrics-app-b4d7dd845-csf2h 1/1 Running 0 84s pod/metrics-app-b4d7dd845-d4r5h 1/1 Running 0 148m pod/metrics-app-b4d7dd845-dtxr6 1/1 Running 0 100s pod/metrics-app-b4d7dd845-dvdw2 1/1 Running 0 69s pod/metrics-app-b4d7dd845-qr7vr 1/1 Running 0 84s pod/metrics-app-b4d7dd845-sbqvh 1/1 Running 0 69s pod/metrics-app-b4d7dd845-std97 1/1 Running 0 148m pod/nfs-client-provisioner-6d868b5856-wsmsj 1/1 Running 0 42m

小结

通过/metrics收集每个Pod的http_request_total指标; prometheus将收集到的信息汇总; APIServer定时从Prometheus查询,获取request_per_second的数据; HPA定期向APIServer查询以判断是否符合配置的autoscaler规则; 如果符合autoscaler规则,则修改Deployment的ReplicaSet副本数量进行伸缩。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:富士通半导体推出可支持10种不同接口的接口桥接芯片MB86E631
下一篇:USB-C是传统接口向前迈进了一大步 采用USB-C接口的iPhone更加出色
相关文章

 发表评论

暂时没有评论,来抢沙发吧~