kubernetes之pod中斷

周國通發表於2019-06-06

系列目錄

目標讀者:

  • 想要構建高可用應用的應用所有者,因此需要知道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 BudgetsEviction 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

    • 沒有當機時間

    • 最小量資源複製

    • 允許更多的叢集自動化管理

    • 編寫能容忍中斷的程式是很有技巧的,但是容忍中斷的工作很大部分是與支援自動擴容和容忍非自願中斷是重疊的

相關文章