一起學習Kubernetes:工作負載重點總結(jié)
容器
容器:容器是容器鏡像的運行態(tài),通過基于標準的容器運行時運行,將應用程序從底層的主機設(shè)施中解耦。
容器鏡像:容器鏡像是一個隨時可以運行的軟件包,包含運行應用程序所需的一切:代碼和它需要的所有運行時、應用程序和系統(tǒng)庫,以及一些基本設(shè)置的默認值。
容器環(huán)境:在容器鏡像的基礎(chǔ)上,包括文件系統(tǒng)以及各種env變量、hostname、掛載的各種volume,共同組成了容器真正的運行環(huán)境。
容器運行時:負責管理 Kubernetes 環(huán)境中容器的執(zhí)行和生命周期,通過容器運行時接口(CRI)與Kubernetes交互。
容器生命周期中的回調(diào):特定運行時支持PostStart(異步)和PreStop(同步)回調(diào)。
容器更新和拉取:建議使用容器標簽或者摘要指定要更新的鏡像名,并配合明確的拉取策略(IfNotPresent/Always),為了加速鏡像拉取可以選擇啟用并行拉取以及預先拉取,同時需要通過憑據(jù)保護私有倉庫的訪問。
Pod
Pod 是可以在 Kubernetes 中創(chuàng)建和管理的、最小的可部署的計算單元。
Pod 內(nèi)的容器共享namespace(共享進程、網(wǎng)絡(luò)、IPC和主機名)和文件系統(tǒng)卷。
Pod 中的容器可以在特權(quán)模式下運行,以使用原本無法訪問的操作系統(tǒng)管理權(quán)能。
通常不需要直接創(chuàng)建 Pod,應該使用諸如 Deployment 這類工作負載資源來創(chuàng)建 Pod。
Pod的更新遵循“刪除-重建”模式,能更新的只有[*].image、activeDeadlineSeconds 和tolerations。
Pod生命周期
Pod是一次性調(diào)度單元,重新調(diào)度、重啟等都是基于刪除舊的、新建新的策略;
Pod有Pending、Running、Successded、Failed、Unknows五個狀態(tài),容器有Waiting、Running、Terminated狀態(tài);
1.29版本加入Pod 就緒態(tài)的狀態(tài)用于更細力度區(qū)分contaienrs ready和Pod ready;
Pod探測:StartupProbe(是否啟動)、livenessProbe(是否存活)、ReadlinessProbe(是否Ready);
Pod支持優(yōu)雅停止,刪除一個Pod時會先發(fā)Term信號,提示Pod內(nèi)的服務(wù)開始排空請求,默認30s后,如果Pod還沒終止,就發(fā)送KILL信號強制殺死Pod。
kubectl delete --force會觸發(fā)強制刪除。
PodGC控制器會自動回收非預期的Pod。
init容器是一種在 Pod 內(nèi)的應用容器啟動之前運行的特殊容器,如果為一個 Pod 指定了多個 Init 容器,會在網(wǎng)絡(luò)和數(shù)據(jù)卷初始化后按順序逐個運行。
每個 Init 容器必須運行成功,下一個才能夠運行,當所有的 Init 容器運行完成時, Kubernetes 才會為 Pod 初始化應用容器并像平常一樣運行。
如果 Pod 重啟,所有 Init 容器必須重新執(zhí)行。因為 Init 容器可能會被重啟、重試或者重新執(zhí)行,所以 Init 容器的代碼應該是冪等的。
Pod中某個資源request/limit的有效值=max(init容器某資源request/limit的最大值,應用容器某資源request/limit之和),調(diào)度和管理基于Pod有效資源值進行。
邊車容器是一種特殊的常駐init容器,遵循init容器啟動順序,在創(chuàng)建Init 容器時將 restartPolicy 設(shè)置為 Always將變?yōu)檫呠嚾萜鳎谡麄€ Pod 的生命周期中都處于活動狀態(tài),并且可以獨立于主容器啟動和停止,具有獨立生命周期并支持探針來控制其生命周期。
臨時容器可以在現(xiàn)有 Pod 中臨時運行,以便完成用戶發(fā)起的操作,例如故障排查。當由于容器崩潰或容器鏡像不包含調(diào)試工具而導致 kubectl exec 無用時,臨時容器對于交互式故障排查很有用。kubectl debug就是使用臨時容器實現(xiàn)的,用于distroless鏡像排查問題很有用,需要注意的是使用時需要共享進程命名空間。
當一個 Node 耗盡資源時,Kubernetes 將首先驅(qū)逐該 Node 上運行的 BestEffort Pod,然后是 Burstable Pod,最后是 Guaranteed Pod。
Guaranteed Pod:Pod內(nèi)部所有容器都有設(shè)置request和limit,且值一樣;Burstable Pod:Pod內(nèi)部至少有一個容器設(shè)置了資源request/limit;BestEffort Pod:Pod內(nèi)部容器都沒有設(shè)置資源request/limit。
故障預算(PDB)指定應用可以容忍的副本數(shù)量(相當于應該有多少副本),可以防止非預期的Pod終止情況。
在進行滾動升級時不受 PDB 的限制,更新期間的處理方式是在對應的工作負載資源的 spec 中配置的。
Pod終止狀況(PodDisruptionConditions)指示Pod終止原因。
在 Kubernetes 中,有兩種方法可以將 Pod 和容器字段暴露給運行中的容器:
- 作為環(huán)境變量,這個是最常用的
- 作為 downwardAPI 卷中的文件
這兩種暴露 Pod 和容器字段的方式統(tǒng)稱為 Downward API。通常使用現(xiàn)代的開發(fā)框架,如springboot,都可以自動識別很多Pod和容器信息,具體需要參考各個框架。應用最常用的是環(huán)境變量方案獲取Podname或者IP,用于設(shè)置日志文件名稱或者注冊中心注冊,這兩個信息通常默認都有(HOSTNAME和XXX_SERVICE_HOST),不需要額外注入,其他信息需要根據(jù)需要選擇注入。
工作負載
Deployment
Deployment 為 Pod 和 ReplicaSet 提供聲明式的更新能力。
Deployment 為 Pod 和 ReplicaSet提供聲明式的更新能力,幫助用戶自動化的管理Pod和服務(wù),包括Pod更新、回滾、縮放等運維操作。
Deployment每次更新會發(fā)起一個新的ReplicaSet,ReplicaSet部署對應Pod。
命名規(guī)則:Deployment的name由.metadata.name指定,ReplicaSet的name由.metadata.name-Pod-template-hash組成,Pod name查了代碼發(fā)現(xiàn)是在ReplicaSet名稱后面附加5個隨機字符。
僅當 Deployment Pod 模板(即 .spec.template)發(fā)生改變時,例如模板的標簽或容器鏡像被更新,才會觸發(fā)Deployment 更新。
在 API 版本 apps/v1 中,Deployment 標簽選擇算符在創(chuàng)建后是不可變的,且.spec.selector 必須匹配 .spec.template.metadata.labels,否則請求會被 API 拒絕。
當 Deployment 正在更新時又被更新,Deployment 會針對更新創(chuàng)建一個新的 ReplicaSet 并開始對其擴容,之前正在被擴容的 ReplicaSet 會被縮容,添加到舊 ReplicaSet 列表 并開始縮容。
如果 .spec.strategy.type==Recreate,在創(chuàng)建新 Pod 之前,所有現(xiàn)有的 Pod 會被殺死。若 .spec.strategy.type==RollingUpdate時,采取滾動更新的方式更新 Pod。可以指定 maxUnavailable 和 maxSurge 來控制滾動更新過程,默認值都是25%。
Deployment支持比例縮放,如果一個Deployment存在多個ReplicaSet在執(zhí)行更新過程,那么縮放時按當前rs中的Pod數(shù)量等比例縮放,而不是一股腦都給最新的rs。
Deployment更新前或者更新過程中,可以設(shè)置暫停更新,然后修改各種信息后,重新恢復執(zhí)行,此時會自動應用最新修改后的更新。
Deployment默認保持最新10次的ReplicaSet記錄,這樣可以支持回滾到最近10次修改,建議還是用git記錄所有歷史YAML的修改。
Deployment狀態(tài)有三種:Progressing、Complete、Failed。
Deployment其實不支持金絲雀發(fā)布,需要額外或者更高級的控制Deployment實現(xiàn)金絲雀發(fā)布的能力。
StatefulSet
StatefulSet 是用來管理有狀態(tài)應用的工作負載 API 對象,可以管理某 Pod 集合的部署和擴縮,并為這些 Pod 提供持久存儲和持久標識符,包括:
- 穩(wěn)定的、唯一的網(wǎng)絡(luò)標識符
- 穩(wěn)定的、持久的存儲
- 有序的、優(yōu)雅的部署和擴縮
- 有序的、自動的滾動更新
重點能力如下:
序號:對于具有 N 個副本的 StatefulSet,該 StatefulSet 中的每個 Pod 將被分配一個整數(shù)序號,該序號在此 StatefulSet 中是唯一的。默認情況下,這些 Pod 將被賦予從 0 到 N-1 的序號。
主機標識:StatefulSet 中的每個 Pod 根據(jù) StatefulSet 的名稱和 Pod 的序號派生出它的主機名,格式為$(StatefulSet 名稱)-$(序號)。
網(wǎng)絡(luò)標識:需要創(chuàng)建Headless服務(wù)以便為 Pod 提供網(wǎng)絡(luò)標識,格式為$(podname).$(servicename).$(namespace).svc.cluster.local。
持久存儲:對于 StatefulSet 中定義的 VolumeClaimTemplate,每個 Pod 接收到一個 PersistentVolumeClaim。 當 Pod 或者 StatefulSet 被刪除時,與 PersistentVolumeClaims 相關(guān)聯(lián)的 PersistentVolume 并不會被刪除,要刪除它必須通過手動方式來完成。
部署的順序性:對于包含 N 個副本的StatefulSet,當部署 Pod 時,它們是依次創(chuàng)建的,順序為 0..N-1。當刪除 Pod 時,它們是逆序終止的,順序為 N-1..0。在將擴縮操作應用到 Pod 之前,它前面的所有 Pod 必須是 Running 和 Ready 狀態(tài)。在一個 Pod 終止之前,所有的繼任者必須完全關(guān)閉。
滾動更新:StatefulSet 控制器會刪除和重建 StatefulSet 中的每個 Pod,按照與 Pod 終止相同的順序(從最大序號到最小序號)進行,每次更新一個 Pod。
滾動更新的異常處置:如果更新后 Pod 模板配置進入無法運行或就緒的狀態(tài)StatefulSet 將停止回滾并等待?;謴湍0搴?,StatefulSet 繼續(xù)等待損壞狀態(tài)的 Pod 準備就緒(永遠不會發(fā)生),此時必須刪除 StatefulSet 嘗試使用錯誤的配置來運行的 Pod, StatefulSet 才會開始使用被還原的模板來重新創(chuàng)建 Pod(已知問題kubernetes/issues/67250)。
來自 volumeClaimTemplate 的 PVC 默認策略是在 Pod 被刪除時不受影響,依然保留。
DaemonSet
DaemonSet 與 Deployment 非常類似,但DaemonSet 確保全部(或者某些)節(jié)點上運行一個 Pod 的副本。當有節(jié)點加入集群時,也會為他們新增一個 Pod,當有節(jié)點從集群移除時,這些 Pod 也會被回收,刪除 DaemonSet 將會刪除它創(chuàng)建的所有 Pod。
- DaemonSet 比較適合運維工具的部署,例如監(jiān)控、日志采集等組件。
- DaemonSet 遵循 .spec.template.spec.nodeSelector 和 .spec.template.spec.affinity 限制,只在滿足節(jié)點親和性的節(jié)點上部署 Pod。 如果沒有指定,則 DaemonSet Controller 將在所有節(jié)點上創(chuàng)建 Pod。
- 調(diào)度起評估符合條件的節(jié)點時,原本在 .spec.template.spec.affinity.nodeAffinity 字段上指定的節(jié)點親和性將由 DaemonSet 控制器進行考慮,但在創(chuàng)建的 Pod 上會被替換為與符合條件的節(jié)點名稱匹配的節(jié)點親和性。
- DaemonSet 控制器會自動將一組容忍度添加到 DaemonSet Pod,以實現(xiàn)可以被調(diào)度到不健康或還不準備接受 Pod 的節(jié)點上,包括不健康、沒Ready、不可達、不可調(diào)度以及資源使用原理的節(jié)點。
- DaemonSet 默認更新策略是滾動更新。
Job
Job 會創(chuàng)建一個或者多個 Pod,并將繼續(xù)重試 Pod 的執(zhí)行,直到指定數(shù)量的 Pod 成功終止。 隨著 Pod 成功結(jié)束,Job 跟蹤記錄成功完成的 Pod 個數(shù)。 當數(shù)量達到指定的成功個數(shù)閾值時,任務(wù)(即 Job)結(jié)束。
- Job 會創(chuàng)建一個或者多個 Pod,并將繼續(xù)重試 Pod 的執(zhí)行,直到指定數(shù)量的 Pod 成功終止。 隨著 Pod 成功結(jié)束,Job 跟蹤記錄成功完成的 Pod 個數(shù)。 當數(shù)量達到指定的成功個數(shù)閾值時,任務(wù)(即 Job)結(jié)束。
- 掛起 Job 的操作會刪除 Job 的所有活躍 Pod(可能執(zhí)行了部分),直到 Job 被再次恢復執(zhí)行(重新調(diào)度新的Pod再次執(zhí)行)。
- 刪除 Job 的操作會清除所創(chuàng)建的全部 Pod。
- Job Spec中通常不設(shè)置Labels和Selctor,RestartPolicy 只能設(shè)置為 Never 或 OnFailure 之一。spec.completions 和 spec.parallelism代表完成數(shù)和并行數(shù),默認都是1,可以根據(jù)任務(wù)需要的完成數(shù)和并行度分別設(shè)置。
- 容器失?。寒擯od中的容器運行失敗時,當RestartPolicy=OnFailure會重啟容器,當RestartPolicy=Never不會重啟容器,會直接將Pod狀態(tài)修改為Failed。
- Pod失敗:Job會重新調(diào)度一個新的Pod運行,所以程序需要處理冪等問題。
- Pod失敗回退策略:.spec.backoffLimit 設(shè)置 Job 失敗之前Pod的重試次數(shù),默認6,回退重試時間將會按指數(shù)增長 (從 10 秒、20 秒到 40 秒)最多至 6 分鐘。
- Pod失敗次數(shù)統(tǒng)計方法:第一種是Pod狀態(tài)為Failed,但對于RestartPolicy=OnFailure會重啟容器的Pod,容器失敗次數(shù)也會當做Pod失敗次數(shù)。當失敗次數(shù)超過.spec.backoffLimit 時會將Job狀態(tài)設(shè)置為Failed。
- .spec.podFailurePolicy 字段支持配置 Pod 失效策略,該策略可以根據(jù)容器退出碼和 Pod 狀況來處理 Pod 失效。
- Job 完成時(不論成功或失敗)不會再創(chuàng)建新的 Pod,不過已有的 Pod 通常也不會被刪除。 保留這些 Pod 使得你可以查看已完成的 Pod 的日志輸出,以便檢查錯誤、警告或者其它診斷性輸出。 Job 完成時 Job 對象也一樣被保留下來,這樣你就可以查看它的狀態(tài)。 在查看了 Job 狀態(tài)之后刪除老的 Job 的操作留給了用戶自己。
- 自動清理已完成 Job (狀態(tài)為 Complete 或 Failed)的一種方式是使用由 TTL 控制器所提供的 TTL 機制。 通過設(shè)置 Job 的 .spec.ttlSecondsAfterFinished 字段,可以讓該控制器清理掉已結(jié)束的資源。
- 可以為 Job 的 .spec.activeDeadlineSeconds 設(shè)置一個秒數(shù)值,該值適用于 Job 的整個生命期,無論 Job 創(chuàng)建了多少個 Pod,一旦 Job 運行時間達到 activeDeadlineSeconds 秒,其所有運行中的 Pod 都會被終止,并且 Job 的狀態(tài)更新為 type: Failed 及 reason: DeadlineExceeded。
CronJob
CronJob 創(chuàng)建基于時隔重復調(diào)度的 Job。CronJob 用于執(zhí)行排期操作,例如備份、生成報告等。 一個 CronJob 對象就像 Unix 系統(tǒng)上的 crontab(cron table)文件中的一行。 它用 Cron 格式進行編寫,并周期性地在給定的調(diào)度時間執(zhí)行 Job。
# ┌───────────── 分鐘 (0 - 59)
# │ ┌───────────── 小時 (0 - 23)
# │ │ ┌───────────── 月的某天 (1 - 31)
# │ │ │ ┌───────────── 月份 (1 - 12)
# │ │ │ │ ┌───────────── 周的某天 (0 - 6)(周日到周六)
# │ │ │ │ │ 或者是 sun,mon,tue,web,thu,fri,sat
# │ │ │ │ │
# │ │ │ │ │
# * * * * *
CronJob 創(chuàng)建基于時隔重復調(diào)度的 Job,Job負責Pod生成和調(diào)度執(zhí)行。
CronJob 用于執(zhí)行排期操作,例如備份、生成報告等。一個 CronJob 對象就像 Unix 系統(tǒng)上的 crontab(cron table)文件中的一行。 它用 Cron 格式進行編寫[分 時 日 月 周],并周期性地在給定的調(diào)度時間執(zhí)行 Job。
CronJob支持時區(qū)設(shè)置,默認為本地時區(qū)。
修改CronJob只對后續(xù)創(chuàng)建的Job有效。
并發(fā)調(diào)度策略支持三種:{"Allow":"允許并發(fā)","Forbid":"不允許","Replace":"調(diào)度覆蓋"},默認Allow。
建議設(shè)置spec.startingDeadlineSeconds,表示統(tǒng)計錯過調(diào)度次數(shù)的開始時間,默認從最后一次調(diào)度時間開始統(tǒng)計錯過調(diào)度次數(shù)(超過100不再調(diào)度)。
CronJob Spec中是jobTemplate,其他控制器都是template,且Job和CronJob控制器都無需定義Labels和Selector,控制器自動添加并確保匹配。