苏州高新区网站建设,导购类网站备案,不属于企业网站建设基本标准的是,临时域名用于网站调试【云原生•监控】基于Prometheus实现自定义指标弹性伸缩(HPA) 什么是弹性伸缩 「Autoscaling即弹性伸缩#xff0c;是Kubernetes中的一种非常核心的功能#xff0c;它可以根据给定的指标#xff08;例如 CPU 或内存#xff09;自动缩放Pod副本#xff0c;从而可以更好地管… 【云原生•监控】基于Prometheus实现自定义指标弹性伸缩(HPA) 什么是弹性伸缩 「Autoscaling即弹性伸缩是Kubernetes中的一种非常核心的功能它可以根据给定的指标例如 CPU 或内存自动缩放Pod副本从而可以更好地管理和利用计算资源提高系统的可用性和性能同时减少开销和成本。弹性伸缩可以解决服务负载存在较大波动或资源实际使用与预估之间的差距。」 在Kubernetes集群中提供了三种弹性伸缩技术 「CACluster Autoscaler」Node级别自动扩/缩容「HPAHorizontal Pod Autoscaler」Pod个数自动扩/缩容「VPAVertical Pod Autoscaler」Pod配置自动扩/缩容主要是CPU、内存配置 「Node自动扩/缩容」 Cluster AutoScaler定期检测是否有充足的资源来调度新创建的Pod当资源不足时会调用Cloud Provider创建新的Node。Cluster AutoScaler也会定期监测 Node的资源使用情况当一个Node长时间资源利用率都很低时低于50%自动将其所在虚拟机从集群中删除。此时原来的Pod会自动调度到其他Node上面。 Node的增减可能会影响整个kubernetes集群的稳定性一旦出现问题会影响整个集群上部署的所有业务程序所以生产中针对Node节点的扩缩容一般还是谨慎使用当确实需要对Node进行扩缩容时往往通过人工执行脚本完成。 「Pod的垂直扩/缩容(VPA)」 VPA全称Vertical Pod Autoscaler即Pod的垂直自动伸缩它根据容器资源使用率自动设置CPU和内存的requests从而允许在节点上进行适当的调度以便为每个Pod提供适当的资源。它既可以缩小过度请求资源的容器也可以根据其使用情况随时提升资源不足的容量。 「目前VPA技术成熟度还不够是Kubernetes比较新的功能更新正在运行的Pod资源配置是VPA的一项试验性功能会导致Pod的重建和重启而且有可能被调度到其他的节点上。」 「Pod的水平扩/缩容(HPA)」 HPA全称Horizontal Pod Autoscaler即Pod的水平自动伸缩根据资源利用率或者自定义指标自动调整Pod的副本数实现Pod的扩容、缩容让部署的规模接近于实际服务的负载。 HPA弹性伸缩原理 Horizontal Pod Autoscaler功能最初是在Kubernetes 1.1中引入并不断发展目前HPA已经支持了autoscaling/v1、autoscaling/v2beta1和autoscaling/v2beta2三个大版本。 常规场景下比如晚上业务压力较小情况下可以使用kubectl scale指令将Pod副本数设置为1当白天上班高分期业务压力大时使用kubectl scale指令将Pod的副本数设置为3但这些操作都是人为介入执行的。而HPA控制器则是基于业务的指标判断业务忙闲自动基于算法计算出当前多少Pod副本数运行比较合适自动调整Pod的副本数。 Kubernetes HPA v2相对于v1版本进行了一些重大改进。其中最显著的改进是引入了「多指标」自动扩缩容即可以同时根据多种指标如 CPU使用率、内存使用率、网络负载等来进行自动扩缩容决策。此外HPA v2还增加了支持「自定义指标」的能力使得用户可以根据自己的需求定义和使用自己的指标。总的来说Kubernetes HPA v2是一个更加成熟、更加灵活和可定制的自动扩缩容机制。 「HPA弹性伸缩的核心机制自动根据业务忙闲来调整业务工作负载的副本数。这里主要涉及到两个关键点」 「如何识别业务的忙闲程度」「使用控制Pod副本数调整」 「我们先来看下第一个问题如何识别业务的忙闲程度」 之前介绍kubernetes集群监控时介绍过metrics-server组件可以从集群中所有节点的kubelet组件中cAdvisor上获取到底层容器运行时指标然后聚合后就可以通过kubectl top node/pod查看CPU、内存资源使用情况也可以通过kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes 接口访问访问获取。所以HPA控制器可以通过metrics-server组件获取Pod的CPU、内存使用率识别业务忙闲。 Kubernestes 1.7引入了聚合层(Aggregator)允许第三方应用程序通过注册自己为API插件来扩展Kubernestes API。metrics-server组件注册到聚合层然后就可以像访问kube-apiserver接口一样访问metrics-server后端服务的接口。 Kubernetes在kube-apiserver服务中引入了一个API聚合层用于将扩展API的访问请求转发到用户服务的功能。比如当你访问apis/metrics.k8s.io/v1beta1的时候aggregator组件会基于group和version转发到后端metrics-server服务上聚合层只是相当于代理层。通过这种方式我们就可以很方便地扩展Kubernetes的API。 从metrics-server获取CPU、内存指标比较单一kubernetes集群监控事实标准是prometheus如果可以从prometheus获取指标用来识别业务忙闲程度弹性伸缩灵活性就会大大增加。prometheus-adapter组件就可以实现这个功能它从prometheus拉取指标转换成kubernetes api接口识别的数据格式并将其注册到聚合层这样kubernetes集群中其它服务就可以通过/apis/访问。 「再来看第二个问题如何控制Pod副本数调整」 HPA控制器会定期执行每个HPA对象的reconcile方法主要包含如何操作 获取当前指标数据从metrics-server获取CPU使用率、内存使用率或从prometheus-adapter获取自定义指标数据Pod副本数计算将获取的指标数据和目标期望比较判断是要扩容、缩容还是不变若不需要要进行扩缩容调整就直接返回当前副本数否则才使用HPA metrics 目标类型对应的算法来计算出deployment的目标副本数更新Pod副本数如果上步骤计算出的Pod目标副本数与当前副本数量不一致时即需要进行扩/缩容的情况则HPA控制器就向Deploymen发起scale操作调整当前副本数完成扩/缩容操作监控调整效果最终实现尽可能将deployment下的每个pod的最终metrics指标平均值基本维持到用户期望的水平HPA会继续监控新的Pod副本数量对指标数据的影响并根据需要进行进一步的调整。 ❝ reconcile定时间隔默认15秒可以通过horizontal-pod-autoscaler-sync-period配置。 ❞ 基于CPU指标的HPA HPA v1版本支持CPU使用率、内存使用率的弹性伸缩内存使用率一般缓存影响很难真实反映系统负载所以一般使用CPU使用率指标来进行弹性伸缩。容器的CPU使用率可以通过聚合层API代理到后端metrics-server服务metrics-server向所有的kubelet组件发送请求通过cAdvisor收集到所有容器的CPU、内存运行信息这样HPA控制器就可以获取到Pod的CPU使用率然后基于CPU使用率进行弹性伸缩。 「1、基于Deployment创建Pod」 #vi deploy-for-hpa_cpu.yml
apiVersion: apps/v1
kind: Deployment
metadata:name: web
spec:replicas: 1selector:matchLabels:app: nginx-phptemplate:metadata:labels:app: nginx-phpspec:containers:- image: lizhenliang/nginx-phpname: javaresources: requests:memory: 300Micpu: 250m
---
apiVersion: v1
kind: Service
metadata:name: web
spec:ports:- port: 80protocol: TCPtargetPort: 80selector:app: nginx-php 「2、创建」 [rootk8s-01 autoscaling]# kubectl apply -f deploy-for-hpa_cpu.yml -n demo01
[rootk8s-01 autoscaling]# kubectl get pod -n demo01
NAME READY STATUS RESTARTS AGE
web-84885d5959-fbtxt 1/1 Running 0 29s 「3、HPA策略文件」 # vi hpa_for_cpu.yml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:name: web
spec:#扩/缩容副本范围maxReplicas: 3minReplicas: 1#指定扩容的DeploymentscaleTargetRef: apiVersion: apps/v1kind: Deploymentname: webtargetCPUUtilizationPercentage: 60 ❝ targetCPUUtilizationPercentage: 60 表示当Pod整体的资源利用率超过60%的时候会进行扩容。 ❞ 「4、创建HPA」 [rootk8s-01 autoscaling]# kubectl apply -f hpa_for_cpu.yml -n demo01
horizontalpodautoscaler.autoscaling/web created
[rootk8s-01 autoscaling]# kubectl get hpa -n demo01
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
web Deployment/web 0%/60% 1 3 1 44s ❝ TARGETS一栏显示指标情况前面0%表示当前Pod得到整体CPU资源使用率因为没有任何HTTP请求所以是0%60%则是扩/缩容阈值。 MINPODS、MAXPODS指定hpa扩/缩容 ❞ 「5、压测」 [rootk8s-01 autoscaling]# yum install httpd-tools
[rootk8s-01 autoscaling]# kubectl get svc -n demo01
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web ClusterIP 10.96.237.204 none 80/TCP 5d20h
[rootk8s-01 autoscaling]# ab -n 100000 -c 100 http://10.96.237.204/status.php 「6、观察扩/缩容」 压测几十秒后查看hpa后发现整体CPU使用率173%超过60%目标值但是replicas还是1并没有扩容 [rootk8s-01 autoscaling]# kubectl get hpa -n demo01
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
metrics-app-hpa Deployment/sample-httpserver2 200m/2 1 3 1 46h
web Deployment/web 173%/60% 1 3 1 75s 再等会查看到replicas3触发了扩容操作 [rootk8s-01 autoscaling]# kubectl get hpa -n demo01
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
metrics-app-hpa Deployment/sample-httpserver2 200m/2 1 3 1 46h
web Deployment/web 15%/60% 1 3 3 76s 查看Pod信息 [rootk8s-01 autoscaling]# kubectl get pod -n demo01
NAME READY STATUS RESTARTS AGE
web-84885d5959-d9l4h 1/1 Running 0 90s
web-84885d5959-fbtxt 1/1 Running 0 6m9s
web-84885d5959-xgn4n 1/1 Running 0 90s kubectl describe hpa信息可以看到有一条副本数扩到3的消息事件 停止压测后CPU使用率压力会降下来大概等个几分钟后又会触发缩容操作replicas又会被设置成1 [rootk8s-01 autoscaling]# kubectl get hpa -n demo01
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
web Deployment/web 0%/60% 1 3 1 7m59s kubectl describe hpa查看hpa信息会发现有两条缩容消息事件一条显示是副本数从3缩容到2消息事件另一条显示副本数从2缩容到1消息事件 基于Prometheus自定义指标的HPA 基于metrics-server组件获取的CPU使用率、内存使用率弹性伸缩灵活性稍差如果想根据自定义指标如HTTP请求的QPS、5XX错误数等在云原生领域监控基本就是Prometheus。自定义指标由Prometheus来提供再利用prometheus-adpater聚合到apiserver实现从metric-server组件获取CPU、内存同样的效果。 基于Prometheus自定义指标的HPA核心流程如下图 prometheus-adapter组件部署 「1、安装prometheus-adapter组件」 [rootk8s-01 ~]# helm repo add stable http://mirror.azure.cn/kubernetes/charts
prometheus-community has been added to your repositories
[rootk8s-01 ~]# helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the prometheus-community chart repository
Update Complete. ⎈ Happy Helming!⎈
[rootk8s-01 ~]# helm repo list
NAME URL
stable http://mirror.azure.cn/kubernetes/charts [rootk8s-01 ~]# helm install prometheus-adapter stable/prometheus-adapter --namespace monitoring --set prometheus.urlhttp://prometheus,prometheus.port9090
NAME: prometheus-adapter
LAST DEPLOYED: Tue Aug 1 23:44:08 2023
NAMESPACE: monitoring
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
prometheus-adapter has been deployed.
In a few minutes you should be able to list metrics using the following command(s):kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1 ❝ curl http://192.168.31.160:32478/metrics ❞ 「2、查看组件安装是否成功」 [rootk8s-01 ~]# kubectl get pod -n monitoring
NAME READY STATUS RESTARTS AGE
prometheus-adapter-76d8fb4549-6vzzg 1/1 Running 0 3m25s[rootk8s-01 ~]# kubectl get apiservices
NAME SERVICE AVAILABLE AGE
...
v1beta1.custom.metrics.k8s.io monitoring/prometheus-adapter True 2m28s[rootk8s-01 ~]# kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1 |jq|more
{kind: APIResourceList,apiVersion: v1,groupVersion: custom.metrics.k8s.io/v1beta1,resources: [{name: namespaces/file_descriptors,singularName: ,namespaced: false,kind: MetricValueList,verbs: [get]},{name: namespaces/kube_ingress_annotations,singularName: ,namespaced: false,kind: MetricValueList,verbs: [get]},
... ❝ 查看prometheus-adapter组件的日志注意不要出现类似http://prometheus:9090/api/v1/series?match%5B%5D%7B__name__%3D~%22%5Econtainer_.%2A%22%2Ccontainer%21%3D%22POD%22%2Cnamespace%21%3D%22%22%2Cpod%21%3D%22%22%7Dstart1690905427.938 timeout 这样错误。 ❞ helm卸载操作如下 [rootk8s-01 ~]# helm ls -n kube-system
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
prometheus-adapter kube-system 1 2023-08-01 23:44:08.027994527 0800 CST deployed prometheus-adapter-4.3.0 v0.11.0
[rootk8s-01 ~]# helm uninstall prometheus-adapter -n kube-system
release prometheus-adapter uninstalled 部署golang应用 「1、初始化golang项目工程」 [rootswarm-manager ~]# mkdir metrics
[rootswarm-manager ~]# cd metrics/
[rootswarm-manager metrics]# go mod init metrics 「2、编写metrics.go」 package mainimport (github.com/prometheus/client_golang/prometheusgithub.com/prometheus/client_golang/prometheus/promhttpnet/httpstrconv
)func main() {metrics : prometheus.NewCounterVec(prometheus.CounterOpts{Name: http_requests_total,Help: Number of total http requests,},[]string{status},)prometheus.MustRegister(metrics)http.HandleFunc(/, func(w http.ResponseWriter, r *http.Request) {path : r.URL.PathstatusCode : 200switch path {case /metrics:promhttp.Handler().ServeHTTP(w, r)default:w.WriteHeader(statusCode)w.Write([]byte(Hello World!))}metrics.WithLabelValues(strconv.Itoa(statusCode)).Inc()})http.ListenAndServe(:3000, nil)
} ❝ 该go项目主要通过/metrics端点暴露http_requests_total指标。 ❞ 「3、本地编译打包」 [rootswarm-manager metrics]# go mod tidy
[rootswarm-manager metrics]# go build -o metrics metrics.go 「4、创建镜像并推送docker hub上」 编写Dockerfile FROM golang:latest
MAINTAINER simon 30743905qq.com
RUN mkdir -p /app
WORKDIR /app
COPY ./metrics /app
EXPOSE 3000RUN chmod x ./metrics
ENTRYPOINT [./metrics] 构建镜像 docker build -t metrics . 「5、k8s部署」 # sample-httpserver-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: sample-httpservername: sample-httpservernamespace: default
spec:replicas: 1selector:matchLabels:app: sample-httpserverstrategy: {}template:metadata:annotations:prometheus.io/scrape: trueprometheus.io/path: /metricsprometheus.io/port: 3000labels:app: sample-httpserverspec:containers:- image: addozhang/httpserver-n-metrics:latestname: httpserver-n-metricsports:- containerPort: 3000resources:requests:memory: 300Mi
---
apiVersion: v1
kind: Service
metadata:name: sample-httpserverlabels:app: sample-httpserver
spec:ports:- name: webport: 3000targetPort: 3000selector:app: sample-httpserver 「6、接口获取指标正常」 [rootk8s-01 demo01]# kubectl get svc -n demo01
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service ClusterIP None none 80/TCP 249d
sample-httpserver ClusterIP 10.96.153.13 none 3000/TCP 32s
tomcat-service ClusterIP None none 8080/TCP 249d
web ClusterIP 10.96.237.204 none 80/TCP 47h
[rootk8s-01 demo01]# curl 10.96.153.13:3000/metrics
# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile0} 3.5147e-05
go_gc_duration_seconds{quantile0.25} 3.8423e-05
go_gc_duration_seconds{quantile0.5} 4.1267e-05
go_gc_duration_seconds{quantile0.75} 5.0566e-05
go_gc_duration_seconds{quantile1} 9.0761e-05
go_gc_duration_seconds_sum 0.001240037
go_gc_duration_seconds_count 25
...... 「7、prometheus配置抓取job」 - job_name: appkubernetes_sd_configs:- role: podrelabel_configs:- action: keepsource_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]regex: true- source_labels: [__meta_kubernetes_namespace]target_label: namespace- source_labels: [__meta_kubernetes_pod_name]target_label: pod 「8、指标抓取验证」 在prometheus target可以查看到部署的应用指标接入成功 使用PromQL查询sum(rate(http_requests_total[30s])) by (pod) hpa资源创建 「1、创建hpa」 # vi app-hpa-v2.yml
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:name: metrics-app-hpa namespace: demo01
spec:scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: sample-httpserverminReplicas: 1maxReplicas: 3metrics:- type: Podspods:metric:name: http_requests_qpstarget:type: AverageValueaverageValue: 2000m # 2000m 即2个/秒 「2、prometheus-adapter组件配置自定义指标的计算规则告诉prometheus-adapter如何从prometheus获取指标并计算出我们需要的指标kubectl edit cm prometheus-adapter -n monitoring」 ❝ prometheus-adapter不能动态加载配置需要kubectl delete pod prometheus-adapter-xx让Pod重启加载最新配置。 ❞ 「3、可以访问api-server获取到prometheus-adapter计算生成的新指标」 [rootk8s-01 ~]# kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1/namespaces/demo01/pods/*/http_requests_qps | jq
{kind: MetricValueList,apiVersion: custom.metrics.k8s.io/v1beta1,metadata: {selfLink: /apis/custom.metrics.k8s.io/v1beta1/namespaces/demo01/pods/%2A/http_requests_qps},items: [{describedObject: {kind: Pod,namespace: demo01,name: sample-httpserver-695f994dbd-s2s2g,apiVersion: /v1},metricName: http_requests_qps,timestamp: 2023-08-02T15:32:56Z,value: 66m,selector: null}]
} ❝ 「注意这里的 value: 66m值的后缀“m” 标识 milli-requests per seconds所以这里的 66m 的意思是 0.06/s 每秒0.06个请求。」 ❞ 「4、prometheus-adapter有了指标数据就可以创建hpa基于该指标kubectl apply -f app-hpa-v2.yml」 # vi app-hpa-v2.yml
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:name: metrics-app-hpanamespace: demo01
spec:scaleTargetRef:apiVersion: apps/v1kind: Deploymentname: sample-httpserverminReplicas: 1maxReplicas: 3metrics:- type: Podspods:metric:name: http_requests_qpstarget:type: AverageValueaverageValue: 2000m # 2000m 即2个/秒 「5、查看hpa从prometheus-adapter组件获取指标正常」 当前Pod副本数为1 「6、接口压测」 [rootk8s-01 ~]# kubectl get svc -n demo01
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service ClusterIP None none 80/TCP 249d
sample-httpserver ClusterIP 10.96.153.13 none 3000/TCP 8m11s
[rootk8s-01 ~]# ab -n 100000 -c 30 http://10.96.153.13:3000/metrics
This is ApacheBench, Version 2.3 $Revision: 1430300 $
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking 10.96.153.13 (be patient)
Completed 10000 requests
Completed 20000 requests 「7、弹性伸缩验证」 查看hpa状态targets一栏显示当前指标到达10900m左右斜杠后面2表示到达2就要弹性伸缩10900m/100010左右明显超过2则replicas一栏显示当前进行扩容到最大副本数3: 查看hpa描述信息可以看到有条Event清晰描述出有图http_requests_qps指标超过target设置的2副本数设置为3 再来看pod信息发现副本数确实扩容到3个 「8、弹性缩容验证」 停止接口压测后hpa指标下降200m明显小于2当大概平稳5分钟后hpa开始进行缩容将副本数从3降到1 查看hpa描述信息同样印证了hpa发生缩容 再来确认下Pod已经变成1个了