k8s-自動橫向伸縮pod 與節點


簡述

我們可以通過調高ReplicationController、 ReplicaSet、 Deployment等可伸縮資源的rep讓cas字段, 來手動實現pod中應用的橫向擴容。 我們也可以通過增加pod容器的資源請求和限制來縱向擴容pod (盡管目前該操作只能在pod創建時, 而非運行時進行)。 雖然如果你能預先知道負載何時會飄升, 或者如果負載的變化是較長時間內逐漸發生的, 手動擴容也是可以接受的, 但指望靠人工干預來處理突發而不可預測的流量增長, 仍然不夠理想。
 
Kubemetes可以監控你的pod, 並在檢測到CPU使用率或其他度量增長時自動對它們擴容。 如果Kubemetes運行在雲端基礎架構之上, 它甚至能在現有節點無法承載更多pod之時自動新建更多節點。

pod的橫向自動伸縮

橫向pod自動伸縮是指由控制器管理 的pod副本數量的自動伸 縮。 它由Horizontal控制器執行, 我們通過創建 一個HorizontalpodAutoscaler C HPA)資源來啟用和配置Horizontal控制器。 該控制器周期性檢查pod度量, 計算滿足HPA資源所配置的目標數值所需的副本數量, 進而調整目標資源(如Deployment、ReplicaSet、 ReplicationController、StatefulSet等)的replicas字段。
 
自動伸縮過程
自動伸縮的過程可以分為三個步驟:
• 獲取被伸縮資源對象所管理的所有pod度量。
• 計算使度量數值到達(或接近)所指定目標數值所需的pod數量。
• 更新被伸縮資源的replicas字段。 
 
下面我們就來看看這三個步驟。

獲取pod度量 

Autoscaler本身並不負責采集pod度量數據 , 而是從另外的來源獲取。 正如之前提到的, pod與節點度量數據是由運行在每個節點的kubelet之上, 名為cAdvisor的agent采集的;這些數據將由 集群級的組件Heapster聚合。 HPA控制器向Heapster 發起REST調用來獲取 所有pod度量數據。 

計算所需的 pod 數量

一 旦Autoscaler獲得了它所調整的資源(Deployment、 ReplicaSet、ReplicationController或State伈!Set)所轄pod的全部度量, 它便可以利用這些度量計算出所需的副本數量。 它需要計算出一個合適的副本數量, 以使所有副本上度量的平均值盡量接近配置的目標值。 該計算的輸入是一組pod度量(每個pod可能有多個), 輸出則是一個整數(pod副本數量)。
當Autoscaler配置為只考慮單個度量時, 計算所需 副本數很簡單。 只要將所有pod的度量求和后除以HPA資源上配置的目標值, 再向上取整即可。 實際的計算稍微復雜一些; Autoscaler還保證了度量數值不穩定、 迅速抖動時不會導致系統抖動(thrash)。
基於多個pod度量的自動伸縮(例如: CPU使用率和每秒查詢率[QPS])的計算也並不復雜。 Autoscaler單獨計算每個度量的副本數, 然后取最大值(例如:如果需要4個pod達到目標CPU使用率, 以及需要3個pod來達到目標QPS, 那么Autoscaler 將擴展到4個pod)。 下圖展示了這個示例。

 

更新被伸縮資源的副本數

自動伸縮操作的最后 一 步是更新被伸縮資源對象(比如ReplicaSet)上的副本數字段 然后讓ReplicaSet控制器負責啟動更多pod或者刪除多余的pod。Autoscaler控制器通過scale子資源來修改被伸縮資源的rep巨cas字段。 這樣Autoscaler不必了解它所管理資源的細節,而只需要通過Scale子資源暴露的界面,就可以完成它的工作了,如下圖
HPA只對Scale子資源進行更改 。
這意味着只要API服務器為某個可伸縮資源暴露了Scale子資源, Autoscaler即可操作該資源。 目前暴露了Scale子資源的資源有: 
• Deployment
• ReplicaSet
• ReplicationController
• StatefulSet
目前也只有這些對象可以附着Autoscaler。
View Code
 
了解整個自動伸縮過程
從pod指向 cAdvisor, 再經過Heapster , 而最終到達HPA的箭頭代表度量數據的流向。 值得注意的是, 每個組件從其他組件拉取數據的動作是周期性的 (即cAdvisor用 一個無限循環從pod中采集數據; Heapster與HPA控制器亦是如此)。這意味着度量數據的傳播與相應動作的觸發都需要相當一段時間, 不是立即發生的。接下來實地觀察Autoscaler行為時要注意這一點。 

 

基於CPU使用率進行自動伸縮
可能你最想用以指導自動伸縮的度量就是pod中進程的CPU使用率了。 假設你用幾個pod來提供服務, 如果它們的CPU使用率達到了100%, 顯然它們已經扛不住壓力了, 要么進行縱向擴容(scale up), 增加它們可用的CPU時間, 要么進行橫向擴容(scale out), 增加pod 數量 。 因為本章談論的是HPA, 我們僅僅關注橫向擴容。
這么一來, 平均CPU使用率就應該下降了。因為CPU使用通常是不穩定的, 比較靠譜的做法是在CPU被壓垮之前就橫向擴容一—可能平均負載達到或超過80%的時候就進行擴容。 但這里有個問題, 到底是誰的80%呢。
 
就 Autoscaler而言, 只有pod的保證CPU用量(CPU請求)才與確認pod的CPU使用有關。 Autoscaler對比pod的實際CPU使用與它的請求, 這意味着你需要給被伸縮的pod設置CPU請求,不管是直接設置還是通過LimitRange對象間接設置,這樣Autoscaler才能確定CPU使用率。

基於CPU使用率創建HPA

創建deployment 資源
apiVersion: extensions/vlbetal 
kind: Deployment 
metadata:
  name: kubia 
spec: 
  replicas: 3                         #手動設置(初始)想要的副本數為3
  template: 
    metadata:
      name: kubia 
      labels: 
        app: kubia 
    spec: 
      containers: 
      - image: luksa/kubia:vl 
        name: nodejs 
        resources: 
          requests: 
            cpu: 100m                 #每個pod請求100毫核的CPU
            
創建了Deployment之后, 為了給它的pod 啟用橫向自動伸縮 , 需要創建一個 HorizontalpodAutoscaler (HPA)對象, 並把它指向該Deployment。

$ kubectl autoscale deploymen七kubia --cpu-percent=30 --min=l --max=5

這會幫你創建 HPA對象,並將叫作kubia的Deployment設置為伸縮目標。你還設置了pod的目標 CPU使用率為30%, 指定了副本的最小和最大數量。Autoscaler會持續調整副本的數量
以使CPU使用率接近30%, 但它永遠不會調整到少於1個或者多於5個。

提示:一定要確保自動伸縮的目標是Deployinent 而不是底層的 ReplicaSet。 這樣才能確保預期的副本數量在應用更新后繼續保持(記着 Deployment 會給每個應用版本創建一個
新的 ReplicaSet)。 手動伸縮也是同樣的道理。
View Code

修改一個已有 HPA 對象的目標度量值 

 可能你 開始設置的目標值30 有點太低了,我們把它提高到 你將使用 kubectl edit 命令來完成這項工作。文本編輯器打開之后,把 targetAverageUtilization 字段改為 60,

正如大多數其他資源 樣,在你修改資源之后, Autosca er 控制器會檢測到這一變更,並執行相應動作 也可以先刪除 HPA 資源再用新的值創建一個,因為刪除HPA 資源只會禁用目標資源的自動伸縮(本例中為 Deployment ,而它的伸縮規模會保持在刪除資源的時刻 在你為 Deployment 創建一個新的 HPA 資源之后,自動伸縮過程就會繼續進行

伸縮操作的最大速率
因為 Autosca 在單次擴容操作中可增加的副本數受到限制。如果當前副本數大於 2,Autoscaler 單次操作至多使副本數翻倍;如果副本數只有 2, Autoscaler 最多擴容到4個副
另外 Autoscaler 兩次擴容操作之間的時間間隔是有限制。目前,只有當3鍾內沒有任何伸縮操作時才會觸發擴容,縮容操作頻率更低一- 5分鍾 記住這點,這樣你再看到度量數據很明顯應該觸發伸縮卻沒有觸發的時候,就不會感到奇怪了。

 

基於內存使用進行自動伸縮
基於內存的自動伸縮比基於CPU 困難很多, 主要原因在於,擴容之后原有的pod 需要有辦法釋放內存。這只能由應用完成,系統無法代勞,系統所能做的只有殺死並重啟應用,希望它能比之前少占用 些內存;但如果應用使用了跟之前多的內存 Autoscaler 就會擴容、擴容 再擴容到達到HPA資源上配置的最大pod 數量,顯然沒有人想要這種行為。基於內存使用的自動伸縮在 Kubernetes 1.8 中得到支持,配置方法與基於 CPU 的自動伸縮完全相同 。
 
基於其他自定義度量進行自動伸縮
...
spec: 
  maxReplicas: 5 
  metrics: 
  - type: Resource
    resource:  
      name: cpu
     targetAverageUtilization:30
...
View Code

如上所示, metrics 字段允許你定義多個度量供使用。在代碼清單中使用了單個度量。每個條目都指定相應度量的類型一一本例中為一個 Resource 度量。可以在HPA 對象中使用三種度量:

  定義 metric 類型
 使用情況會被監控的資源
 資源的 目標使用量

Resurce 量類型

Resource 類型使 autoscaler 基於一個資源度量做出自動伸縮決策,在容器的資源請求中指定的那些度量即為一例 。這一類型的使用方式我們己經看過了,所以重點關注另外兩種類型。
 

pods 度量類型

Pods 類型用來引用任何其他種類的(包括自定義的)與 pod 直接相關的度量。每秒查詢次數 CQPS ),或者消息隊列中的消息數量(當消息隊列服務運行在 pod 之中 )都屬於這種度量。要配置autoscaler 使用 pod QPS 度量, HPA 對象的 metrics 字段中就需要包含以下代碼清單所示的條目。
...
spec: 
  metrics: 
  - type: Pods
    resource:  
      metricName: qps
     targetAverageValue:100
...
View Code
代碼清單中的示例配置 Autoscaler ,使該 HPA 控制的 ReplicaSet (或其他)控制器下所轄 pod 的平均 QPS 維持 100 的水平。

Object 度量類型

Object 類型被用來讓 Autoscaler 基於並非直接與 pod 關聯的度量來進行伸縮,比方說,你可能希望基於另一集群對象 ,比如 Ingress 對象來伸縮你的 pod。 這度量可能是代碼清單 15.8 中的 QPS ,也可能是平均請求延遲,或者完全是不相干的其他東西。與此前的例子不同,使用 object 度量類型時, Autoscaler 只會從這單個對象中獲取單個度量數據;在此前的例子中, Autoscaler 需要從所有下屬 pod 中獲取度量,並使用它們的平均值。你需要在HPA對象的定義中指定目標對象與目標值。如下所示:
...
spec: 
  maxReplicas: 5 
  metrics: 
  - type: Object
    resource:  
      metricname: latencyMillis          #度量名稱
     target:                    #autoscale 從中獲取度量的特定對象
      apiVersion: extensions/vlbetal
      kind: Ingress 
     name: frontend 
      targetValue: 20 
     scaleTargetRef:                 #autoscale 將要管理的可伸縮資源
       apiVersion: extensions/vlbetal 
       kind: Deployment
      name: kubia
...
View Code

該例中 HPA 被配置為使用 Ingress 對象 frontend 的 latencyMillis 度量,目標值為 20 。HPA 會監控該 Ingress 度量,如果該度量超過了目標值太多autoscaler 便會對 kubia Deployment 資源進行擴容了。

 

確定哪些度量適合用於自動伸縮
不是所有度量都適合作為自動伸縮的基礎。正如之前提到的, pod 中容器的內存占用並不是自動伸縮的一個好度量。如果增加副本數不能導致被觀測度量平均值的線性(或者至少接近線性)下降 ,那么 autoscaler 就不能正常工作比方說,如果你只有 pod 實例,度量數值為 X,這時 autoscaler 擴容到了2個副本,度量數值就需要落在接近 X/2 位置 每秒查詢次數 QPS )就是這么一種自定義度量,對 we 應用而 即為應用每秒接收的請求數。增大副本數總會導致QPS 成比例下降,因為同樣多的請求數現在被更多數量的 pod 處理了。在你決定基於應用自有的自定義度量來伸縮它之前,一定要思考 pod 數量增加或減少時,它的值會如何變化。 
 
縮容到0個副本
HPA 目前不允許設置 minReplicas 字段為0 ,所以 autoscaler 永遠不會縮容到0個副本,即便 pod 什么都沒做也不會。允許 pod 數量縮容到0可以大幅提升硬件利用率:如果你運行的服幾個小時甚至幾天才會收到1次請求,就沒有道理留着它們一直運行,占用本來可以給其他服務利用的資源:然而一旦客戶端請求進來了,你仍然還想讓這些服務馬上可用。
這叫空載( idling )與解除空載 (un-idling ),即允許提供特定服務的 pod 被縮容量到0 副本。在新的請求到來時,請求會先被阻塞,直到 pod 被啟動,從而請求被轉發到新的 pod 為止。Kubernetes 目前暫時沒有提供這個特性,但在未來會實現。可 以檢查 Kubernetes 文檔來看看空載特性有沒有被實現。
  

pod 的縱向自動伸縮

橫向伸縮很棒,但並不是所有應用都能被橫向伸縮,對這些應用而言,唯一選項是縱向伸縮一-給它們更多 CPU 和(或)內存。因為每個節點所擁有的資源通常都比單個 pod 請求的要多 ,我們應該幾乎總能縱向擴容 pod ,因為 pod 的資源請求是通過 pod manifest 的字段配置的,縱向伸縮 pod 將會通過改變這些字段來實現。筆者這里說的是“將會”,因為目前還不可能改變己有 pod的資源請求和限制, 在筆者動筆之前(已經是一年多之前了), 請參考Kubemetes文檔來檢查縱向pod自動伸縮實現了沒有。

集群節點的橫向伸縮

HPA在需要的時候會創建更多的pod實例。 但萬一所有的節點都滿了, 放不下更多pod了, 怎么辦?顯然這個問題並不局限於Autoscaler創建新pod實例的場景。即便是手動創建pod, 也可能碰到因為資源被已有pod使用殆盡, 以至於沒有節點能接收新pod的清況。 
Kubernetes支持在需要時立即自動從雲服務提供者請求更多節點。 該特性由 Cluster Autoscaler執行。
 
Cluster Autoscaler介紹

Cluster Autoscaler負責在由於節點資源不足, 而無法調度某pod到已有節點時,自動部署新節點。它也會在 節點長時間使用率低下的情況下下線節點。 

 從雲端基礎架構請求新節點

如果在 一個pod被創建之后,Scheduler無法將其調度到任何一個已有 節點,一個新節點就會被創建。ClusterAutoscaler會注意此類pod, 並請求雲服務提供者啟動 一個新節點。但在這么做之前,它會檢查新節點有沒有可能容納這個(些) pod,畢竟如果 新節點本來就不可能容納它們,就沒必要啟動這么一個節點了。
 
雲服務提供者通常把相同規格(或者有相同特性)的節點聚合成組。因此Cluster Autoscaler不能單純地說 “給我多一個節點”,它還需要指明節點類型。Cluster Autoscaler 通過檢查可用的節點分組來確定是否有至少一種節點類型能容納未被調度的pod。如果只存在唯一一個此種節點分組,ClusterAutoscaler就可以增加節點分組的大小,讓雲服務提供商給分組中增加一個節點。但如果存在多個滿足條件的節點分組,ClusterAutoscaler就必須挑一個最合適的。這里 “ 最合適” 的精確含義顯然必須是可配置的。在 最壞的情況下,它會隨機挑選一個。
新節點啟動后,其上運行的Kubelet會聯系API服務器,創建一個Node資源以注冊該節點。從這一刻起,該節點即成為Kubernetes集群的一部分,可 以調度pod於其上了。

歸還節點

當節點利用率不足時, Cluster Autoscaler 也需要能夠減少節點的數目。 Cluster Autoscaler 通過監控所有節點上請求的CPU 與內存來實現這一點。 如果某個節點上
所有pod請求的CPU、 內存都不 到 50%, 該節點即被認定 為不再需要。這並不是決定是否要歸還某 一 節點的唯一因素。 Cluster Autoscaler 也會檢查是否有系統 pod (僅僅)運行在該節點上(這並不包括每個節點上都運行的服務, 比如 DaemonSet所部署的服務)。 如果節點上有系統 pod 在運行,該節點就不會被歸還。
 
對非托管 pod, 以及有本地存儲的pod 也是如此, 否則就會造成這些 pod 提供的服務中斷。 換句話說, 只有當 Cluster Autoscaler 知道節點上運行的pod 能夠重新調度到其他節點, 該節點才會被 歸還。
 
當一個節點被選中下線, 它首先會被標記為不可調度, 隨后運行其上的pod 將被疏散至其他節點。 因為所有這些 pod 都屬於 ReplicaSet 或者其他控制器, 它們的替代 pod會被創建並調度到其他剩下的節點(這就是為何正被下線的節點要先標記為不可調度的原因)。 
 
手動標記節點為不可調度、 排空節點 
節點也可以手動被標記為不可調度並排空。 不涉及細節, 這些工作可用以下 kubectl 命令完成:

• kubectl cordon <node> 標記節點為不可調度(但對其上的 pod不做任何事)。
• kubectl drain <node> 標記節點為不可調度, 隨后疏散其上所有pod。

兩種情形下, 在你用 kubectl uncordon <node> 解除節點的不可調度狀態之前, 不會有新 pod被調度到該節點。
View Code

 

限制集群縮容時的服務干擾 
如果 一個節點發生非預期故障, 你不可能阻止其上的pod變為不可用;但如果 一個節點被Cluster Autoscaler或者人類操作員主動下線,可以用一個新特性來確保下線操作不會干擾到這個節點上pod所提供的服務。一些服務要求至少保持一定數量的pod持續運行 , 對基於quorum的集群應用而言尤其如此。 為此, Kubemetes可以指定 下線等操作時需要保待的最少 pod數量,我們通過創建一個podDisruptionBudget資源的方式來利用這一特性。盡管這個資源的名稱聽起來挺復雜的, 實際上 它是最簡單的Kubemetes資源
之一 。 它只包含 一個pod 標簽選擇器和 一個數字, 指定 最少需要維持運行的podYAML文件。
如果想確保你的kubiapod總有3個實例在運行(它們有 app=kubia這個標簽), 像這樣創建PodDisruptionBudget資源 :
$ kubectl    create   pdb   kubia-pdb   --selector=app=kubia   --min-available=3
poddisruptionbudget "kubia-pdb" created
View Code

現在獲取這個pod 的YAML文件, 如以下代碼清單所示。

也可以用 一個百分比而非絕對數值來寫minAvailable字段。 比方說,可以指定60%帶app=kubia標簽的pod應當時刻保持運行。注意從Kubemetes 1. 7開始podDismptionBudget資源也支持maxUnavailable。如果當很多pod不可用而想要阻止pod被剔除時,就可以用maxUnavailable字段而不是minAvailable。

關於這個資源, 沒有更多要講的了。 只 要它存在 ,Cluster Autoscaler與 kubectl drain 命令都會遵守它;如果疏散一個帶有app=kubia標簽的pod會導致它們的總數小於3, 那這個操作就永遠不會被執行。比方說,如果總共有4個pod, minAvailable像例子中 一 樣被設為3, pod 疏散過程就會挨個進行,待ReplicaSet控制器把被疏散的pod換成新的,才繼續下一個。
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM