目標讀者:
-
想要構建高可用應用的應用所有者,因此需要知道pod會發生哪些類型的中斷
-
想要執行自動化(比如升級和自動擴容)的集群管理員.
自願和非自願的中斷
pod不會自動消息,除非有人(可能是一個人或者一個控制器)把它銷毀了,或者出現無法避免的硬件或者系統軟件錯誤.
我們把這些稱作非自願的不可避免的應用中斷.
以下是示例:
-
用於支撐節點的機會出現硬件故障
-
集群管理員誤操作把VM(實例)刪除了
-
虛擬機故障導致VM實例消失
-
kernel panic
-
由於網絡分區導致集群節點消失
-
由於資源耗盡導致pod被驅離
除了資源耗盡外,其它情況大部分讀者應該都非常熟悉,它們並不是kubernetes特有的.
我們稱其它的情況為自願中斷.這包括集群管理員或者應用擁有者采取的動作.應用擁有者采取的典型動作有:
-
刪除了管理pod的deployment或者其它控制器
-
更新了deployment的pod模板導致重啟
-
直接刪除pod(比如誤刪除)
集群管理員的動作有如下:
-
排干node以便升級或修復
-
排干一個node以便對集群縮容
-
從節點中刪除一個pod以便可以做其它的事情
這些動作可能由集群管理者直接觸發,或者自動觸發,或者有集群服務提供者觸發
詢問集群管理員或者雲服務提供商或者查詢文檔來確定是否觸發了自願中止.如果以上都沒有發生,你可以跳過創建Pod Disruption Budgets
注意:並非所有的自願中斷都被
Pod Disruption Budgets
約束,比如刪除deployment或者pod會繞過Pod Disruption Budgets
處理中斷
以下是一些可以減輕非自願中斷的辦法
-
確保pod請求需要的資源
-
如果你想要高可用,制作程序副本集
-
如果想要更高可用性,使用跨區域集群部署應用
自願中斷的頻率根據實際情況往往也是不同的.在一個基礎的集群上,可能根本不會有自願的中斷.但是集群管理員或者服務提供商可能會運行一些額外的服務導致自願中斷.比如滾動更新可能會導致自願中斷.一些自動集群擴容為了防止完整節點碎片化也會自願中斷.集群管理員或者服務提供商應該用文檔把可能導致的自願中斷寫出來,以便查詢.
kubernetes提供了這樣一種特性,當高頻率自願中斷發生時仍然能夠保證集群的高可用性,我們稱之為Disruption Budgets
Disruption Budgets
有些資料上翻譯為中斷預算,但是更多的是沒有翻譯,大家只要知道它的大致意思就行了,這里也不做翻譯
Disruption Budgets如何工作
應用所有者可以為每個應用創建一個PodDisruptionBudget(PDB)
對象.PDB限制一個包含副本集的集群由於自願中斷而同時宕掉的pod的個數.例如,一個基於仲裁投票的應用想要保證運行的副本數永遠不會低於某個數量以便仲裁.一個web前端想要保證運行中的副本數不會低於某一比例.
集群管理員和服務提供商應當通過遵守Pod Disruption Budgets
的Eviction API而不是直接刪除pod或者deployment.例如可以使用kubectl drain
當集群管理員想通過kubectl drain
命令來排干一個節點.命令會嘗試排干節點機器上的所有pod.驅離請求可能會暫時被拒絕,命令會周期性的重新發送失敗請求直到所有pod都終止,或者達到了設定的超時時間.
PDB規定了副本集可以容忍的副本集的數量(實際上是能容忍的最小值),這是相對於它期望的數量而言的.比如一個有.spec.replicas: 5
的deployment希望在任何時候都有五個副本,如果PDB允許有4個副本運行,則Eviction API
允許同一時刻有一個副本中斷,而不是2個.
期望的副本數量由pod控制器通過pod的.spec.replicas
計算得出,控制器通過.metadata.ownerReferences
被pod發現
PDB不能阻止非自願的中斷發生,但是它們會被計入預算
由於被刪除或者更新導到不可用的pod也會計入預算,但是控制器(比如deployment,stateful-set)滾動更新時不會被PDB限制,滾動更新導致的失敗會計入控制器的spec里
當一個pod通過eviction API被驅離,它會優雅的中止(請看podspec里的terminationGracePeriodSeconds
)
PDB示例
比如集群有從node-1到node-3這樣的3個節點.集群中運行着一些應用,其中一個有三個副本,叫作pod-a,pod-b和pod-c.此外還有一個無關的,包含PDB的pod稱作pod-x,它們的初始分布情況如下:
node-1 | node-2 | node-3 |
---|---|---|
pod-a available | pod-b available | pod-c available |
pod-x available |
同一副本集的三個節點是一個deployment的一部分,它們共享一個PDB,要求它們三個中至少有2個同時運行着.
假如集群管理員想要重啟節點以便修復一個內核bug,集群管理員首先嘗試通過kubectl drain
命令來排干node-1節點.命令會嘗試把pod-a和pod-x驅離節點node-1.命令馬上執行成功,上面的pod同時進入terminating
狀態.現在集群處於如下狀態:
node-1 draining | node-2 | node-3 |
---|---|---|
pod-a terminating | pod-b available | pod-c available |
pod-x terminating |
deployment發現其中一個節點終止了.因此它創建了一個替代節點叫作pod-d,由於node-1被封鎖,因此它會落到其它節點.其它的控制器也會創建一個pod-y來替代pod-x
注意,對一StatefulSet,pod-a可能叫作pod-1,需要在被替代之前完全終止,它仍然叫作pod-a,但是PID可能不同了.除此之外(pod的名字的區別),這個例子也適用於StatefulSet.
現在集群處於如下狀態:
node-1 draining | node-2 | node-3 |
---|---|---|
pod-a terminating | pod-b available | pod-c available |
pod-x terminating | pod-d starting | pod-y |
在某一個時間點,node-a上的節點被終止,現在集群的狀態如下
node-1 drained | node-2 | node-3 |
---|---|---|
pod-b available | pod-c available | |
pod-d starting | pod-y |
此時,如果一個沒有耐心的集群管理員嘗試排干node-2或者node-3,排干命令會被阻止,因為只有兩個可用的節點,它的PDB要求至少運行2個,過一段時間,pod-d變得可用
node-1 drained | node-2 | node-3 |
---|---|---|
pod-b available | pod-c available | |
pod-d available | pod-y |
此時,如果集群管理員嘗試排干node-2,排干命令會以一定順序驅離上面的兩個pod,比如說先是pod-b然后是pod-d,它會成功驅離pod-b.但是當嘗試驅離pod-d的時候會被拒絕,因為這會導致deployment只有一個可用pod
pod-b被驅離后並不會馬上在其它節點上落地開始工作,也就是這個節點的替代節點並不能馬上工作,此時如果再驅離pod-d會導致只有pod-c是可用的,因此會被拒絕.
deployment創建了一個pod-b的替代叫作pod-e,由於集群沒有足夠資源來調度pod-e因此此時drain會再入陷入阻塞.集群最終的狀態如下:
node-1 drained | node-2 | node-3 | no node |
---|---|---|---|
pod-b available | pod-c available | pod-e pending | |
pod-d available | pod-y |
此時,集群管理員需要添加一個節點來讓升級繼續.
你可以看到基於以下原因,kubernetes怎樣控制中斷的速率:
-
集群需要多少個副本
-
優雅地中止一個實例需要多長時間
-
一個新的實例啟動需要多長時間
-
控制器的類型
-
集群資源容量
分離集群擁有者和應用擁有者的角色
通常,把集群管理者和應用擁有者看作是對對方知之甚少不同的角色是有用的.這種職責分離在以下情形是有意義的:
-
多個開發團隊使用同一個集群,這時候有一個中立的專家角色
-
當一些第三方工具或者服務被用來做集群的自動化管理工作.
怎樣在集群中執行有中斷性的動作
如果你是集群管理員,由於節點或者系統軟件升級,你可能需要對集群的所有節點執行可能產生中斷的動作,有以下選項:
-
升級過程中接受宕機時間
-
故障轉移到一個完整的副本集群中.這能夠保證沒有宕機時間,但是可能需要花費高價錢來復制節點和花費人力來編排切換
-
使用能容忍中斷的程序和使用PDB
-
沒有宕機時間
-
最小量資源復制
-
允許更多的集群自動化管理
-
編寫能容忍中斷的程序是很有技巧的,但是容忍中斷的工作很大部分是與支持自動擴容和容忍非自願中斷是重疊的
-