亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Kubernetes中如何保證優雅地停止Pod

發布時間:2021-10-19 17:52:25 來源:億速云 閱讀:109 作者:柒染 欄目:大數據

今天就跟大家聊聊有關Kubernetes中如何保證優雅地停止Pod,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

一直以來我對優雅地停止 Pod 這件事理解得很單純:不就利用是 PreStop hook 做優雅退出嗎?但最近發現很多場景下 PreStop Hook 并不能很好地完成需求,這篇文章就簡單分析一下“優雅地停止 Pod”這回事兒。

何謂優雅停止?

優雅停止(Graceful shutdown)這個說法來自于操作系統,我們執行關機之后都得 OS 先完成一些清理操作,而與之相對的就是硬中止(Hard shutdown),比如拔電源。

到了分布式系統中,優雅停止就不僅僅是單機上進程自己的事了,往往還要與系統中的其它組件打交道。比如說我們起一個微服務,網關把一部分流量分給我們,這時:

  • 假如我們一聲不吭直接把進程殺了,那這部分流量就無法得到正確處理,部分用戶受到影響。不過還好,通常來說網關或者服務注冊中心會和我們的服務保持一個心跳,過了心跳超時之后系統會自動摘除我們的服務,問題也就解決了;這是硬中止,雖然我們整個系統寫得不錯能夠自愈,但還是會產生一些抖動甚至錯誤。

  • 假如我們先告訴網關或服務注冊中心我們要下線,等對方完成服務摘除操作再中止進程,那不會有任何流量受到影響;這是優雅停止,將單個組件的啟停對整個系統影響最小化。

按照慣例,SIGKILL 是硬終止的信號,而 SIGTERM 是通知進程優雅退出的信號,因此很多微服務框架會監聽 SIGTERM 信號,收到之后去做反注冊等清理操作,實現優雅退出。

PreStop Hook

回到 Kubernetes(下稱 K8s),當我們想干掉一個 Pod 的時候,理想狀況當然是 K8s 從對應的 Service(假如有的話)把這個 Pod 摘掉,同時給 Pod 發 SIGTERM 信號讓 Pod 中的各個容器優雅退出就行了。但實際上 Pod 有可能犯各種幺蛾子:

  • 已經卡死了,處理不了優雅退出的代碼邏輯或需要很久才能處理完成。

  • 優雅退出的邏輯有 BUG,自己死循環了。

  • 代碼寫得野,根本不理會 SIGTERM。

因此,K8s 的 Pod 終止流程中還有一個“最多可以容忍的時間”,即 grace period(在 Pod 的 .spec.terminationGracePeriodSeconds 字段中定義),這個值默認是 30 秒,我們在執行 kubectl delete 的時候也可通過 --grace-period 參數顯式指定一個優雅退出時間來覆蓋 Pod 中的配置。而當 grace period 超出之后,K8s 就只能選擇 SIGKILL 強制干掉 Pod 了。

很多場景下,除了把 Pod 從 K8s 的 Service 上摘下來以及進程內部的優雅退出之外,我們還必須做一些額外的事情,比如說從 K8s 外部的服務注冊中心上反注冊。這時就要用到 PreStop Hook 了,K8s 目前提供了 Exec 和 HTTP 兩種 PreStop Hook,實際用的時候,需要通過 Pod 的 .spec.containers[].lifecycle.preStop 字段為 Pod 中的每個容器單獨配置,比如:

spec:
  contaienrs:
  - name: my-awesome-container
    lifecycle:
      preStop:
        exec:
          command: ["/bin/sh","-c","/pre-stop.sh"]
復制代碼

/pre-stop.sh 腳本里就可以寫我們自己的清理邏輯。

最后我們串起來再整個表述一下 Pod 退出的流程(官方文檔里更嚴謹哦):

  1. 用戶刪除 Pod。


    • 2.1. Pod 進入 Terminating 狀態。

    • 2.2. 與此同時,K8s 會將 Pod 從對應的 service 上摘除。

    • 2.3. 與此同時,針對有 PreStop Hook 的容器,kubelet 會調用每個容器的 PreStop Hook,假如 PreStop Hook 的運行時間超出了 grace period,kubelet 會發送 SIGTERM 并再等 2 秒。

    • 2.4. 與此同時,針對沒有 PreStop Hook 的容器,kubelet 發送 SIGTERM。

  2. grace period 超出之后,kubelet 發送 SIGKILL 干掉尚未退出的容器。

這個過程很不錯,但它存在一個問題就是我們無法預測 Pod 會在多久之內完成優雅退出,也無法優雅地應對“優雅退出”失敗的情況。而在我們的產品 TiDB Operator 中,這就是一個無法接受的事情。

有狀態分布式應用的挑戰

為什么說無法接受這個流程呢?其實這個流程對無狀態應用來說通常是 OK 的,但下面這個場景就稍微復雜一點:

TiDB 中有一個核心的分布式 KV 存儲層 TiKV。TiKV 內部基于 Multi-Raft 做一致性存儲,這個架構比較復雜,這里我們可以簡化描述為一主多從的架構,Leader 寫入,Follower 同步。而我們的場景是要對 TiKV 做計劃性的運維操作,比如滾動升級,遷移節點。

在這個場景下,盡管系統可以接受小于半數的節點宕機,但對于預期性的停機,我們要盡量做到優雅停止。這是因為數據庫場景本身就是非常嚴苛的,基本上都處于整個架構的核心部分,因此我們要把抖動做到越小越好。要做到這點,就得做不少清理工作,比如說我們要在停機前將當前節點上的 Leader 全部遷移到其它節點上。

得益于系統的良好設計,大多數時候這類操作都很快,然而分布式系統中異常是家常便飯,優雅退出耗時過長甚至失敗的場景是我們必須要考慮的。假如類似的事情發生了,為了業務穩定和數據安全,我們就不能強制關閉 Pod,而應該停止操作過程,通知工程師介入。 這時,上面所說的 Pod 退出流程就不再適用了。

小心翼翼:手動控制所有流程

這個問題其實 K8s 本身沒有開箱即用的解決方案,于是我們在自己的 Controller 中(TiDB 對象本身就是一個 CRD)與非常細致地控制了各種操作場景下的服務啟停邏輯。

拋開細節不談,最后的大致邏輯是在每次停服務前,由 Controller 通知集群進行節點下線前的各種遷移操作,操作完成后,才真正下線節點,并進行下一個節點的操作。

而假如集群無法正常完成遷移等操作或耗時過久,我們也能“守住底線”,不會強行把節點干掉,這就保證了諸如滾動升級,節點遷移之類操作的安全性。

但這種辦法存在一個問題就是實現起來比較復雜,我們需要自己實現一個控制器,在其中實現細粒度的控制邏輯并且在 Controller 的控制循環中不斷去檢查能否安全停止 Pod。

另辟蹊徑:解耦 Pod 刪除的控制流

復雜的邏輯總是沒有簡單的邏輯好維護,同時寫 CRD 和 Controller 的開發量也不小,能不能有一種更簡潔,更通用的邏輯,能實現“保證優雅關閉(否則不關閉)”的需求呢?

有,辦法就是 ValidatingAdmissionWebhook。

這里先介紹一點點背景知識,Kubernetes 的 apiserver 一開始就有 AdmissionController 的設計,這個設計和各類 Web 框架中的 Filter 或 Middleware 很像,就是一個插件化的責任鏈,責任鏈中的每個插件針對 apiserver 收到的請求做一些操作或校驗。舉兩個插件的例子:

  • DefaultStorageClass,為沒有聲明 storageClass 的 PVC 自動設置 storageClass。

  • ResourceQuota,校驗 Pod 的資源使用是否超出了對應 Namespace 的 Quota。

雖然說這是插件化的,但在 1.7 之前,所有的 plugin 都需要寫到 apiserver 的代碼中一起編譯,很不靈活。而在 1.7 中 K8s 就引入了 Dynamic Admission Control 機制,允許用戶向 apiserver 注冊 webhook,而 apiserver 則通過 webhook 調用外部 server 來實現 filter 邏輯。1.9 中,這個特性進一步做了優化,把 webhook 分成了兩類: MutatingAdmissionWebhook 和 ValidatingAdmissionWebhook,顧名思義,前者就是操作 api 對象的,比如上文例子中的 DefaultStroageClass,而后者是校驗 api 對象的,比如 ResourceQuota。拆分之后,apiserver 就能保證在校驗(Validating)之前先做完所有的修改(Mutating),下面這個示意圖非常清晰:

Kubernetes中如何保證優雅地停止Pod

而我們的辦法就是,利用 ValidatingAdmissionWebhook,在重要的 Pod 收到刪除請求時,先在 webhook server 上請求集群進行下線前的清理和準備工作,并直接返回拒絕。這時候重點來了,Control Loop 為了達到目標狀態(比如說升級到新版本),會不斷地進行 reconcile,嘗試刪除 Pod,而我們的 webhook 則會不斷拒絕,除非集群已經完成了所有的清理和準備工作

下面是這個流程的分步描述:

Kubernetes中如何保證優雅地停止Pod

  1. 用戶更新資源對象。

  2. controller-manager watch 到對象變更。

  3. controller-manager 開始同步對象狀態,嘗試刪除第一個 Pod。

  4. apiserver 調用外部 webhook。

  5. webhook server 請求集群做 tikv-1 節點下線前的準備工作(這個請求是冪等的),并查詢準備工作是否完成,假如準備完成,允許刪除,假如沒有完成,則拒絕,整個流程會因為 controller manager 的控制循環回到第 2 步。

好像一下子所有東西都清晰了,這個 webhook 的邏輯很清晰,就是要保證所有相關的 Pod 刪除操作都要先完成優雅退出前的準備,完全不用關心外部的控制循環是怎么跑的,也因此它非常容易編寫和測試,非常優雅地滿足了我們“保證優雅關閉(否則不關閉)”的需求,目前我們正在考慮用這種方式替換線上的舊方案。

后記

其實 Dynamic Admission Control 的應用很廣,比如 Istio 就是用 MutatingAdmissionWebhook 來實現 envoy 容器的注入的。從上面的例子中我們也可以看到它的擴展能力很強,而且常常能站在一個正交的視角上,非常干凈地解決問題,與其它邏輯做到很好的解耦。

當然了,Kubernetes 中還有 非常多的擴展點,從 kubectl 到 apiserver,scheduler,kubelet(device plugin,flexvolume),自定義 Controller 再到集群層面的網絡(CNI),存儲(CSI)可以說是處處可以做事情。以前做一些常規的微服務部署對這些并不熟悉也沒用過,而現在面對 TiDB 這樣復雜的分布式系統,尤其在 Kubernetes 對有狀態應用和本地存儲的支持還不夠好的情況下,得在每一個擴展點上去悉心考量,做起來非常有意思。

看完上述內容,你們對Kubernetes中如何保證優雅地停止Pod有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

郑州市| 绥芬河市| 临洮县| 汶上县| 新巴尔虎右旗| 博白县| 乌什县| 滁州市| 綦江县| 阿图什市| 巴林左旗| 随州市| 全州县| 定陶县| 德昌县| 郴州市| 合肥市| 库伦旗| 潞城市| 奇台县| 凤冈县| 依兰县| 班玛县| 平和县| 聂拉木县| 义乌市| 紫云| 湘潭县| 新乐市| 萝北县| 丹巴县| 南皮县| 乳山市| 萨迦县| 金昌市| 怀宁县| 恩平市| 甘洛县| 九龙城区| 伊通| 屏东县|