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