k8s從入門到放棄(2): 縮擴容&更新

前言

自動縮擴容是現代化的容器調度平臺帶給咱們的最激動人心的一項能力。在上規模的業務系統中咱們無時無刻不面臨着這樣的難題:用戶的流量每每隨着時間波動,甚至偶爾出現不可預測的峯值(毛刺流量),每當流量增長時都須要手工的對應用進行擴容,峯值流量消失後又須要將擴容的機器回收,運維起來費時費力。git

幸運的是,k8s這樣的容器調度平臺正在逐漸幫助咱們解決這樣的問題,它帶來的AutoScaler功能目前已經支持在多個不一樣維度上的彈性縮擴容,能夠根據應用的負載狀況進行自適應。儘管在一些較爲苛刻的場景下,因爲容器啓動速度等緣由的限制,AutoScaler的效果還不盡人意,但相信在不久的未來,自動縮擴容方案將會徹底成熟,屆時咱們將輕鬆獲取具備強大彈性能力的服務集羣。github

如今來試着使用一下k8s的Scale相關功能吧算法

手動調整服務規模

咱們可使用kubectl提供的命令來手動調整某個Deployment的規模,也就是其包含的Pod數量,這裏拿上一節裏建立的HelloWorld服務來做爲例子,當前的deployment狀態以下:緩存

  • DISIRED 表示配置時聲明的指望副本數
  • CURRENT 表示當前正在運行的副本數
  • UP-TO_DATE 表示符合預期狀態的副本數(好比某個副本宕機了,這裏就不會計算那個副本)
  • AVAILABLE 表示目前可用的副本數

咱們可使用kubectl scale命令來手動調整deployment的規模,如今嘗試把helloworld服務的副本數量擴充到4個:bash

執行命令後,k8s很快就爲咱們建立了另外3個helloworld的副本,這時候整個服務就有多個實例在運行了,那麼對應Service的負載均衡功能便會生效,能夠看到Service的狀態裏已經偵測到多個EndPoint:架構

當咱們連續調用service時,能夠看到每次實際調用的pod都不一樣(這裏對服務的源碼作了一些修改,打印出了hostname):app

同理,咱們也能夠用一樣的方式把服務縮容,好比把副本集的數量下調到兩個:負載均衡

自動縮擴容:極致彈性?

參考好文運維

剛纔的例子中,咱們是經過命令行的方式來手動調整服務規模的,顯然在面對線上真實流量時是不能這麼作的,咱們但願調度平臺可以根據服務的負載來智能地調控規模,進行彈性縮擴容。這時候就輪到k8s中的AutoScaler出場了ssh

到目前爲止,k8s一共提供了3個不一樣維度的AutoScaler,以下圖:

k8s把彈性伸縮分爲兩類:

  • 資源維度:保障集羣資源池大小知足總體規劃,當集羣內的資源不足以支撐產出新的pod時,就會觸發邊界進行擴容
  • 應用維度:保障應用的負載處在預期的容量規劃內

對應兩種伸縮策略:

  • 水平伸縮

    • 集羣維度:自動調整資源池規模(新增/刪除Worker節點)
    • Pod維度:自動調整Pod的副本集數量
  • 垂直伸縮

    • 集羣維度:不支持
    • Pod維度:自動調整應用的資源分配(增大/減小pod的cpu、內存佔用)

其中最爲成熟也是最爲經常使用的伸縮策略就是HPA(水平Pod伸縮),因此下面以它爲例來重點分析,官方文檔在此:https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/

基本流程

任何彈性系統的縮擴容都無外乎於如下幾個步驟:

  1. 採集監控指標
  2. 聚合監控指標,判斷是否須要執行縮擴容
  3. 執行縮擴容動做

下面就按照這個順序來分析HPA的工做方式,這裏先給出一個HPA大致的架構圖:

監控指標

根據官方文檔的描述,HPA是使用巡檢(Control Loop)的機制來採集Pod資源使用狀況的,默認採集間隔爲15s,能夠經過Controller Manager(Master節點上的一個進程)的--horizontal-pod-autoscaler-sync-period參數來手動控制。

目前HPA默認採集指標的實現是Heapster,它主要採集CPU的使用率;beta版本也支持自定義的監控指標採集,但尚不穩定,不推薦使用

所以能夠簡單認爲,HPA就是經過CPU的使用率做爲監控指標的

聚合算法

採集到CPU指標後,k8s經過下面的公式來判斷須要擴容多少個pod

desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]
複製代碼

ceil表示向上取整,舉個實際例子,假設某個服務運行了4個Pod,當前的CPU使用率爲50%,預期的CPU使用率爲25%,那麼知足預期的實際Pod數量就是4 * (50% / 25%) = 8個,即須要將Pod容量擴大一倍,增長4個Pod來知足需求

固然上述的指標並非絕對精確的,首先,k8s會盡量的讓指標往指望值靠近,而不是徹底相等,其次HPA設置了一個容忍度(tolerance)的概念,容許指標在必定範圍內偏離指望值,默認是0.1,這就意味着若是你設置調度策略爲CPU預期使用率 = 50%,實際的調度策略會是小於45%或者大於55%進行縮擴容,HPA會盡力把指標控制在這個範圍內(容忍度能夠經過--horizontal-pod-autoscaler-tolerance來調整)

另外有兩點須要說明的細節:

一是k8s作出決策的間隔,它不會連續地執行擴縮容動做,而是存在必定的cd,目前擴容動做的cd爲3分鐘,縮容則爲5分鐘

二是k8s針對擴容作了一個最大限制,每次擴容的pod數量不會大於當前副本數量的2倍

HPA實踐

最後咱們來嘗試實際使用一下HPA,依然是使用kubectl命令行的方式來建立:

kubectl autoscale deployment helloworld --cpu-percent=10 --min=1 --max=5
複製代碼

運行上面的命令後,能夠在dashboard看到HPA已經被建立,策略是以CPU使用率10%爲臨界值,最少副本集數量爲1,最大爲5:

使用kubectl get hpa也能夠看到:

可是這裏出現了異常,targets的當前CPU使用率始終顯示爲unknown,網上說是由於副本集裏沒有配置resources致使的。咱們須要在dashboard裏找到對應的副本集,而後在spec.containers.resources裏聲明requests和limits值:

其中requests表示pod所須要分配的資源配額,limits表示單個pod最大可以獲取到的資源配額。

配置完以後仍是沒有出現指標,繼續百度,發現沒有安裝heapster支持,那就安裝,具體方法可見此文,注意須要把國外gcr的鏡像經過阿里雲代理一把才能安裝(若是你不太會搞,能夠用我轉好的,見github),influxDBgrafanaheapster三個組件都裝好後,記得再裝一把heapster rbac(在kubeconfig/rbac目錄下),最後重啓一波minikube,打開控制檯,能夠看到節點頁面已經有了指標圖像:

kubectl top命令也能正常返回數值了:

然而,kubectl get hpa顯示cpu的當前指標仍是unknown,鬱悶,進到deployment裏看一把日誌:

能夠看到HPA一直在報沒法從metrics API獲取請求資源的錯誤,github走一波,找到一個相似的issue,緣由是1.9版本之後的k8s默認的監控指標來源從heapster變成了metrics-server(我用的1.0,坑),不過要再安裝一套metrics-server實在太麻煩了,能夠經過修改kube-controller-manager的啓動參數來禁用這個新特性。

minikube ssh進入到vm內部,而後找到/etc/kubernetes/manifests/kube-controller-manager.yaml這個文件,在啓動參數里加上--horizontal-pod-autoscaler-use-rest-clients=false,這時候對應的容器組會自動重啓更新,再執行kubectl get hpa,能夠看到cpu的指標終於Ok了:

留下了感動的淚水,終於能夠開始壓測試水了,趕忙搞個buzybox壓起來:

kubectl run -i --tty load-generator --image=busybox /bin/sh
複製代碼

寫個循環去訪問咱們的helloworld服務(爲了更快的出效果,我把服務的scale縮減到只有一個副本集,直接壓這個pod的ip)

/ # while true; do wget -q -O- http://172.17.0.5:8080; done
複製代碼

大概2,3分鐘後就能看到結果,此時查看hpa的狀態,能夠看到已經觸發水平擴容,副本集的數量由1個追加到4個:

dashboard上也能看到效果:

關掉壓測腳本,靜置一下子,再看HPA的狀態:

自動縮容到了1個副本集,那麼HPA的實踐使用到這裏就算是結束了

更新、發佈、回滾

服務代碼必然是會常常修改的,當代碼發生變更時,就須要從新打包生成鏡像,而後進行發佈和部署,來看看在k8s中是如何對這些步驟進行處理的。

如今咱們對代碼作了一些改動,加上了hostname的輸出,而後打包造成了一個2.0版本的新鏡像,下面須要把這個新版本的鏡像部署到k8s的容器集羣上,使用kubectl set image在deployment上指定新的鏡像:

kubectl set image deployments/helloworld helloworld=registry.cn-qingdao.aliyuncs.com/gold-faas/gold-demo-service:2.0
複製代碼

執行該命令後,能夠從kubectl和dashboard中看到,新的容器組正在被建立,同時舊的容器組也在被回收:

最終全部的舊版本pod都會被回收,只留下新發布版本的容器組副本集:

來測試一下服務是否更新:

假設咱們的發佈到線上的版本出現了致命的問題,須要緊急將服務回退到上一個版本,該怎麼作呢?使用kubectl rollout undo便可,來看看效果:

能夠看到執行回滾命令後,新版本的pod開始被回收,同時上一個版本鏡像所對應的pod被喚醒(這裏速度很是快,我感受k8s在發佈完新服務後可能並不會馬上銷燬歷史版本的pod實例,而是會緩存一段時間,這樣很是快速的回滾,只要把service的負載均衡指回歷史版本的pod就能夠了)

回滾完成後再度請求服務,能夠發現服務已經變回了上一個版本的內容:

上面這些發佈和回滾的特性在k8s中被稱爲滾動更新,它容許咱們按照必定的比例逐步(能夠手工設置百分比)更新pod,從而實現平滑的更新和回滾,也能夠藉此實現相似藍綠髮布和金絲雀發佈的功能。

小結

經過實際操做體驗了k8s的縮擴容以及發佈機制,雖然遇到了幾個坑,但總體上用起來仍是很是絲滑的,到這裏k8s的基本功能就探索的差很少了,從下一篇開始將會繼續深刻分析k8s的原理,敬請期待!

原文地址 http://marklux.cn/blog/107, 轉載請註明出處

相關文章
相關標籤/搜索