k8s集群Job Pod 容器可能因為多種原因失效,想要更加穩定的使用Job負載,有哪些需要注意的地方?

k8s集群Job Pod 容器可能因為多種原因失效,想要更加穩定的使用Job負載,有哪些需要注意的地方?

面試官:「計數性Job默認完成模式是什麼?Indexed模式如何發布自定義索引呢?」
面試官:「k8s的Job Pod 中的容器可能因為多種不同原因失效,想要更加穩定的使用Job負載,有哪些可以注意的地方?「
面試官:「為什麼k8s建議在調試 Job 時將 `restartPolicy` 設置為 "Never"?」
面試官:「Job 終止與清理了解嘛?Pod重試次數還未 達到 `backoffLimit` 所設的限制,為什麼突然被終止了?猜測原因?「

囧么肥事-胡說八道



計數性Job默認完成模式是什麼?Indexed模式如何發布自定義索引呢?

計數性Job默認完成模式是無索引模式NonIndexed

實際上,帶有 確定完成計數 的 Job,即 .spec.completions 不為 null 的 Job, 都可以在其 .spec.completionMode 中設置完成模式:NonIndexed(默認)和Indexed兩種。

先看默認模式NonIndexed,無索引模式👨‍💻‍

1、每個Job完成事件都是獨立無關且同質的
2、成功完成的Pod個數達到.spec.completions值時認為Job已經完成
3、當.spec.completions取值null時,Job被隱式處理為NonIndexed

再看Indexed,索引模式👨‍💻‍

1、Job 的 Pod 會分配對應的完成索引
2、索引取值為 0 到.spec.completions-1
3、當每個索引都對應一個完成的 Pod 時,Job 被認為是已完成的
4、同一索引值可能被分配給多個Pod,但是只有一個會被記入完成計數

對於索引模式來說,我下發10個索引,我不關注10個索引分別由多少個Pod去完成,我只關注10個索引任務是否按需完成即可。

Indexed模式下,索引有三種獲取方式:🤓

  • 第一種:基於註解,Pod 索引在註解 batch.kubernetes.io/job-completion-index中呈現,具體表示為一個十進位值字元串。
  • 第二種:基於主機名,作為 Pod 主機名的一部分,遵循模式 $(job-name)-$(index)。 當你同時使用帶索引的 Job(Indexed Job)與服務(Service), Job 中的 Pods 可以通過 DNS 使用確切的主機名互相定址。
  • 第三種:基於環境變數,對於容器化的任務,在環境變數 JOB_COMPLETION_INDEX 中體現。

Indexed模式如何發布自定義索引呢?

上面提到了三種獲取索引的方式:註解,主機名,環境變數。

Downward API 機制有兩種方式可以把將 Pod 和 Container 欄位資訊呈現給 Pod 中運行的容器:

  • 環境變數
  • 卷文件

你使用 Job 控制器為所有容器設置的內置 JOB_COMPLETION_INDEX 環境變數。 Init 容器將索引映射到一個靜態值,並將其寫入一個文件,該文件通過 emptyDir 卷與運行 worker 的容器共享

舉例👨‍💻‍

  1. 定義使用帶索引完成資訊的 Job 清單
  2. Downward API 將 Pod 索引注釋作為環境變數文件傳遞給容器。例如環境變數控制平面自動設置 downward API 以在 JOB_COMPLETION_INDEX 環境變數中公開索引
  3. 根據該清單啟動一個帶索引(Indexed)的 Job。

Pod 中的容器可能因為多種不同原因失效,想要更加穩定的使用Job負載,有哪些可以注意的地方?

首先需要理解的是,失效有兩種形式,需要適配的能力也不同。

第一種Pod管理的部分容器失效

第二種Pod失效

第一種Pod管理的部分容器失效

Pod 中的容器可能因為多種不同原因失效,例如因為其中的進程退出時返回值非零, 或者容器因為超出記憶體約束而被殺死等。

如果發生這類事件,並且 .spec.template.spec.restartPolicy = "OnFailure", Pod 則繼續留在當前節點,但容器會被重新運行。

面對這種場景,你的程式需要具備能夠處理在本地被重啟的情況的能力,或者容器設置 .spec.template.spec.restartPolicy = "Never"

注意,即使你將 .spec.parallelism 設置為 1,且將 .spec.completions 設置為 1,並且 .spec.template.spec.restartPolicy 設置為 “Never”,同一程式仍然有可能被啟動兩次😈,程式猿思維:「永遠不要假想某某情況不會發生🤣🤣🤣」。

它就發生了,你能咋滴,不管啊???🤡🤡🤡

第二種Pod失效

整個 Pod 也可能會失敗,且原因各不相同。 😇😇😇

例如,當 Pod 啟動時,節點失效(被升級、被重啟、被刪除等)🙃

或者其中的容器失敗並且設置了 .spec.template.spec.restartPolicy = "Never"

當 Pod 失敗時,Job 控制器會啟動一個新的 Pod 替身,去接替失敗的Pod未處理完成的工作。

這意味著,你的應用需要處理在一個新 Pod 中被重啟的情況。 尤其是應用需要處理之前運行所產生的臨時文件、鎖、不完整的輸出等問題。

再次注意😈

如果你將 .spec.parallelism.spec.completions 都設置為比 1 大的值, 那就有可能同時出現多個 Pod 運行的情況。

為此,你的 Pod 也必須能夠處理並發性問題☺️。

為什麼k8s建議在調試 Job 時將 restartPolicy 設置為 “Never”?

回答這個問題前,先看下Job Pod 回退失效策略

在有些情形下,你可能希望 Job 在經歷若干次重試之後直接進入失敗狀態,因為這很可能意味著Job遇到了配置錯誤。

  • .spec.backoffLimit 欄位設置Job Pod 回退失效策略,標識Job失敗重試次數,失效回退的限制值默認為 6。
  • 與 Job 相關的失效的 Pod 會被 Job 控制器重建,同時回退重試時間將會按指數增長 (從 10 秒、20 秒到 40 秒)最多至 6 分鐘。
  • 當 Job 的 Pod 被刪除,或者 Pod 成功時沒有其它 Pod 處於失敗狀態,失效回退的次數也會被重置(為 0)。

好了,這下可以回答剛才的問題,為什麼重啟策略要設置為Never?

如果你的 Job 的 restartPolicy 被設置為 “OnFailure“,那麼該 Job 管理的 Pod 會在 Job 到達失效回退次數上限時自動被終止

Pob 被終止,那麼調試 Job 中可執行文件的工作變得非常棘手,難以把控。也許你剛調試沒多久,結果Pod終止了,調試過程中斷了,絕望不!!!

為了解決Pod終止後 Jobs 的輸出遺失掉的問題,k8s建議在調試 Job 時將 restartPolicy 設置為 “Never”, 或者使用日誌系統來確保失效 Jobs 的輸出不會意外遺失。

Job 終止與清理了解嘛?Pod重試次數還未 達到 backoffLimit 所設的限制,為什麼突然被終止了?猜測原因?

Job終止和清理策略

Job 完成時不會再創建新的 Pod,不過已有的 Pod 也不會被刪除

保留這些 Pod 使得你可以查看已完成的 Pod 的日誌輸出,以便檢查錯誤、警告 或者其它診斷性輸出。

Job 完成時 Job 對象也一樣被保留下來,這樣你就可以查看它的狀態。

刪除老的 Job 的操作留給了用戶自己,在查看了 Job 狀態之後,你可以使用 kubectl 來刪除 Job(例如,kubectl delete jobs/pi 或者 kubectl delete -f ./job.yaml)。 當使用 kubectl 來刪除 Job 時,該 Job 所創建的 Pods 也會被刪除。

默認情況下,Job 會持續運行,除非某個 Pod 失敗(restartPolicy=Never) 或者某個容器出錯退出(restartPolicy=OnFailure)。 這時,Job 基於前述的 spec.backoffLimit 來決定是否以及如何重試。 一旦重試次數到達 .spec.backoffLimit 所設的上限,Job 會被標記為失敗, 其中運行的 Pods 都會被終止。

終止 Job 的另一種方式是設置一個活躍期限。 你可以為 Job 的 .spec.activeDeadlineSeconds 設置一個秒數值。 該值適用於 Job 的整個生命期,無論 Job 創建了多少個 Pod。 一旦 Job 運行時間達到 activeDeadlineSeconds 秒,其所有運行中的 Pod 都會被終止,並且 Job 的狀態更新為 type: Failedreason: DeadlineExceeded

注意 Job 的 .spec.activeDeadlineSeconds 優先順序高於其 .spec.backoffLimit 設置。 因此,如果一個 Job 正在重試一個或多個失效的 Pod,該 Job 一旦到達 activeDeadlineSeconds 所設的時限,即不再部署額外的 Pod,即使其重試次數還未達到 backoffLimit 所設的限制

注意問題

Job 規約和 Job 中的Pod 模版規約都有 activeDeadlineSeconds 欄位。 請確保你在合適的層次設置正確的欄位。

還要注意的是,restartPolicy 對應的是 Pod,而不是 Job 本身: 一旦 Job 狀態變為 type: Failed,就不會再發生 Job 重啟的動作。 換言之,由 .spec.activeDeadlineSeconds.spec.backoffLimit 所觸發的 Job 終結機制 都會導致 Job 永久性的失敗,而這類狀態都需要手工干預才能解決。