k8s版本v1.20
從傳統意義上,彈性伸縮主要解決的問題是容量規划與實際負載的矛盾。
藍色水位線表示集群資源容量隨着負載的增加不斷擴容,紅色曲線表示集群資源實際負載變化。
彈性伸縮就是要解決當實際負載增大,而集群資源容量沒來得及反應的問題。
1 Kubernetes中彈性伸縮存在的問題
常規的做法是給集群資源預留保障集群可用,通常20%左右。這種方式看似沒什么問題,但放到Kubernetes中,就會發現如下2個問題。
(1) 機器規格不統一造成機器利用率百分比碎片化
在一個Kubernetes集群中,通常不只包含一種規格的機器,假設集群中存在4C8G與16C32G兩種規格的機器,對於10%的資源預留,這兩種規格代表的意義是完全不同的。
特別是在縮容的場景下,為了保證縮容后集群穩定性,我們一般會一個節點一個節點從集群中摘除,那么如何判斷節點是否可以摘除其利用率百分比就是重要的指標。此時如果大規則機器有較低的利用率被判斷縮容,那么很有可能會造成節點縮容后,容器重新調度后的爭搶。如果優先縮容小規則機器,則可能造成縮容后資源的大量冗余。
(2) 機器利用率不單純依靠宿主機計算
在大部分生產環境中,資源利用率都不會保持一個高的水位,但從調度來講,調度應該保持一個比較高的水位,這樣才能保障集群穩定性,又不過多浪費資源。
2 彈性伸縮概念的延伸
不是所有的業務都存在峰值流量,越來越細分的業務形態帶來更多成本節省和可用性之間的跳轉。
(1) 在線負載型:微服務、網站、API (2) 離線任務型:離線計算、機器學習 (3) 定時任務型:定時批量計算 不同類型的負載對於彈性伸縮的要求有所不同,在線負載對彈出時間敏感,離線任務對價格敏感,定時任務對調度敏感。
2.2 kubernetes 彈性伸縮布局
1 在 Kubernetes 的生態中,在多個維度、多個層次提供了不同的組件來滿足不同的伸縮場景
有三種彈性伸縮:
(1) CA(Cluster Autoscaler): Node級別自動擴/縮容cluster-autoscaler組件。 (2) HPA(Horizontal Pod Autoscaler): Pod個數自動擴/縮容。 (3) VPA(Vertical Pod Autoscaler): Pod配置自動擴/縮容,主要是CPU、內存。addon-resizer組件
如果在雲上建議 HPA 結合 cluster-autoscaler 的方式進行集群的彈性伸縮管理。
2 在Kubernetes平台中,資源分為兩個維度 (1) Node級別:K8s將多台服務器抽象一個集群資源池,每個Node提供這些資源 (2) Pod級別:Pod是K8s最小部署單元,運行實際的應用程序,使用request和limit為Pod配額
因此,K8s實現彈性伸縮也是這兩個級別,當Node資源充裕情況下,Pod可任意彈性,當不足情況下需要彈性增加節 點來擴容資源池。 (3) 針對Pod負載:當Pod資源不足時,使用HPA(Horizontal Pod Autoscaler)自動增加Pod副本數量 (4) 針對Node負載:當集群資源池不足時,使用CA(Cluster Autoscaler)自動增加Node
3 Node彈性伸縮有兩種方案 (1) Cluster Autoscaler:是一個自動調整Kubernetes集群大小的組件,需要與公有雲一起使用,例如AWS、Azure、Aliyun 項目地址:https://github.com/kubernetes/autoscaler (2) 自研發:根據Node監控指標或者Pod調度狀態判斷是否增加Node,需要一定開發成本
2.3 Node 自動擴容/縮容
1 Cluster AutoScaler
擴容:Cluster AutoScaler 定期檢測是否有充足的資源來調度新創建的 Pod,當資源不足時會調用 Cloud Provider 創建新的 Node。
縮容:Cluster AutoScaler 也會定期監測 Node 的資源使用情況,當一個 Node 長時間資源利用率都很低時(低於 50%)自動將其所在虛擬機從雲服務商中刪除。此時,原來的 Pod 會自動調度到其他 Node 上面。
Cluster Autoscaler支持的雲提供商(阿里雲、aws、azure ......): https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler/cloudprovider/ GCE:https://kubernetes.io/docs/concepts/cluster-administration/cluster-management/ GKE:https://cloud.google.com/container-engine/docs/cluster-autoscaler/
2 自研發-基於Ansible自動增加Node
(1) 觸發新增Node (2) 調用Ansible腳本部署組件 (3) 檢查服務是否可用 (4) 調用API將新Node加入集群或者啟用Node自動加入 (5) 觀察新Node狀態 (6) 完成Node擴容,接收新Pod
3 自研發-基於Ansible自動增加Node
(1) 自動增加Node
https://github.com/HyjyLc/ansible-install-k8s/
1)在k8s主節點添加新增節點的解析(kubectl操作節點時使用的是主機名)
# echo '172.16.1.85 k8s-node3' >> /etc/hosts
2)擴容node
# cd /root/ansible-install-k8s-master/
# vim hosts
[newnode]
172.16.1.85 node_name=k8s-node3
注: /root/ansible-install-k8s-master/roles/node/templates/
bootstrap.kubeconfig.j2、kube-proxy.kubeconfig.j2
文件對多master進行了判斷,如果是多master,kubelet、kube-proxy的kubeconfig使用的是VIP,否則則相反。
# ansible-playbook -i hosts add-node.yml -uroot -k
# kubectl get node
# kubectl get pod -n kube-system -o wide
(2) 自動減少Node
如果你想從Kubernetes集群中刪除節點,正確流程如下
1) 獲取節點列表
kubectl get node
2) 設置不可調度
kubectl cordon <node_name>
3) 驅逐節點上的Pod
kubectl drain <node_name> --ignore-daemonsets
4) 移除節點
kubectl delete node <node_name>
注:
如果這塊自動化的話,前提要獲取長期空閑的Node,然后執行這個步驟。
我這里是二進制部署的k8s,在下線的node節點重新啟動kubelet、kube-proxy服務后就可以重新將下線的node節點注冊上了。
如果是kubeadm部署的k8s,需要在master節點上重新生成node加入k8s集群的token即可。
2.4 Pod自動擴容/縮容(HPA)
1 HPA介紹
Horizontal Pod Autoscaler(HPA,Pod水平自動伸縮),根據資源利用率或者自定義指標自動調整replication controller, deployment 或 replica set,實現部署的自動擴展和縮減,讓部署的規模接近於實際服務的負載。HPA不適用於無法縮放的對象,例如DaemonSet。
2 使用HPA前提條件
(1) 使用HPA,確保滿足以下條件 1)啟用Kubernetes API聚合層 2)相應的API已注冊 對於資源指標(例如CPU、內存),將使用metrics.k8s.io API,一般由metrics-server提供。 對於自定義指標(例如QPS),將使用custom.metrics.k8s.io API,由相關適配器(Adapter)服務提供。 已知適配器列表:https://github.com/kubernetes/metrics/blob/master/IMPLEMENTATIONS.md#custom-metrics-api
(2) Kubernetes API Aggregation
在 Kubernetes 1.7 版本引入了聚合層,允許第三方應用程序通過將自己注冊到kube-apiserver上,仍然通過 API Server 的 HTTP URL 對新的 API 進行訪問和操作。為了實現這個機制,Kubernetes 在 kube-apiserver 服務中引入了一個 API 聚合層(API Aggregation Layer),用於將擴展 API 的訪問請求轉發到用戶服務的功能。
當你訪問 apis/metrics.k8s.io/v1beta1 的時候,實際上訪問到的是一個叫作 kube-aggregator 的代理。而 kube-apiserver,正是這個代理的一個后端;而 Metrics Server,則是另一個后端 。通過這種方式,我們就可以很方便地擴展 Kubernetes 的 API 了。 如果你使用kubeadm部署的,默認已開啟。如果你使用二進制方式部署的話,需要在kube-APIServer中添加啟動參數,增加以下配置:
# vim /opt/kubernetes/cfg/kube-apiserver.conf
......
--requestheader-client-ca-file=/opt/kubernetes/ssl/ca.pem \
--proxy-client-cert-file=/opt/kubernetes/ssl/server.pem \
--proxy-client-key-file=/opt/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 \
......
在設置完成重啟 kube-apiserver 服務,就啟用 API 聚合功能了。
3 HPA冷卻周期
在彈性伸縮中,冷卻周期是不能逃避的一個話題, 由於評估的度量標准是動態特性,副本的數量可能會不斷波動。有時被稱為顛簸, 所以在每次做出擴容縮容后,冷卻時間是多少。在 HPA 中,默認的擴容冷卻周期是 3 分鍾,縮容冷卻周期是 5 分鍾。 可以通過調整 kube-controller-manager 組件啟動參數設置冷卻時間。 --horizontal-pod-autoscaler-downscale-delay // 擴容冷卻 --horizontal-pod-autoscaler-upscale-delay // 縮容冷卻
4 HPA的演進歷程
目前 HPA 已經支持了 autoscaling/v1、autoscaling/v2beta1和autoscaling/v2beta2 三個大版本 。 目前大多數人比較熟悉是autoscaling/v1,這個版本只支持CPU一個指標的彈性伸縮。 而autoscaling/v2beta1增加了支持自定義指標,autoscaling/v2beta2又額外增加了外部指標支持。 而產生這些變化不得不提的是Kubernetes社區對監控與監控指標的認識與轉變。從早期Heapster到Metrics Server再到將指標邊界進行划分,一直在豐富監控生態。 (1) autoscaling/v1版本
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: web
namespace: lc
spec:
maxReplicas: 10
minReplicas: 2
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web
targetCPUUtilizationPercentage: 80
(2) autoscaling/v2beta2(多指標)
# kubectl get hpa.v2beta2.autoscaling -o yaml > /tmp/hpa-v2.yaml
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: 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
5 資源指標與自定義指標工作流程
(1) 資源指標工作流程: hpa -> apiserver -> kube aggregation -> metrics-server -> kubelet(cadvisor) (2) 自定義資源指標工作流程: hpa -> apiserver -> kube aggregation -> prometheus-adapter -> prometheus -> pods
2.5 基於CPU資源指標縮放
1 基本工作原理
Kubernetes 中的 Metrics Server 持續采集所有 Pod 副本的指標數據。HPA 控制器通過 Metrics Server 的 API(Heapster 的 API 或聚合 API)獲取這些數據,基於用戶定義的擴縮容規則進行計算,得到目標 Pod 副本數量。當目標 Pod 副本數量與當前副本數量不同時,HPA 控制器就向 Pod 的副本控制器(Deployment、RC 或 ReplicaSet)發起 scale 操作,調整 Pod 的副本數量,完成擴縮容操作。
2 部署 Metrics Server
Metrics Server是一個集群范圍的資源使用情況的數據聚合器,作為一個應用部署在集群中。 Metric server從每個節點上Kubelet公開的摘要API(cadvisor)收集指標。 Metrics server通過Kubernetes聚合器注冊在Master APIServer中。
hpa/kubectl get --raw/kubectl top -> apiserver -> metrics-server(不效驗證書) -> kubelet/cadvisor(https自簽)
兼容性:
(1) 項目地址
https://github.com/kubernetes-sigs/metrics-server/
https://github.com/kubernetes-sigs/metrics-server/releases/
(2) 下載yaml
# wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.5.1/components.yaml
(3) 修改yml文件
# vim components.yaml
# 修改的參數如下
- --kubelet-insecure-tls
image: registry.aliyuncs.com/google_containers/metrics-server:v0.5.1
(4) 部署
# kubectl apply -f components.yaml
(5) 查看容器
# kubectl get pod -n kube-system -o wide | grep metrics-server
metrics-server-6f6f7948b9-w98vc 1/1 Running 0 41s 172.27.224.7 k8s-master2
可通過Metrics API在Kubernetes中獲得資源使用率指標,例如容器CPU和內存使用率。這些度量標准既可以由用戶直接訪問(例如,通過使用kubectl top
命令),也可以由集群中的控制器(例如,Horizontal Pod Autoscaler)用於進行決策。
(6) 測試
1) 查看注冊到apiserver上的metrics-server
# kubectl get apiservices |grep metrics
v1beta1.metrics.k8s.io kube-system/metrics-server True 23m
2) 獲取node,pod的cpu、內存使用量指標
# kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes
# kubectl get --raw /apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods
3) 查看node資源消耗
# kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
k8s-master1 205m 10% 995Mi 25%
k8s-master2 237m 11% 965Mi 25%
k8s-node1 131m 6% 635Mi 16%
k8s-node2 87m 4% 410Mi 10%
4) 查看pod資源消耗(區分命名空間)
# kubectl top pod -n kube-system
NAME CPU(cores) MEMORY(bytes)
calico-kube-controllers-97769f7c7-fnxpb 1m 13Mi
calico-node-4hngl 25m 65Mi
calico-node-5kwnr 29m 69Mi
calico-node-h46tb 25m 65Mi
calico-node-qchbv 25m 62Mi
coredns-6cc56c94bd-cwtgf 3m 12Mi
metrics-server-6f6f7948b9-fwss4 4m 20Mi
5) 以上測試能正常顯示資源消耗,說明Metrics Server服務工作正常。
3 autoscaling/v1(CPU指標實踐)
autoscaling/v1版本只支持CPU一個指標。
(1) 部署應用 # kubectl create namespace lc # kubectl create deployment web --image=nginx -n lc --dry-run=client -o yaml > deployment-web-lc.yaml # cat deployment-web-lc.yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: web name: web namespace: lc spec: replicas: 1 selector: matchLabels: app: web template: metadata: labels: app: web spec: containers: - image: nginx name: nginx resources: requests: memory: "300Mi" cpu: "300m" limits: memory: "450Mi" cpu: "450m" # 注意:修改yaml,增加resources.requests.cpu # kubectl apply -f deployment-web-lc.yaml # kubectl expose deployment web --port=80 --target-port=80 --type=NodePort -n lc \ --dry-run=client -o yaml > service-web-lc.yaml # cat service-web-lc.yaml apiVersion: v1 kind: Service metadata: labels: app: web name: web namespace: lc spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: web type: NodePort # kubectl apply -f service-web-lc.yaml (2) 創建HPA # kubectl autoscale deployment web -n lc --min=2 --max=10 --cpu-percent=80 \ --dry-run=client -o yaml > deployment-web-lc-hpa.yaml # cat deployment-web-lc-hpa.yaml apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: web namespace: lc spec: maxReplicas: 10 minReplicas: 2 scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: web targetCPUUtilizationPercentage: 80 # scaleTargetRef:表示當前要伸縮對象是誰 # targetCPUUtilizationPercentage:當整體的資源利用率超過80%的時候,會進行擴容。 # kubectl apply -f deployment-web-lc-hpa.yaml # kubectl get hpa -n lc NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE web Deployment/web 0%/80% 2 10 2 78s # 說明:為名為web的deployment創建一個HPA對象,目標CPU使用率為80%,副本數量配置為2到10之間。 (3) 壓測 # yum install httpd-tools # ab -n 2000000 -c 100 http://172.28.34.23/index.html # 總200w請求,並發100,172.28.34.23為ClusterIP (4) 觀察擴容狀態 # kubectl get hpa -n lc NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE web Deployment/web 106%/80% 2 10 8 21m # 可以看到deployment/web的副本數加到了8,由於node節點cpu的資源不夠了,不能夠繼續創建pod了。 # kubectl top pods -n lc NAME CPU(cores) MEMORY(bytes) web-86c68d4466-khvqg 253m 4Mi web-86c68d4466-ksfkz 221m 5Mi web-86c68d4466-kwldc 250m 4Mi web-86c68d4466-ltpbf 258m 7Mi web-86c68d4466-mbflm 173m 4Mi web-86c68d4466-mchtg 272m 4Mi web-86c68d4466-px8cv 262m 4Mi web-86c68d4466-rsqg4 258m 7Mi # kubectl get pods -n lc NAME READY STATUS RESTARTS AGE web-86c68d4466-khvqg 1/1 Running 0 7m31s web-86c68d4466-ksfkz 1/1 Running 0 11m web-86c68d4466-kwldc 1/1 Running 0 8m21s web-86c68d4466-ltpbf 1/1 Running 1 27m web-86c68d4466-mbflm 1/1 Running 0 7m31s web-86c68d4466-mchtg 1/1 Running 0 8m21s web-86c68d4466-px8cv 1/1 Running 0 11m web-86c68d4466-rsqg4 1/1 Running 1 35m (5) 關閉壓測,過5分鍾后檢查縮容狀態,發現pod數量變為了2 # kubectl get hpa -n lc NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE web Deployment/web 0%/80% 2 10 2 32m # kubectl get pods -n lc NAME READY STATUS RESTARTS AGE web-86c68d4466-ltpbf 1/1 Running 1 33m web-86c68d4466-rsqg4 1/1 Running 1 41m
2.6 基於Prometheus自定義指標縮放
資源指標只包含CPU、內存,一般來說也夠了。但如果想根據自定義指標:如請求qps/5xx錯誤數來實現HPA,就需要使用自定義指標了,目前比較成熟的實現是 Prometheus Custom Metrics。自定義指標由Prometheus來提供,再利用k8s-prometheus-adpater聚合到apiserver,實現和核心指標(metric-server)同樣的效果。
為滿足更多的需求,HPA也支持自定義指標,例如QPS、5xx錯誤狀態碼等,實現自定義指標由autoscaling/v2版本提供,而v2版本又分為beta1和beta2兩個版本。 這兩個版本的區別是autoscaling/v2beta1支持了Resource Metrics(資源指標)、Custom Metrics(自定義指標)。 在autoscaling/v2beta2的版本中額外增加了External Metrics(擴展指標)的支持。 對於自定義指標(例如QPS),將使用custom.metrics.k8s.io API,由相關適配器(Adapter)服務提供。 已知適配器列表:https://github.com/kubernetes/metrics/blob/master/IMPLEMENTATIONS.md#custom-metrics-api
hpa/kubectl get --raw/kubectl top -> apiserver -> prometheus-adpater -> prometheus -> pod(自定義暴露指標)
假設我們有一個網站,想基於每秒接收到的HTTP請求對其Pod進行自動縮放,實現HPA大概步驟如下: (1) 部署Prometheus (2) 對應用暴露指標,部署應用,並讓Prometheus采集暴露的指標 (3) 部署Prometheus Adapter (4) 為指定HPA配置Prometheus Adapter (5) 創建HPA (6) 壓測、驗證
1 部署Prometheus
Prometheus(普羅米修斯)是一個最初在SoundCloud上構建的監控系統。自2012年成為社區開源項目,擁有非常活躍的開發人員和用戶社區。為強調開源及獨立維護,Prometheus於2016年加入雲原生雲計算基金會(CNCF),成為繼Kubernetes之后的第二個托管項目。
(1) Prometheus 特點 1)多維數據模型:由度量名稱和鍵值對標識的時間序列數據 2)PromSQL:一種靈活的查詢語言,可以利用多維數據完成復雜的查詢 3)不依賴分布式存儲,單個服務器節點可直接工作 4)基於HTTP的pull方式采集時間序列數據 5)推送時間序列數據通過PushGateway組件支持 6)通過服務發現或靜態配置發現目標 7)多種圖形模式及儀表盤支持(grafana)
(2) Prometheus組成及架構
1)Prometheus Server:收集指標和存儲時間序列數據,並提供查詢接口 2)ClientLibrary:客戶端庫 3)Push Gateway:短期存儲指標數據。主要用於臨時性的任務 4)Exporters:采集已有的第三方服務監控指標並暴露metrics 5)Alertmanager:告警 6)Web UI:簡單的Web控制台
(3) 部署(采用deployment方式部署)
# unzip prometheus.zip
# cd prometheus/
# ls -l
prometheus-configmap.yaml # 部署Prometheus
prometheus-deployment.yaml # Prometheus配置文件,主要配置基於Kubernetes服務發現
prometheus-rules.yaml # Prometheus告警規則
# kubectl apply -f .
# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
(省略的內容)......
prometheus-8474f8559d-zrpg8 2/2 Running 0 2m19s
# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
(省略的內容)......
prometheus NodePort 172.28.46.226 <none> 9090:30090/TCP 2m43s
訪問Prometheus UI: http://NodeIP:30090
2 部署一個應用並暴露Prometheus采集的指標
對應用暴露指標,部署應用,並讓Prometheus采集暴露的指標。在做這步之前先了解下Prometheus如何監控應用的。 如果要想監控,前提是能獲取被監控端指標數據,並且這個數據格式必須遵循Prometheus數據模型,這樣才能識別和采集,一般使用exporter提供監控指標數據。但對於自己開發的項目,是需要自己實現類似於exporter的指標采集程序。 exporter列表:https://prometheus.io/docs/instrumenting/exporters
先模擬自己開發一個網站,采用Python Flask Web框架,寫兩個頁面,/ 首頁,/metrics 指標、然后使用Dockefile制作成鏡像並部署 到Kubernetes平台。
# cat metrics-flask-app.yaml apiVersion: apps/v1 kind: Deployment metadata: name: metrics-flask-app spec: replicas: 3 selector: matchLabels: app: flask-app template: metadata: labels: app: flask-app # 聲明Prometheus采集 annotations: prometheus.io/scrape: "true" prometheus.io/port: "80" prometheus.io/path: "/metrics" spec: containers: - image: lc/metrics-flask-app name: web resources: requests: memory: "300Mi" cpu: "300m" --- apiVersion: v1 kind: Service metadata: name: metrics-flask-app spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: flask-app # kubectl apply -f metrics-flask-app.yaml (1) flask-app.py # cat main.py import prometheus_client from prometheus_client import Counter from flask import Response, Flask app = Flask(__name__) requests_total = Counter("request_count","統計HTTP請求") @app.route("/metrics") def requests_count(): requests_total.inc() return Response(prometheus_client.generate_latest(requests_total), mimetype="text/plain") @app.route('/') def index(): requests_total.inc() return "Hello World" if __name__ == "__main__": app.run(host="0.0.0.0",port=80) (2) Dockerfile # cat Dockerfile FROM python RUN pip install flask -i https://mirrors.aliyun.com/pypi/simple/ && \ pip install prometheus_client -i https://mirrors.aliyun.com/pypi/simple/ COPY main.py / CMD python main.py
該metrics-app暴露了一個Prometheus指標接口,可以通過訪問service看到
# kubectl get svc -n default
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 172.28.0.1 <none> 443/TCP 23d
metrics-flask-app ClusterIP 172.28.128.88 <none> 80/TCP 10m
# curl 172.28.128.88/metrics
# HELP request_count_total 統計HTTP請求
# TYPE request_count_total counter
request_count_total 9.0
# HELP request_count_created 統計HTTP請求
# TYPE request_count_created gauge
request_count_created 1.63419377682031e+09
# 說明: 由於是svc起到了負載均衡的作用,每次統計到的request_count_total值都不一樣。
由於我們Prometheus配置了基於Kubernetes服務發現,會自動采集Pod暴露的指標,在prometheus UI界面中查看被采集到指標的pod。
3 部署 Custom Metrics Adapter
但是prometheus采集到的metrics並不能直接給k8s用,因為兩者數據格式不兼容,還需要另外一個組件(k8s-prometheus-adpater),將prometheus的metrics 數據格式轉換成k8s API接口能識別的格式,轉換以后,因為是自定義API,所以還需要用Kubernetes aggregator在主APIServer中注冊,以便直接通過/apis/來訪問。
https://github.com/DirectXMan12/k8s-prometheus-adapter 注: 由於官方推薦使用的helm安裝,我在國內拉不下來,我這里直接使用yaml進行不出,yaml也是從helm中拿到的。
(1) prometheus-adapter.yaml配置文件注意點
prometheus-adapter部署在kube-system命名空間下(configmap配置文件在kube-system命名空間),並添加prometheus-adapter連
接prometheus的參數prometheus-url=http://prometheus.kube-system:9090。
(省略內容)......
containers:
- name: prometheus-adapter
image: "directxman12/k8s-prometheus-adapter-amd64:v0.7.0"
imagePullPolicy: IfNotPresent
args:
- /adapter
- --secure-port=6443
- --cert-dir=/tmp/cert
- --logtostderr=true
- --prometheus-url=http://prometheus.kube-system:9090
- --metrics-relist-interval=1m
- --v=4
- --config=/etc/adapter/config.yaml
ports:
(省略內容)......
(2) 部署
# kubectl apply -f prometheus-adapter.yaml
# kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
(省略的內容......)
prometheus-8474f8559d-zrpg8 2/2 Running 0 18m
prometheus-adapter-7f94cc997d-qhpcf 1/1 Running 0 50s
# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 172.28.0.2 <none> 53/UDP,53/TCP,9153/TCP 23d
prometheus NodePort 172.28.46.226 <none> 9090:30090/TCP 18m
prometheus-adapter ClusterIP 172.28.10.137 <none> 443/TCP 93s
(3) 驗證適配器注冊到APIServer
# kubectl get apiservices |grep custom
v1beta1.custom.metrics.k8s.io kube-system/prometheus-adapter True 3m26s
# kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1"
4 指定prometheus-adapter從prometheus中查詢指標的配置(configmap)
(1) 配置內容配置 # cat prometheus-adapter-configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: prometheus-adapter labels: app: prometheus-adapter chart: prometheus-adapter-2.5.1 release: prometheus-adapter heritage: Helm namespace: kube-system data: config.yaml: | rules: - seriesQuery: 'request_count_total{app="flask-app"}' resources: overrides: kubernetes_namespace: {resource: "namespace"} kubernetes_pod_name: {resource: "pod"} name: matches: "request_count_total" as: "qps" metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)' (2) 配置說明 seriesQuery # Prometheus查詢語句,查詢應用系列指標。 resources # Kubernetes資源標簽映射到Prometheus標簽。 name # 將Prometheus指標名稱在自定義指標API中重命名, matches # 正則匹配,as指定新名稱。 metricsQuery # 一個Go模板,對調用自定義指標API轉換為Prometheus查詢語句。 (3) 應用配置 # kubectl apply -f prometheus-adapter-configmap.yaml # 刪除prometheus-adapter pod使配置生效 # kubectl delete pod/prometheus-adapter-7f94cc997d-qhpcf -n kube-system (4) 向自定義指標API訪問 # kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/qps" 注: 如果配置沒問題,會返回JSON數據,注意里面的value字段,HPA控制器會拿這個值計算然后比對閾值。這個值單位是m,表示毫秒,千分之一, 例如值為500m是每秒0.5個請求,10000m是每秒10個請求(並發)。 Adapter向Prometheus查詢語句最終是由於HTTP請求統計是累計的,對HPA自動縮放不是特別有用,因此將其轉為速率指標。 這條語句意思是:查詢每個Pod在2分鍾內訪問速率,即QPS(每秒查詢率) sum(rate(request_count_total{app="flask-app", kubernetes_namespace="default", kubernetes_pod_name=~"pod1|pod2"}[2m])) by (kubernetes_pod_name)
5 創建HPA策略
# cat hpa-v2-qps.yaml apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: metrics-flask-app namespace: default spec: minReplicas: 1 maxReplicas: 10 scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: metrics-flask-app metrics: - type: Pods pods: metric: name: qps target: type: AverageValue averageValue: 10000m # 所有Pod平均值為10000m觸發擴容,即每秒10個請求 # kubectl apply -f hpa-v2-qps.yaml # kubectl get hpa -n default NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE metrics-flask-app Deployment/metrics-flask-app 16m/10 1 10 3 41s
6 壓測
# yum install httpd-tools -y
# ab -n 100000 -c 100 http://172.28.128.88/
# 172.28.128.88 是 deployment/metrics-flask-app svc 的 cluster-ip 地址
7 查看HPA狀態
# 可以看到pod副本數擴充到了10個
# kubectl get hpa -n default
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
metrics-flask-app Deployment/metrics-flask-app 202072m/10 1 10 10 4m17s
# kubectl get pod -n default
NAME READY STATUS RESTARTS AGE
metrics-flask-app-5475d5f794-4n9sw 1/1 Running 0 2m10s
metrics-flask-app-5475d5f794-6cm4c 1/1 Running 0 2m26s
metrics-flask-app-5475d5f794-9gwzp 1/1 Running 0 80m
metrics-flask-app-5475d5f794-9jlt2 1/1 Running 0 2m26s
metrics-flask-app-5475d5f794-chwrl 1/1 Running 0 2m10s
metrics-flask-app-5475d5f794-gnvm7 1/1 Running 0 2m10s
metrics-flask-app-5475d5f794-jvl26 1/1 Running 0 2m10s
metrics-flask-app-5475d5f794-lnj4q 1/1 Running 0 80m
metrics-flask-app-5475d5f794-px6pg 1/1 Running 0 80m
metrics-flask-app-5475d5f794-ws42t 1/1 Running 0 2m26s
# kubectl describe hpa metrics-flask-app