Kubernetes Pod的生命周期

2022-04-29 11:47 更新

Pod 的生命周期

本頁面講述 Pod 的生命周期。 Pod 遵循一個預(yù)定義的生命周期,起始于 ?Pending ?階段,如果至少 其中有一個主要容器正常啟動,則進入 ?Running?,之后取決于 Pod 中是否有容器以 失敗狀態(tài)結(jié)束而進入 Succeeded 或者 Failed 階段。

在 Pod 運行期間,?kubelet ?能夠重啟容器以處理一些失效場景。 在 Pod 內(nèi)部,Kubernetes 跟蹤不同容器的狀態(tài) 并確定使 Pod 重新變得健康所需要采取的動作。

在 Kubernetes API 中,Pod 包含規(guī)約部分和實際狀態(tài)部分。 Pod 對象的狀態(tài)包含了一組 Pod 狀況(Conditions)。 如果應(yīng)用需要的話,你也可以向其中注入自定義的就緒性信息。

Pod 在其生命周期中只會被調(diào)度一次。 一旦 Pod 被調(diào)度(分派)到某個節(jié)點,Pod 會一直在該節(jié)點運行,直到 Pod 停止或者 被終止。

Pod 生命期 

和一個個獨立的應(yīng)用容器一樣,Pod 也被認為是相對臨時性(而不是長期存在)的實體。 Pod 會被創(chuàng)建、賦予一個唯一的 ID(UID), 并被調(diào)度到節(jié)點,并在終止(根據(jù)重啟策略)或刪除之前一直運行在該節(jié)點。

如果一個節(jié)點死掉了,調(diào)度到該節(jié)點 的 Pod 也被計劃在給定超時期限結(jié)束后刪除。

Pod 自身不具有自愈能力。如果 Pod 被調(diào)度到某節(jié)點 而該節(jié)點之后失效,Pod 會被刪除;類似地,Pod 無法在因節(jié)點資源 耗盡或者節(jié)點維護而被驅(qū)逐期間繼續(xù)存活。Kubernetes 使用一種高級抽象 來管理這些相對而言可隨時丟棄的 Pod 實例,稱作 控制器。

任何給定的 Pod (由 UID 定義)從不會被“重新調(diào)度(rescheduled)”到不同的節(jié)點; 相反,這一 Pod 可以被一個新的、幾乎完全相同的 Pod 替換掉。 如果需要,新 Pod 的名字可以不變,但是其 UID 會不同。

如果某物聲稱其生命期與某 Pod 相同,例如存儲卷, 這就意味著該對象在此 Pod (UID 亦相同)存在期間也一直存在。 如果 Pod 因為任何原因被刪除,甚至某完全相同的替代 Pod 被創(chuàng)建時, 這個相關(guān)的對象(例如這里的卷)也會被刪除并重建。

pod

  • Pod 結(jié)構(gòu)圖例
  • 一個包含多個容器的 Pod 中包含一個用來拉取文件的程序和一個 Web 服務(wù)器, 均使用持久卷作為容器間共享的存儲。

Pod 階段 

Pod 的 ?status ?字段是一個 PodStatus 對象,其中包含一個 ?phase ?字段。

Pod 的階段(Phase)是 Pod 在其生命周期中所處位置的簡單宏觀概述。 該階段并不是對容器或 Pod 狀態(tài)的綜合匯總,也不是為了成為完整的狀態(tài)機。

Pod 階段的數(shù)量和含義是嚴(yán)格定義的。 除了本文檔中列舉的內(nèi)容外,不應(yīng)該再假定 Pod 有其他的 ?phase ?值。

下面是 ?phase ?可能的值:

取值 描述
Pending(懸決) Pod 已被 Kubernetes 系統(tǒng)接受,但有一個或者多個容器尚未創(chuàng)建亦未運行。此階段包括等待 Pod 被調(diào)度的時間和通過網(wǎng)絡(luò)下載鏡像的時間。
Running(運行中) Pod 已經(jīng)綁定到了某個節(jié)點,Pod 中所有的容器都已被創(chuàng)建。至少有一個容器仍在運行,或者正處于啟動或重啟狀態(tài)。
Succeeded(成功) Pod 中的所有容器都已成功終止,并且不會再重啟。
Failed(失?。?/td> Pod 中的所有容器都已終止,并且至少有一個容器是因為失敗終止。也就是說,容器以非 0 狀態(tài)退出或者被系統(tǒng)終止。
Unknown(未知) 因為某些原因無法取得 Pod 的狀態(tài)。這種情況通常是因為與 Pod 所在主機通信失敗。

如果某節(jié)點死掉或者與集群中其他節(jié)點失聯(lián),Kubernetes 會實施一種策略,將失去的節(jié)點上運行的所有 Pod 的 ?phase ?設(shè)置為 ?Failed?。

容器狀態(tài) 

Kubernetes 會跟蹤 Pod 中每個容器的狀態(tài),就像它跟蹤 Pod 總體上的階段一樣。 你可以使用容器生命周期回調(diào) 來在容器生命周期中的特定時間點觸發(fā)事件。

一旦調(diào)度器將 Pod 分派給某個節(jié)點,kubelet 就通過 容器運行時 開始為 Pod 創(chuàng)建容器。 容器的狀態(tài)有三種:?Waiting?(等待)、?Running?(運行中)和 ?Terminated?(已終止)。

要檢查 Pod 中容器的狀態(tài),你可以使用 ?kubectl describe pod <pod 名稱>?。 其輸出中包含 Pod 中每個容器的狀態(tài)。

每種狀態(tài)都有特定的含義:

Waiting (等待) 

如果容器并不處在 ?Running ?或 ?Terminated ?狀態(tài)之一,它就處在 ?Waiting ?狀態(tài)。 處于 ?Waiting ?狀態(tài)的容器仍在運行它完成啟動所需要的操作:例如,從某個容器鏡像 倉庫拉取容器鏡像,或者向容器應(yīng)用 Secret 數(shù)據(jù)等等。 當(dāng)你使用 ?kubectl ?來查詢包含 ?Waiting ?狀態(tài)的容器的 Pod 時,你也會看到一個 Reason 字段,其中給出了容器處于等待狀態(tài)的原因。

Running(運行中) 

?Running ?狀態(tài)表明容器正在執(zhí)行狀態(tài)并且沒有問題發(fā)生。 如果配置了 ?postStart ?回調(diào),那么該回調(diào)已經(jīng)執(zhí)行且已完成。 如果你使用 ?kubectl ?來查詢包含 ?Running ?狀態(tài)的容器的 Pod 時,你也會看到 關(guān)于容器進入 ?Running ?狀態(tài)的信息。

Terminated(已終止) 

處于 ?Terminated ?狀態(tài)的容器已經(jīng)開始執(zhí)行并且或者正常結(jié)束或者因為某些原因失敗。 如果你使用 ?kubectl ?來查詢包含 ?Terminated ?狀態(tài)的容器的 Pod 時,你會看到 容器進入此狀態(tài)的原因、退出代碼以及容器執(zhí)行期間的起止時間。

如果容器配置了 ?preStop ?回調(diào),則該回調(diào)會在容器進入 ?Terminated ?狀態(tài)之前執(zhí)行。

容器重啟策略

Pod 的 ?spec ?中包含一個 ?restartPolicy ?字段,其可能取值包括 Always、OnFailure 和 Never。默認值是 Always。

?restartPolicy ?適用于 Pod 中的所有容器。?restartPolicy ?僅針對同一節(jié)點上 ?kubelet ?的容器重啟動作。當(dāng) Pod 中的容器退出時,?kubelet ?會按指數(shù)回退 方式計算重啟的延遲(10s、20s、40s、...),其最長延遲為 5 分鐘。 一旦某容器執(zhí)行了 10 分鐘并且沒有出現(xiàn)問題,?kubelet ?對該容器的重啟回退計時器執(zhí)行 重置操作。

Pod 狀況 

Pod 有一個 PodStatus 對象,其中包含一個 PodConditions 數(shù)組。Pod 可能通過也可能未通過其中的一些狀況測試。

  • ?PodScheduled?:Pod 已經(jīng)被調(diào)度到某節(jié)點;
  • ?ContainersReady?:Pod 中所有容器都已就緒;
  • ?Initialized?:所有的 Init 容器 都已成功完成;
  • ?Ready?:Pod 可以為請求提供服務(wù),并且應(yīng)該被添加到對應(yīng)服務(wù)的負載均衡池中。
字段名稱 描述
type Pod 狀況的名稱
status 表明該狀況是否適用,可能的取值有 "True", "False" 或 "Unknown"
lastProbeTime 上次探測 Pod 狀況時的時間戳
lastTransitionTime Pod 上次從一種狀態(tài)轉(zhuǎn)換到另一種狀態(tài)時的時間戳
reason 機器可讀的、駝峰編碼(UpperCamelCase)的文字,表述上次狀況變化的原因
message 人類可讀的消息,給出上次狀態(tài)轉(zhuǎn)換的詳細信息

Pod 就緒態(tài) 

FEATURE STATE: Kubernetes v1.14 [stable]

你的應(yīng)用可以向 PodStatus 中注入額外的反饋或者信號:Pod Readiness(Pod 就緒態(tài))。 要使用這一特性,可以設(shè)置 Pod 規(guī)約中的 ?readinessGates ?列表,為 kubelet 提供一組額外的狀況供其評估 Pod 就緒態(tài)時使用。

就緒態(tài)門控基于 Pod 的 ?status.conditions? 字段的當(dāng)前值來做決定。 如果 Kubernetes 無法在 ?status.conditions? 字段中找到某狀況,則該狀況的 狀態(tài)值默認為 "?False?"。

這里是一個例子:

kind: Pod
...
spec:
  readinessGates:
    - conditionType: "www.example.com/feature-1"
status:
  conditions:
    - type: Ready                              # 內(nèi)置的 Pod 狀況
      status: "False"
      lastProbeTime: null
      lastTransitionTime: 2018-01-01T00:00:00Z
    - type: "www.example.com/feature-1"        # 額外的 Pod 狀況
      status: "False"
      lastProbeTime: null
      lastTransitionTime: 2018-01-01T00:00:00Z
  containerStatuses:
    - containerID: docker://abcd...
      ready: true
...

你所添加的 Pod 狀況名稱必須滿足 Kubernetes 標(biāo)簽鍵名格式。

Pod 就緒態(tài)的狀態(tài)

命令 ?kubectl patch? 不支持修改對象的狀態(tài)。 如果需要設(shè)置 Pod 的 ?status.conditions?,應(yīng)用或者 Operators 需要使用 ?PATCH ?操作。 你可以使用 Kubernetes 客戶端庫 之一來編寫代碼,針對 Pod 就緒態(tài)設(shè)置定制的 Pod 狀況。

對于使用定制狀況的 Pod 而言,只有當(dāng)下面的陳述都適用時,該 Pod 才會被評估為就緒:

  • Pod 中所有容器都已就緒;
  • readinessGates 中的所有狀況都為 True 值。

當(dāng) Pod 的容器都已就緒,但至少一個定制狀況沒有取值或者取值為 ?False?, ?kubelet ?將 Pod 的狀況設(shè)置為 ?ContainersReady?。

容器探針 

probe 是由 kubelet 對容器執(zhí)行的定期診斷。 要執(zhí)行診斷,kubelet 既可以在容器內(nèi)執(zhí)行代碼,也可以發(fā)出一個網(wǎng)絡(luò)請求。

檢查機制 

使用探針來檢查容器有四種不同的方法。 每個探針都必須準(zhǔn)確定義為這四種機制中的一種:

  • exec
  • 在容器內(nèi)執(zhí)行指定命令。如果命令退出時返回碼為 0 則認為診斷成功。
  • grpc
  • 使用 gRPC 執(zhí)行一個遠程過程調(diào)用。 目標(biāo)應(yīng)該實現(xiàn) gRPC健康檢查。 如果響應(yīng)的狀態(tài)是 "SERVING",則認為診斷成功。 gRPC 探針是一個 alpha 特性,只有在你啟用了 "GRPCContainerProbe" 特性門控時才能使用。
  • httpGet
  • 對容器的 IP 地址上指定端口和路徑執(zhí)行 HTTP GET 請求。如果響應(yīng)的狀態(tài)碼大于等于 200 且小于 400,則診斷被認為是成功的。
  • tcpSocket
  • 對容器的 IP 地址上的指定端口執(zhí)行 TCP 檢查。如果端口打開,則診斷被認為是成功的。 如果遠程系統(tǒng)(容器)在打開連接后立即將其關(guān)閉,這算作是健康的。

探測結(jié)果 

每次探測都將獲得以下三種結(jié)果之一:

  • Success(成功)
  • 容器通過了診斷。
  • Failure(失?。?/li>容器未通過診斷。
  • Unknown(未知)
  • 診斷失敗,因此不會采取任何行動。

探測類型 

針對運行中的容器,?kubelet ?可以選擇是否執(zhí)行以下三種探針,以及如何針對探測結(jié)果作出反應(yīng):

  • livenessProbe
  • 指示容器是否正在運行。如果存活態(tài)探測失敗,則 kubelet 會殺死容器, 并且容器將根據(jù)其重啟策略決定未來。如果容器不提供存活探針, 則默認狀態(tài)為 Success。
  • readinessProbe
  • 指示容器是否準(zhǔn)備好為請求提供服務(wù)。如果就緒態(tài)探測失敗, 端點控制器將從與 Pod 匹配的所有服務(wù)的端點列表中刪除該 Pod 的 IP 地址。 初始延遲之前的就緒態(tài)的狀態(tài)值默認為 Failure。 如果容器不提供就緒態(tài)探針,則默認狀態(tài)為 Success。
  • startupProbe
  • 指示容器中的應(yīng)用是否已經(jīng)啟動。如果提供了啟動探針,則所有其他探針都會被 禁用,直到此探針成功為止。如果啟動探測失敗,kubelet 將殺死容器,而容器依其 重啟策略進行重啟。 如果容器沒有提供啟動探測,則默認狀態(tài)為 Success。

何時該使用存活態(tài)探針? 

FEATURE STATE: Kubernetes v1.0 [stable]

如果容器中的進程能夠在遇到問題或不健康的情況下自行崩潰,則不一定需要存活態(tài)探針; ?kubelet ?將根據(jù) Pod 的?restartPolicy ?自動執(zhí)行修復(fù)操作。

如果你希望容器在探測失敗時被殺死并重新啟動,那么請指定一個存活態(tài)探針, 并指定?restartPolicy ?為 "?Always?" 或 "?OnFailure?"。

何時該使用就緒態(tài)探針? 

FEATURE STATE: Kubernetes v1.0 [stable]

如果要僅在探測成功時才開始向 Pod 發(fā)送請求流量,請指定就緒態(tài)探針。 在這種情況下,就緒態(tài)探針可能與存活態(tài)探針相同,但是規(guī)約中的就緒態(tài)探針的存在意味著 Pod 將在啟動階段不接收任何數(shù)據(jù),并且只有在探針探測成功后才開始接收數(shù)據(jù)。

如果你希望容器能夠自行進入維護狀態(tài),也可以指定一個就緒態(tài)探針,檢查某個特定于 就緒態(tài)的因此不同于存活態(tài)探測的端點。

如果你的應(yīng)用程序?qū)蠖朔?wù)有嚴(yán)格的依賴性,你可以同時實現(xiàn)存活態(tài)和就緒態(tài)探針。 當(dāng)應(yīng)用程序本身是健康的,存活態(tài)探針檢測通過后,就緒態(tài)探針會額外檢查每個所需的后端服務(wù)是否可用。 這可以幫助你避免將流量導(dǎo)向只能返回錯誤信息的 Pod。

如果你的容器需要在啟動期間加載大型數(shù)據(jù)、配置文件或執(zhí)行遷移,你可以使用 啟動探針。 然而,如果你想?yún)^(qū)分已經(jīng)失敗的應(yīng)用和仍在處理其啟動數(shù)據(jù)的應(yīng)用,你可能更傾向于使用就緒探針。

請注意,如果你只是想在 Pod 被刪除時能夠排空請求,則不一定需要使用就緒態(tài)探針; 在刪除 Pod 時,Pod 會自動將自身置于未就緒狀態(tài),無論就緒態(tài)探針是否存在。 等待 Pod 中的容器停止期間,Pod 會一直處于未就緒狀態(tài)。

何時該使用啟動探針? 

FEATURE STATE: Kubernetes v1.18 [beta]

對于所包含的容器需要較長時間才能啟動就緒的 Pod 而言,啟動探針是有用的。 你不再需要配置一個較長的存活態(tài)探測時間間隔,只需要設(shè)置另一個獨立的配置選定, 對啟動期間的容器執(zhí)行探測,從而允許使用遠遠超出存活態(tài)時間間隔所允許的時長。

如果你的容器啟動時間通常超出 ?initialDelaySeconds + failureThreshold × periodSeconds? 總值,你應(yīng)該設(shè)置一個啟動探測,對存活態(tài)探針?biāo)褂玫耐欢它c執(zhí)行檢查。 ?periodSeconds ?的默認值是 10 秒。你應(yīng)該將其 ?failureThreshold? 設(shè)置得足夠高, 以便容器有充足的時間完成啟動,并且避免更改存活態(tài)探針?biāo)褂玫哪J值。 這一設(shè)置有助于減少死鎖狀況的發(fā)生。

Pod 的終止 

由于 Pod 所代表的是在集群中節(jié)點上運行的進程,當(dāng)不再需要這些進程時允許其體面地 終止是很重要的。一般不應(yīng)武斷地使用 ?KILL ?信號終止它們,導(dǎo)致這些進程沒有機會 完成清理操作。

設(shè)計的目標(biāo)是令你能夠請求刪除進程,并且知道進程何時被終止,同時也能夠確保刪除 操作終將完成。當(dāng)你請求刪除某個 Pod 時,集群會記錄并跟蹤 Pod 的體面終止周期, 而不是直接強制地殺死 Pod。在存在強制關(guān)閉設(shè)施的前提下, kubelet 會嘗試體面地終止 Pod。

通常情況下,容器運行時會發(fā)送一個 TERM 信號到每個容器中的主進程。 很多容器運行時都能夠注意到容器鏡像中 ?STOPSIGNAL ?的值,并發(fā)送該信號而不是 TERM。 一旦超出了體面終止限期,容器運行時會向所有剩余進程發(fā)送 KILL 信號,之后 Pod 就會被從 API 服務(wù)器 上移除。如果 ?kubelet ?或者容器運行時的管理服務(wù)在等待進程終止期間被重啟, 集群會從頭開始重試,賦予 Pod 完整的體面終止限期。

下面是一個例子:

  1. 你使用 ?kubectl ?工具手動刪除某個特定的 Pod,而該 Pod 的體面終止限期是默認值(30 秒)。
  2. API 服務(wù)器中的 Pod 對象被更新,記錄涵蓋體面終止限期在內(nèi) Pod 的最終死期,超出所計算時間點則認為 Pod 已死(dead)。 如果你使用 ?kubectl describe? 來查驗?zāi)阏趧h除的 Pod,該 Pod 會顯示為 "Terminating" (正在終止)。 在 Pod 運行所在的節(jié)點上:?kubelet ?一旦看到 Pod 被標(biāo)記為正在終止(已經(jīng)設(shè)置了體面終止限期),?kubelet ?即開始本地的 Pod 關(guān)閉過程。
    1. 如果 Pod 中的容器之一定義了 ?preStop ?回調(diào), ?kubelet ?開始在容器內(nèi)運行該回調(diào)邏輯。如果超出體面終止限期時,?preStop ?回調(diào)邏輯 仍在運行,?kubelet ?會請求給予該 Pod 的寬限期一次性增加 2 秒鐘。
    2. 如果 ?preStop ?回調(diào)所需要的時間長于默認的體面終止限期,你必須修改 ?terminationGracePeriodSeconds ?屬性值來使其正常工作。

    3. ?kubelet ?接下來觸發(fā)容器運行時發(fā)送 TERM 信號給每個容器中的進程 1。
    4. Pod 中的容器會在不同時刻收到 TERM 信號,接收順序也是不確定的。 如果關(guān)閉的順序很重要,可以考慮使用 ?preStop ?回調(diào)邏輯來協(xié)調(diào)。

  3. 與此同時,?kubelet ?啟動體面關(guān)閉邏輯,控制面會將 Pod 從對應(yīng)的端點列表(以及端點切片列表, 如果啟用了的話)中移除,過濾條件是 Pod 被對應(yīng)的 服務(wù)以某 選擇算符選定。 ReplicaSets和其他工作負載資源 不再將關(guān)閉進程中的 Pod 視為合法的、能夠提供服務(wù)的副本。關(guān)閉動作很慢的 Pod 也無法繼續(xù)處理請求數(shù)據(jù),因為負載均衡器(例如服務(wù)代理)已經(jīng)在終止寬限期開始的時候 將其從端點列表中移除。
  4. 超出終止寬限期限時,?kubelet ?會觸發(fā)強制關(guān)閉過程。容器運行時會向 Pod 中所有容器內(nèi) 仍在運行的進程發(fā)送 ?SIGKILL ?信號。 ?kubelet ?也會清理隱藏的 ?pause ?容器,如果容器運行時使用了這種容器的話。
  5. ?kubelet ?觸發(fā)強制從 API 服務(wù)器上刪除 Pod 對象的邏輯,并將體面終止限期設(shè)置為 0 (這意味著馬上刪除)。
  6. API 服務(wù)器刪除 Pod 的 API 對象,從任何客戶端都無法再看到該對象。

強制終止 Pod

對于某些工作負載及其 Pod 而言,強制刪除很可能會帶來某種破壞。

默認情況下,所有的刪除操作都會附有 30 秒鐘的寬限期限。 ?kubectl delete? 命令支持 ?--grace-period=<seconds>? 選項,允許你重載默認值, 設(shè)定自己希望的期限值。

將寬限期限強制設(shè)置為 ?0? 意味著立即從 API 服務(wù)器刪除 Pod。 如果 Pod 仍然運行于某節(jié)點上,強制刪除操作會觸發(fā) ?kubelet ?立即執(zhí)行清理操作。

你必須在設(shè)置 ?--grace-period=0? 的同時額外設(shè)置 ?--force? 參數(shù)才能發(fā)起強制刪除請求。

執(zhí)行強制刪除操作時,API 服務(wù)器不再等待來自 ?kubelet ?的、關(guān)于 Pod 已經(jīng)在原來運行的節(jié)點上終止執(zhí)行的確認消息。 API 服務(wù)器直接刪除 Pod 對象,這樣新的與之同名的 Pod 即可以被創(chuàng)建。 在節(jié)點側(cè),被設(shè)置為立即終止的 Pod 仍然會在被強行殺死之前獲得一點點的寬限時間。

失效 Pod 的垃圾收集 

對于已失敗的 Pod 而言,對應(yīng)的 API 對象仍然會保留在集群的 API 服務(wù)器上,直到 用戶或者控制器進程顯式地 將其刪除。

控制面組件會在 Pod 個數(shù)超出所配置的閾值 (根據(jù) ?kube-controller-manager? 的 ?terminated-pod-gc-threshold? 設(shè)置)時 刪除已終止的 Pod(階段值為 ?Succeeded ?或 ?Failed?)。 這一行為會避免隨著時間演進不斷創(chuàng)建和終止 Pod 而引起的資源泄露問題。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號