1. 程式人生 > 其它 >自動橫向伸縮pod與叢集節點

自動橫向伸縮pod與叢集節點

可以通過調高 ReplicationController、 ReplicaSet、 Deployment等可伸縮資源的 replicas 欄位, 來手動實現 pod 中應用的橫向擴容。們也可以通過增加 pod 容器的資源請求和限制來縱向擴容pod (儘管目前該操作只能在pod建立時, 而非執行時進行)。雖然如果能預先知道負載何時會飄升, 或者如果負載的變化是較長時間內逐漸發生的, 手動擴容也是可以接受的, 但指望靠人工干預來處理突發而不可預測的流量增長, 仍然不夠理想。

pod 的橫向自動伸縮 HPA

橫向 pod 自動伸縮是指由控制器管理的 pod 副本數量的自動伸縮。 它由Horizontal控制器執行, 我們通過建立一個 HorizontalpodAutoscaler(HPA) 資源來啟用和配置Horizontal控制器。 該控制器週期性檢查 pod 度量, 計算滿足 HPA 資源所配置的目標數值所需的副本數量, 進而調整目標資源(如 Deployment、ReplicaSet、 ReplicationController、 StatefulSet等)的replicas 欄位。

瞭解自動伸縮過程

自動伸縮 的過程可以分為三個步驟:

  • 獲取被伸縮資源物件所管理的所有 pod 度量。
  • 計算使度量數值到達(或接近)所指定目標數值所需的 pod 數量。
  • 更新被伸縮資源的 replicas 欄位。

獲取 pod 度量
Autoscaler本身並不負責採集pod度量資料 , 而是從另外的來源獲取。pod 與節點度量資料是由執行在每個節點的 kubelet 之上, 名為 cAdvisor 的 agent 採集的;這些資料將由叢集級的元件 Heapster 聚合。 HPA 控制器向 Heapster 發起 REST 呼叫來獲取所有 pod 度量資料。

這樣的資料 流意味著在叢集中必須執行Heapster才能實現自動伸縮。

計算所需的 pod 數量
一 旦 Autoscaler 獲得了它所調整的資源 (Deployment、 ReplicaSet、ReplicationController或StatetSet) 所轄 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 子資源來修改被伸縮資源的 replicas 欄位。 這樣 Autoscaler 不必瞭解它所管理資源的細節,而只需要通過 Scale 子資源暴露的介面,就可以完成它的工作了

這意味著只要API伺服器為某個可伸縮資源暴露了Scale子資源, Autoscaler 即可操作該資源。

瞭解整個自動伸縮過程

從 pod 指向 cAdvisor, 再經過 Heapster , 而最終到達 HPA 的箭頭代表度量資料的流向。 值得注意的是, 每個元件從其他元件拉取資料的動作是週期性的 (即cAdvisor用 一個無限迴圈從 pod 中採集資料; Heapster 與 HPA 控制器亦是如此)。這意味著度量資料的傳播與相應動作的觸發都需要相當一段時間, 不是立即發生的。接下來實地觀察 Autoscaler 行為時要注意這一點。

基於CPU使用率進行自動伸縮

假設用幾個 pod 來提供服務, 如果它們的 CPU 使用率達到了100%, 顯然它們已經扛不住壓力了, 要麼進行縱向擴容(scale up),增加它們可用的CPU時間, 要麼進行橫向擴容(scale out),增加pod 數量 。
因為 CPU 使用通常是不穩定的, 比較靠譜的做法是在 CPU 被壓垮之前就橫向擴容 —— 可能平均負載達到或超過80%的時候就進行擴容。 但這裡有個問題, 到底是誰的80%呢?

提示 一定把目標 CPU 使用率設定得遠遠低於100% (一定不要超過90%),以預留充分空間給突發的流量洪峰。

就 Autoscaler 而言, 只有 pod 的保證 CPU 用量(CPU請求)才與確認 pod 的 CPU 使用有關。 Autoscaler 對比 pod 的實際 CPU 使用與它的請求, 這意味著你需要給被伸縮的 pod 設定CPU請求,不管是直接設定還是通過 LimitRange 物件間接設定,這樣 Autoscaler 才能確定 CPU 使用率。

基千CPU使用率建立HPA
首先建立一個負載 Deployment ,其中所有 pod 都指定 CPU 資源請求,這樣才有可能實現自動伸縮。

vim deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kubia
spec:
  replicas: 3
  selector:
    matchLabels: 
      app: kubia
  template:
    metadata:
      name: kubia
      labels:
        app: kubia
    spec:
      containers:
      - image: luksa/kubia:v1
        name: nodejs
        resources:
          requests:
            cpu: 100m

這個 Deployment 物件 —— 現在還沒有啟用自動伸縮 。 它會執行3個例項的 kubia NodeJS 應用, 每個例項請求 100 毫核的CPU。
為了給它的 pod 啟用橫向自動伸縮 , 需要建立一個 HorizontalpodAutoscaler (HPA) 物件, 並把它指向該 Deployment 。可以給 HPA 準備 YAML manifest,但有個辦法更簡單 —— 可以用kubectl autoscale 命令

kubectl autoscale deployment kubia --cpu-percent=20  --min=1  --max=5 
horizontalpodautoscaler.autoscaling/kubia autoscaled

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

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

檢視 HorizontalpodAutoscaler 資源的定義

kubectl  get horizontalpodautoscaler.autoscaling kubia -o yaml 
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  annotations:
    autoscaling.alpha.kubernetes.io/conditions: 
	...
  name: kubia    # 每個 HPA 都有一個名稱(井不一定非要像這裡一樣與 Deployment 名稱一致)
  namespace: default
  resourceVersion: "302021"
  uid: ae46cc8f-2820-4a22-961f-ed635a750277
spec:
  maxReplicas: 5
  minReplicas: 1
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment   # 該 Autoscaler將作用於的目標資源
    name: kubia
  targetCPUUtilizationPercentage: 20  # 你想讓 Autoscaler 調整 pod 數量以使每個 pod 都使用所請求 CPU 的30%
status:
  currentReplicas: 3   # Autoscaler 的當前狀態
  desiredReplicas: 0

檢視HPA狀態 為 unknown ,需開啟聚合層

kubectl  get hpa 
NAME    REFERENCE          TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
kubia   Deployment/kubia   <unknown>/20%   1         5         0          11s

修改kube-apiserver.yaml 開啟聚合層

vim /etc/kubernetes/manifests/kube-apiserver.yaml
...
spec:
  containers:
  - command:
    ...
    - --enable-bootstrap-token-auth=true
    - --enable-aggregator-routing=true  #新增
    
systemctl restart kubelet

通過 Metrics API,可以獲得指定節點或 Pod 當前使用的資源量。 此 API 不儲存指標值,因此想要獲取某個指定節點 10 分鐘前的 資源使用量是不可能的。

下載metrics-server部署檔案

wget  https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.7/components.yaml
vim components.yaml   
...
      containers:
      - name: metrics-server
        image: registry.cn-hangzhou.aliyuncs.com/ljck8s/metrics-server-amd64:v0.3.6
        imagePullPolicy: IfNotPresent
        args:
          - --cert-dir=/tmp
          - --secure-port=4443
          - --kubelet-insecure-tls                  #不驗證kubelet提供的https證書
          - --kubelet-preferred-address-types=InternalIP    #使用節點IP連線kubelet
          
kubectl  apply -f components.yaml 

啟動後檢視報錯,需等待一會 #F44336

kubectl  top  node 
W0126 01:57:05.323264   32596 top_node.go:119] Using json format to get metrics. Next release will switch to protocol-buffers, switch early by passing --use-protocol-buffers flag
error: metrics not available yet

kubectl  top  node 
W0126 01:57:29.562132   32827 top_node.go:119] Using json format to get metrics. Next release will switch to protocol-buffers, switch early by passing --use-protocol-buffers flag
NAME     CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%     
master   214m         5%     1226Mi          71%         
node1    30m          1%     449Mi           26%         
node2    <unknown>                           <unknown>               <unknown>               <unknown>      

kubectl  get hpa 
NAME    REFERENCE          TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
kubia   Deployment/kubia   <unknown>/20%   1         5         0          11s
kubectl  get hpa 
NAME    REFERENCE          TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
kubia   Deployment/kubia   0%/20%    1         5         1          2m42s

觸發自動擴容
要往 pod 傳送請求,增加它的 CPU 使用率,隨後應該看到 Autoscaler 檢測到這 一切並啟動更多的 pod 。需要通過一個 Service 來暴露 pod, 以便用單一 的 URL 訪問到所有 pod 。

 kubectl expose deployment kubia --port=80 --target-port=8080
 service/kubia exposed

在向 pod 傳送請求之前,在另一個終端裡執行以下命令,來觀察 HPA 與 Deployment 上發生了什麼

watch -n 1 kubectl get hpa,deployment
NAME                                        REFERENCE          TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/kubia   Deployment/kubia   <unknown>/30%   1         5         1          4h32m

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/kubia   1/1     1            1           4h37m

執行產生負載的 pod

kubectl  get svc 
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP   48d
kubia        ClusterIP   10.105.143.135   <none>        80/TCP    67m
kubectl run -it --rm --restart=Never loadgenerator --image=busybox -- sh -c "while true; do wget -O  - -q http://10.105.143.135; done" 
If you don't see a command prompt, try pressing enter.
This is v1 running in pod kubia-5957b4c689-hjnqw
This is v1 running in pod kubia-5957b4c689-hjnqw
This is v1 running in pod kubia-5957b4c689-hjnqw

觀察 Autoscaler 擴容 Deployment

kubectl describe  hpa kubia
Events:
  Type    Reason             Age    From                       Message
  ----    ------             ----   ----                       -------
  Normal  SuccessfulRescale  7m23s  horizontal-pod-autoscaler  New size: 4; reason: cpu resource utilization (percentage of request) above target
  Normal  SuccessfulRescale  7m8s   horizontal-pod-autoscaler  New size: 5; reason: cpu resource utilization (percentage of request) above target

kubectl  get pod 
NAME                     READY   STATUS              RESTARTS   AGE
kubia-5957b4c689-5lrwh   1/1     Running             0          41s
kubia-5957b4c689-75q8r   0/1     ContainerCreating   0          41s
kubia-5957b4c689-hjnqw   1/1     Running             0          81m
kubia-5957b4c689-nd54t   1/1     Running             0          41s
kubia-5957b4c689-qwrsv   1/1     Running             0          26s

pod 的縱向自動伸縮 VPA

Vertical Pod Autoscaler(VPA)使使用者無需為其pods中的容器設定最新的資源request。配置後,它將根據使用情況自動設定request,從而允許在節點上進行適當的排程,以便為每個pod提供適當的資源量。
使用名為VerticalPodAutoscaler的自定義資源定義物件配置自動縮放 。它允許指定垂直自動縮放的pod以及是否/如何應用資源建議。

必須在群集中部署Metrics Server

git clone https://github.com/kubernetes/autoscaler.git
下載的資源使用映象為 v0.9.0 , 國內下載不到

wget https://github.com/kubernetes/autoscaler/archive/refs/tags/vertical-pod-autoscaler-0.8.0.tar.gz
tar xvf autoscaler-vertical-pod-autoscaler-0.8.0.tar.gz

cd autoscaler/vertical-pod-autoscaler/deploy
admission-controller-deployment.yaml
us.gcr.io/k8s-artifacts-prod/autoscaling/vpa-admission-controller:0.8.0
改為
scofield/vpa-admission-controller:0.8.0

recommender-deployment.yaml
us.gcr.io/k8s-artifacts-prod/autoscaling/vpa-recommender:0.8.0
改為
image: scofield/vpa-recommender:0.8.0

updater-deployment.yaml
us.gcr.io/k8s-artifacts-prod/autoscaling/vpa-updater:0.8.0
改為
scofield/vpa-updater:0.8.0

./hack/vpa-up.sh
ERROR: Failed to create CA certificate for self-signing. If the error is "unknown option -addext", update your openssl version or deploy VPA from the vpa-release-0.8 branch

需要升級openssl的版本解決
yum install gcc gcc-c++ -y
openssl version -a
wget https://www.openssl.org/source/openssl-1.1.1k.tar.gz && tar zxf openssl-1.1.1k.tar.gz && cd openssl-1.1.1k
./config
make && make install
mv /usr/local/bin/openssl /usr/local/bin/openssl.bak
mv apps/openssl /usr/local/bin
openssl version -a

升級openssl後執行
vertical-pod-autoscaler/pkg/admission-controller/gencerts.sh

或
./hack/vpa-down.sh
./hack/vpa-up.sh

kubectl get po -n kube-system | grep -E "metrics-server|vpa"
metrics-server-7899654b87-xpvzp             1/1     Running   0          14h
vpa-admission-controller-7958497486-m6zxx   1/1     Running   0          35m
vpa-recommender-76478b64cf-57bvb            1/1     Running   0          35m
vpa-updater-6b987c7559-d7tv7                1/1     Running   0          35m

VPA使用限制
不能與HPA(Horizontal Pod Autoscaler )一起使用
Pod比如使用副本控制器,例如屬於Deployment或者StatefulSet

VPA的好處
Pod 資源用其所需,所以叢集節點使用效率高。
Pod 會被安排到具有適當可用資源的節點上。
不必執行基準測試任務來確定 CPU 和記憶體請求的合適值。
VPA 可以隨時調整 CPU 和記憶體請求,無需人為操作,因此可以減少維護時間。

VPA 參照 https://juejin.cn/post/6982867694378811400

Cluster Autoscaler介紹 CA

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

從雲端基礎架構請求新節點
如果在一個 pod 被建立之後,Scheduler 無法將其排程到任何一個已有節點,一個新節點就會被建立。ClusterAutoscaler 會注意此類 pod,並請求雲服務提供者啟動一個新節點。但在這麼做之前,它會檢查新節點有沒有可能容納這個 pod, 畢竟如果新節點本來就不可能容納它們,就沒必要啟動這麼一個節點了。
雲服務提供者通常把相同規格(或者有相同特性)的節點聚合成組。因此 Cluster Autoscaler 不能單純地說 “給我多一個節點”,它還需要指明節點型別。
Cluster Autoscaler 通過檢查可用的節點分組來確定是否有至少一種節點型別能容納未被排程的pod。如果只存在唯一一個此種節點分組,ClusterAutoscaler 就可以增加節點分組的大小,讓雲服務提供商給分組中增加一個節點。但如果存在多個滿足條件的節點分組, ClusterAutoscaler 就必須挑一個最合適的。這裡 “ 最合適” 的精確含義顯然必須是可配置的。在 最壞的情況下,它會隨機挑選一個。如圖簡單描述了 ClusterAutoscaler 面對一個不可排程pod時是如何反應的。

新節點啟動後,其上執行的 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 cordon <node> 標記節點為不可排程(但對其上的 pod不做任何事)。
kubectl drain <node> 標記節點為不可排程, 隨後疏散其上所有 pod 。
兩種情形下, 在用 kubectl uncordon <node> 解除節點的不可排程狀態之前, 不會有新 pod 被排程到該節點。

啟用Cluster Autoscaler

叢集自動伸縮在以下雲服務提供商可用:

  • Google Kubernetes En伊ne (GKE)
  • Google Compute Engine (GCE)
  • Amazon Web Services (A W S)
  • Microsoft Azure

https://dasydong.github.io/blog/2019/12/21/k8s-ca-code綜合篇/

https://feisky.gitbooks.io/kubernetes/content/addons/cluster-autoscaler.html