Kubernetes服務定時伸

Kubernetes服務定時伸縮

前言

容器技術的發展讓軟件的交付和運維更加標註化,輕量化,自動化.這使得動態調整負載的容其數量成爲一件非常簡單的事情,在kubernetes中,只需要修改對應的replcas數目即可完成,對應到我們的paas平臺上我們只改變手動伸縮進行調整也可以改變所需容器組數量即可

當負載的容量調整變得如此簡單後,我們再回過頭來看下應用的資源畫像。對於大部分互聯網的在線應用而言,負載的峯谷分佈是存在一定規律的。下圖是paas平臺中語音識別的敷在曲線,通過觀察不難發現峯值的週期是每天早上6點開始持續兩個小時,再到晚上九點開始持續兩個小時

每天低負載的時間爲16個小時高負載爲8個小時之間性能差距大約在5倍左右,如果使用純靜態的容器規劃方式進行部署與管理,可以計算的出資源的浪費比例爲53.33%(計算方式:(1-(8*5+16*1)/24*5)*100%).

在面對資源浪費的情況我們可以使用HPA基於指標閾值進行伸縮,paas平臺提供CPU,內存,QPS/p95/GPU等策略,但是這裏存在一個問題,因爲基於資源的伸縮是有一定時延的,這個時延主要包含:採集時延(分鐘級)+判斷時延(分鐘級)+伸縮時延(分鐘級)對於上圖我們可以看出負載的毛刺非常尖銳,這種情況下普通HPA的伸縮時延會造成負載無法及時變化,短時間內應用整體負載飆高,響應時間變慢,對於一些實時性的業務而言影響非常大.

爲了解決這個場景,我們將阿里雲開源的k8s組件kube-cronhpa-controller集成到paas平臺中,專門應對資源華興存在週期性的場景.可以通過自定義伸縮規則來提前擴容資源,並且預期的波谷定時將資源回收.我們在底層也結合了autoscaler在資源擴容的時候會根據配置好的伸縮組規則擴展指定機型.

系統設計

引入定時伸縮之後對系統的複雜性帶來了提高,主要面臨以下幾個問題:

  1. 避免在同一時間存在大量的擴容需求導致原有系統的不可用;
  2. 定時擴容的容器增多導致原有系統無法新增新的服務;
  3. 不同的業務服務需要使用不同的機器型號(如cpu/內存);

爲了避免上述一二問題的出現我們將現有的資源和定時擴容的資源劃分爲兩個部分,具體如下圖所示:

工作資源池與伸縮資源池是兩個不可見的空間,並且後者的node全部帶有污點:

  • 工作資源池:原有的資源池,用來提供服務部署,伸縮等;
  • 伸縮資源池:用來部署定時擴容出來的服務.

當某一個服務需要擴容時會對當給前的deployment進行copy並且添加特有的容忍和親和性,當到達指定的擴容時間deployment所管理的pod就會在伸縮資源池進行啓動.

下面的yaml配置截取自

spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: node/type
                operator: In
                values:
                  - AIASR
              - key: cronhpa
                operator: In
                values:
                  - paas
  tolerations:
    - key: AI_ASR
      value: paas
      effect: NoExecute
    - key: cronhpa
      value: paas
      effect: NoExecute

目前我們處理伸縮的資源是利用阿里雲的autoscale技術實現的,目前大部分雲服務提供商都支持k8snode級別的彈性伸縮,通過這種方式可以更大程度的降低我們機器的付費成本.

擴容服務的管理

在擴容之後的服務管理方面會通過監聽cronhpa規則的變化以及父deployment的變化進行更新

原則上新創建的deployment不應該提供修改和刪除操作,其修改只能通過監聽原deployment的變化進行修改,而刪除操作則綁定着將其創建出來的定時伸縮任務,任務存在則新建的deployment存在同樣任務刪除

工作流程

上圖的工作流程需要注意,在copy新的deployment的同時會出發autoscale,所以需要提前將雲服務商提供的autoscale功能配置好

[root ~]# kubectl get pod -n kube-system | grep auto
cluster-autoscaler-65885dc87b-h4s4r                               1/1     Running    0          18h

當新創建的deployment檢測到資源不足是回去檢查自身的親和度以及容忍是否符合伸縮組的配置,如果符合就會將新創建的機器彈出,如果不符合則無法完成擴容,這時就需要我們根據當前的需要擴容的pod的affinity配置新的伸縮組.

kube-cronhpa-controller部署

cronhpa是基於CRD的方式開發的controller,使用cronhpa的方式非常簡單,整體的使用習慣也儘可能的和HPA保持一致。代碼倉庫地址

1. 安裝CRD

kubectl apply -f config/crds/autoscaling_v1beta1_cronhorizontalpodautoscaler.yaml

2. 安裝RBAC授權

# create ClusterRole 
kubectl apply -f config/rbac/rbac_role.yaml

# create ClusterRolebinding and ServiceAccount 
kubectl apply -f config/rbac/rbac_role_binding.yaml

3. 部署kubernetes-cronhpa-controller

kubectl apply -f config/deploy/deploy.yaml

4. 驗證kubernetes-cronhpa-controller安裝狀態

kubectl get deploy kubernetes-cronhpa-controller -n kube-system -o wide 

kubernetes-cronhpa-controller git:(master)  kubectl get deploy kubernetes-cronhpa-controller -n kube-system
NAME                            DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
kubernetes-cronhpa-controller   1         1         1            1           49s

功能介紹

彈性伸縮自身是不限制伸縮次數以及伸縮時間的,在開源版本的文檔中也給出了配置的示例,具體的調度時間可以按照如下給出的規則自定義填寫.

Field name   | Mandatory? | Allowed values  | Allowed special characters
  ----------   | ---------- | --------------  | --------------------------
  Seconds      | Yes        | 0-59            | * / , -
  Minutes      | Yes        | 0-59            | * / , -
  Hours        | Yes        | 0-23            | * / , -
  Day of month | Yes        | 1-31            | * / , - ?
  Month        | Yes        | 1-12 or JAN-DEC | * / , -
  Day of week  | Yes        | 0-6 or SUN-SAT  | * / , - ?    

但是實際的使用場景其實並不需要很多複雜的規則,過度的開放功能反而會給用戶帶來選擇的煩惱,所以在paas平臺中我們直接將其抽象成了如下的形式

下圖的配置會在每天1時3分的時候新增一個pod在每天0是0分的時候將擴容的一個pod釋放掉

遇到的問題

擴容的node存在污點無法flannel等插件

上文講到所有新增的機器爲了和原有的節點隔離需要包含cronhpa=paas污點,但是對於flannel等基礎插件同樣會因爲污點的存在導致無法部署,最終使新增的node一直處於nodeReady狀態,爲了解決這個問題,需要修改flannel的DaemonSet在yaml中添加對應污點的容忍,或者是直接添加統配的容忍

      tolerations:
      - operator: Exists

DaemonSet的部署策略提供了兩種選擇,一種是OnDelete,即只有手工刪除了DaemonSet創建的Pod副本,新的Pod副本纔回被創建出來,如果不設置updateStrategy的值,則在Kubernetes1.6之後的版本中會被默認設置爲RollingUpdate,所謂的RollingUpdate就是滾動升級

通過觀察flannel的DaemonSet的升級方式是OnDelete所以在對其進行更新操作的時候並不會影響其他node的flannel,直接修改DaemonSet即可

kube-cronhpa-controller時區不統一

cronhpa作爲一個定時伸縮的組件那自然就會用到時間,如果kube-cronhpa-controller容器內部的時區和主機或者是當前所在的時區不同意就會造成無法在指定時間進行伸縮的情況,官方github上提供的源碼並沒有指定時區爲了解決這個問題,我們在部署鏡像的時候需要在yaml中手動指定時區:

spec:
  containers:
  - command:
    - /root/kubernetes-cronhpa-controller
    env:
    - name: TZ
      value: Asia/Shanghai

指定時區之後更新kube-cronhpa-controller進入容器查看時間

[root ~]# kubectl exec -it -n kube-system ack-kubernetes-cronhpa-controller-ack-kubernetes-cronhpa-cc8pwv /bin/sh
~ # date
Wed Dec 25 16:05:02 CST 2019

時間與當前時區同步即可

結束

paas平臺服務定時擴容的功能介紹到這裏基本就結束了,由於篇幅問題很多細節的問題沒有詳細介紹,有疑問的老師可以在下方評論區直接提問.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章