Kubernetes 的自动伸缩你用对了吗?
作者 | AddoZhang
來源 | 云原生指北
本文翻譯自 learnk8s 的?Architecting Kubernetes clusters — choosing the best autoscaling strategy[1],有增刪部分內容。
TL;DR: 在默認設置下,擴展 Kubernetes 集群中的 pod 和節點可能需要幾分鐘時間。了解如何調整集群節點的大小、配置水平和集群自動縮放器以及過度配置集群以加快擴展速度。
自動擴展器
在 Kubernetes 中,常說的“自動擴展”有:
?HPA:Pod 水平縮放器[2]
?VPA:Pod 垂直縮放器[3]
?CA:集群自動縮放器[4]
不同類型的自動縮放器,使用的場景不一樣。
HPA
HPA 定期檢查內存和 CPU 等指標,自動調整 Deployment 中的副本數,比如流量變化:
調整前
調整后
VPA
有些時候無法通過增加 Pod 數來擴容,比如數據庫。這時候可以通過 VPA 增加 Pod 的大小,比如調整 Pod 的 CPU 和內存:
調整前
調整后
CA
當集群資源不足時,CA 會自動配置新的計算資源并添加到集群中:
調整前
調整后
自動縮放 Pod 出錯時
比如一個應用需要 1.5 GB 內存和 0.25 個 vCPU。一個 8GB 和 2 個 vCPU 的節點,可以容納 4 個這樣的 Pod,完美!
做如下配置:
1.HPA:每增加 10 個并發,增加一個副本。即 40 個并發的時候,自動擴展到 4 個副本。(這里使用自定義指標,比如來自 Ingress Controller 的 QPS)
2.CA:在資源不足的時候,增加計算節點。
當并發達到 30 的時候,系統是下面這樣。完美!HPA 工作正常,CA 沒工作。
當增加到 40 個并發的時候,系統是下面的情況:
1.HPA 增加了一個 Pod
2.Pod 掛起
3.CA 增加了一個節點
HPA 工作
CA 工作
為什么 Pod 沒有部署成功?
節點上的操作系統進程和 kubelet 也會消耗一部分資源,8G 和 2 vCPU 并不是全都可以提供給 Pod 用的。并且還有一個驅逐閾值[5]:在節點系統剩余資源達到閾值時,會驅逐 Pod,避免 OOM 的發生。
當然上面的這些都是可配置[6]的。
那為什么在創建該 Pod 之前,CA 沒有增加新的節點呢?
CA 如何工作?
CA 在觸發自動縮放時,不會查看可用的內存或 CPU。
CA 是面向事件工作的,并每 10 秒檢查一次是否存在不可調度(Pending)的 Pod。
當調度器無法找到可以容納 Pod 的節點時,這個 Pod 是不可調度的。
此時,CA 開始創建新節點:CA 掃描集群并檢查是否有不可調度的 Pod。
當集群有多種節點池,CA 會通過選擇下面的一種策略:
?random:默認的擴展器,隨機選擇一種節點池
?most-pods:能夠調度最多 Pod 的節點池
?least-waste:選擇擴展后,資源空閑最少的節點池
?price:選擇成本最低的節點池
?priority:選擇用戶分配的具有最高優先級的節點池
確定類型后,CA 會調用相關 API 來創建資源。(云廠商會實現 API,比如 AWS 添加 EC2;Azure 添加 Virtual Machine;阿里云增加 ECS;GCP 增加 Compute Engine)
計算資源就緒后,就會進行節點的初始化[7]。
注意,這里需要一定的耗時,通常比較慢。
探索 Pod 自動縮放的前置時間
四個因素:
1.HPA 的響應耗時
2.CA 的響應耗時
3.節點的初始化耗時
4.Pod 的創建時間
默認情況下,kubelet 每 10 秒抓取一次 Pod 的 CPU 和內存占用情況[8]。
每分鐘,Metrics Server 會將聚合的指標開放[9]給 Kubernetes API 的其他組件使用。
CA 每 10 秒排查不可調度的 Pod。[10]
?少于 100 個節點,且每個節點最多 30 個 Pod,時間不超過 30s。平均延遲大約 5s。
?100 到 1000個節點,不超過 60s。平均延遲大約 15s。
節點的配置時間,取決于云服務商。通常在 3~5 分鐘。
容器運行時創建 Pod:啟動容器的幾毫秒和下載鏡像的幾秒鐘。如果不做鏡像緩存,幾秒到 1 分鐘不等,取決于層的大小和梳理。
對于小規模的集群,最壞的情況是 6 分 30 秒。對于 100 個以上節點規模的集群,可能高達 7 分鐘。
HPA delay:1m30s+CA delay:0m30s+Cloud provider:4m+Container runtime:0m30s+=========================Total6m30s突發情況,比如流量激增,你是否愿意等這 7 分鐘?
這 7 分鐘,如何優化壓縮?
?HPA 的刷新時間,默認 15 秒,通過?--horizontal-pod-autoscaler-sync-period?標志控制。
?Metrics Server 的指標抓取時間,默認 60 秒,通過?metric-resolution?控制。
?CA 的掃描間隔,默認 10 秒,通過?scan-interval?控制。
?節點上緩存鏡像,比如?kube-fledged[11]?等工具。
即使調小了上述設置,依然會受云服務商的時間限制。
那么,如何解決?
兩種嘗試:
1.盡量避免被動創建新節點
2.主動創建新節點
為 Kubernetes 選擇最佳規格的節點
這會對擴展策略產生巨大影響。
這樣的場景
應用程序需要 1GB 內存和 0.1 vCPU;有一個 4GB 內存和 1 個 vCPU 的節點。
排除操作系統、kubelet 和閾值保留空間后,有 2.5GB 內存和 0.7 個 vCPU 可用。
最多只能容納 2 個 Pod,擴展副本時最長耗時 7 分鐘(HPA、CA、云服務商的資源配置耗時)
假如節點的規格是 64GB 內存和 16 個 vCPU,可用的資源為 58.32GB 和 15.8 個 vCPU。
這個節點可以托管 58 個 Pod。只有擴容第 59 個副本時,才需要創建新的節點。
CleanShot 2021-06-08 at 23.16.56@2x
這樣觸發 CA 的機會更少。
選擇大規格的節點,還有另外一個好處:資源的利用率會更高。
節點上可以容納的 Pod 數量,決定了效率的峰值。
物極必反!更大的實例,并不是一個好的選擇:
1.爆炸半徑(Blast radius):節點故障時,少節點的集群和多節點的集群,前者影響更大。
2.自動縮放的成本效益低:增加一個大容量的節點,其利用率會比較低(調度過去的 Pod 數少)
即使選擇了正確規格的節點,配置新的計算單元時,延遲仍然存在。怎么解決?
能否提前創建節點?
為集群過度配置節點
即為集群增加備用節點,可以:
1.創建一個節點,并留空 (比如 SchedulingDisabled)
2.一旦空節點中有了一個 Pod,馬上創建新的空節點
CleanShot 2021-06-08 at 23.26.26@2x
這種會產生額外的成本,但是效率會提升。
CA 并不支持此功能 -- 總是保留一個空節點。
但是,可以偽造。創建一個只占用資源,不使用資源的 Pod 占用整個 Node 節點。
一旦有了真正的 Pod,驅逐占位的 Pod。
待后臺完成新的節點配置后,將“占位” Pod 再次占用整個節點。
這個“占位”的 Pod 可以通過永久休眠來實現空間的保留。
apiVersion: apps/v1kind:Deploymentmetadata: name: overprovisioningspec: replicas:1 selector: matchLabels: run: overprovisioningtemplate: metadata: labels: run: overprovisioning spec: containers:- name: pause image: k8s.gcr.io/pause resources: requests: cpu:'1739m' memory:'5.9G'使用優先級和搶占[12],來實現創建真正的 Pod 后驅逐“占位”的 Pod。
使用?PodPriorityClass?在配置 Pod 優先級:
apiVersion: scheduling.k8s.io/v1beta1kind:PriorityClassmetadata: name: overprovisioningvalue:-1#默認的是 0,這個表示比默認的低globalDefault:falsedescription:'Priority class used by overprovisioning.'為“占位” Pod 配置優先級:
apiVersion: apps/v1kind:Deploymentmetadata: name: overprovisioningspec: replicas:1 selector: matchLabels: run: overprovisioningtemplate: metadata: labels: run: overprovisioning spec: priorityClassName: overprovisioning #HERE containers:- name: reserve-resources image: k8s.gcr.io/pause resources: requests: cpu:'1739m' memory:'5.9G'已經做完過度配置,應用程序是否需要優化?
為 Pod 選擇正確的內存和 CPU 請求
Kubernetes 是根據 Pod 的內存和 CPU 請求,為其分配節點。
如果 Pod 的資源請求配置不正確,可能會過晚(或過早)觸發自動縮放器。
這樣一個場景:
?應用程序平均負載下消耗 512MB 內存和 0.25 個 vCPU。
?高峰時,消耗 4GB 內存 和 1 個 vCPU。(即資源限制,Limit)
有三種請求的配置選擇:
1.遠低于平均使用量
2.匹配平均使用量
3.盡量接近限制
第一種的問題在于超賣嚴重,過度使用節點。kubelet 負載高,穩定性差。
第三種,會造成資源的利用率低,浪費資源。這種通常被稱為?QoS:Quality of Service class[13]?中的?Guaranteed?級別,Pod 不會被終止和驅逐。
如何在穩定性和資源使用率間做權衡?
這就是?QoS:Quality of Service class[14]?中的?Burstable?級別,即 Pod 偶爾會使用更多的內存和 CPU。
1.如果節點中有可用資源,應用程序會在返回基線(baseline)前使用這些資源。
2.如果資源不足,Pod 將競爭資源(CPU),kubelet 也有可能嘗試驅逐 Pod(內存)。
在?Guaranteed?和?Burstable?之前如何做選擇?取決于:
1.想盡量減少 Pod 的重新調度和驅逐,應該是用?Guaranteed。
2.如果想充分利用資源時,使用?Burstable。比如彈性較大的服務,Web 或者 REST 服務。
如何做出正確的配置?
應該分析應用程序,并測算空閑、負載和峰值時的內存和 CPU 消耗。
甚至可以通過部署 VPA 來自動調整。
如何進行集群縮容?
每 10 秒,當請求(request)利用率低于 50%時,CA 才會決定刪除節點。
CA 會匯總同一個節點上的所有 Pod 的 CPU 和內存請求。小于節點容量的一半,就會考慮對當前節點進行縮減。
需要注意的是,CA 不考慮實際的 CPU 和內存使用或者限制(limit),只看請求(request)。
移除節點之前,CA 會:
1.檢查 Pod[15]?確保可以調度到其他節點上。
2.檢查節點[16],避免節點被過早的銷毀,比如兩個節點的請求都低于 50%。
檢查都通過之后,才會刪除節點。
為什么不根據內存或 CPU 進行自動縮放?
基于內存和 CPU 的自動縮放器,不關進 pod。
比如配置縮放器在節點的 CPU 達到總量的 80%,就自動增加節點。
當你創建 3 個副本的 Deployment,3 個節點的 CPU 達到了 85%。這時會創建一個節點,但你并不需要第 4 個副本,新的節點就空閑了。
不建議使用這種類型的自動縮放器。
總結
定義和實施成功的擴展策略,需要掌握以下幾點:
?節點的可分配資源。
?微調 Metrics Server、HPA 和 CA 的刷新間隔。
?設計集群和節點的規格。
?緩存容器鏡像到節點。
?應用程序的基準測試和分析。
配合適當的監控工具,可以反復測試擴展策略并調整集群的縮放速度和成本。
引用鏈接
[1]?Architecting Kubernetes clusters — choosing the best autoscaling strategy:?https://learnk8s.io/kubernetes-autoscaling-strategies#when-autoscaling-pods-goes-wrong
[2]?HPA:Pod 水平縮放器:?https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
[3]?VPA:Pod 垂直縮放器:?https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler
[4]?CA:集群自動縮放器:?https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler
[5]?驅逐閾值:?https://kubernetes.io/docs/tasks/administer-cluster/reserve-compute-resources/#eviction-thresholds
[6]?可配置:?https://kubernetes.io/docs/tasks/administer-cluster/reserve-compute-resources/#node-allocatable
[7]?節點的初始化:?https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/
[8]?kubelet 每 10 秒抓取一次 Pod 的 CPU 和內存占用情況:?https://github.com/kubernetes/kubernetes/blob/2da8d1c18fb9406bd8bb9a51da58d5f8108cb8f7/pkg/kubelet/kubelet.go#L1855
[9]?每分鐘,Metrics Server 會將聚合的指標開放:?https://github.com/kubernetes-sigs/metrics-server/blob/master/FAQ.md#how-often-metrics-are-scraped
[10]?CA 每 10 秒排查不可調度的 Pod。:?https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#how-does-scale-up-work
[11]?kube-fledged:?https://github.com/senthilrch/kube-fledged
[12]?優先級和搶占:?https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/
[13]?QoS:Quality of Service class:?https://kubernetes.io/docs/tasks/configure-pod-container/quality-service-pod/#qos-classes
[14]?QoS:Quality of Service class:?https://kubernetes.io/docs/tasks/configure-pod-container/quality-service-pod/#qos-classes
[15]?檢查 Pod:?https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#what-types-of-pods-can-prevent-ca-from-removing-a-node
[16]?檢查節點:?https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#i-have-a-couple-of-nodes-with-low-utilization-but-they-are-not-scaled-down-why
往期推薦
如果讓你來設計網絡
這種本機網絡 IO 方法,性能可以翻倍!
留不住客戶?該從你的系統上找找原因了!
明明還有大量內存,為啥報錯“無法分配內存”?
點分享
點收藏
點點贊
點在看
總結
以上是生活随笔為你收集整理的Kubernetes 的自动伸缩你用对了吗?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 开发者看过来,5 行代码实现身份认证,A
- 下一篇: Colima:MacOS 上的极简容器运