
凌晨兩點(diǎn)線上某服務(wù)連著三次重啟kubectl get events里OOMKilled紅通通地躺著。第一反應(yīng)很直接把 memory 的 limit 從 512Mi 加到 1024Mi重新發(fā)布然后坐等。結(jié)果第二天凌晨同樣的時(shí)間點(diǎn)Evicted又來了。這類場景我見過太多次問題不在“l(fā)imit 不夠大”而在大家把 Pod 資源模型想成了一行數(shù)字但 K8S 里這套資源機(jī)制從調(diào)度器一路貫穿到內(nèi)核的 cgroup 和 OOM Killer每個(gè)字段管的是不同層的事。這篇內(nèi)容我就把 Pod 資源這條鏈路從頭到尾捋一遍把 requests、limits、QoS、驅(qū)逐排序這些概念串起來講適合正在被 Pod 無故被殺困擾、或者想把資源配到心里有數(shù)的人。1. 從Pod被殺現(xiàn)場說起資源這條隱形鏈路到底連著哪些內(nèi)核機(jī)制1.1 三種“死亡方式”的差異OOMKilled、Evicted 與啟動(dòng)即失敗很多人看到 Pod 狀態(tài)不對第一反應(yīng)都是“加內(nèi)存”。但 Pod 死法不一樣背后對應(yīng)的機(jī)制完全不同不先分清再動(dòng)手基本白改。OOMKilled是容器內(nèi)進(jìn)程觸發(fā)了內(nèi)核 OOM Killer。最常見的原因有兩個(gè)一是容器 cgroup 內(nèi)存上限設(shè)得太低進(jìn)程申請內(nèi)存時(shí)被內(nèi)核直接干掉二是整臺節(jié)點(diǎn)的物理內(nèi)存被耗盡內(nèi)核開始全局掃殺。兩者的共同點(diǎn)是動(dòng)手殺進(jìn)程的不是 Kubernetes而是操作系統(tǒng)內(nèi)核。Evicted則完全是另一回事它是 kubelet 主動(dòng)驅(qū)逐。kubelet 每隔一段時(shí)間檢查節(jié)點(diǎn)上的驅(qū)逐信號比如memory.available太低、nodefs.available太低、imagefs.available太低一旦越過閾值它會挑選一批 Pod 殺掉或標(biāo)記為失敗讓節(jié)點(diǎn)恢復(fù)穩(wěn)定。Event 里會寫The node was low on resource: memory或者disk。啟動(dòng)即失敗和上面兩種也不一樣。比如CreateContainerConfigError、CreateContainerError通常是鏡像拉取、存儲卷掛載、環(huán)境變量引用出了問題跟資源配額沒有直接關(guān)系但很多人排查時(shí)會把它們混在一起繞半天彎子。所以排查的第一步永遠(yuǎn)是先看 Event 和 Pod 的 Last State而不是憑“可能內(nèi)存不夠”就先把 limit 拉高。1.2 從YAML三行文字到內(nèi)核動(dòng)作一條完整的資源鏈路一個(gè)最普通的 Deployment 片段長這樣resources: requests: cpu: 200m memory: 256Mi limits: cpu: 500m memory: 512Mi這三行寫下去之后會依次走過這么一條鏈路API Server 持久化資源信息跟著 Pod 定義進(jìn)入 Etcd這只是個(gè)“聲明”沒有任何人執(zhí)行它。調(diào)度器記賬Scheduler 在 Filter 階段會看每個(gè)節(jié)點(diǎn)的Allocatable然后算出“所有已調(diào)度 Pod 的 requests 總和”加上新 Pod 的 requests不能超過節(jié)點(diǎn)剩余可分配量。注意它只看 requests完全不看 limits。kubelet 監(jiān)聽與創(chuàng)建Pod 被綁定到某節(jié)點(diǎn)后kubelet 從 API Server Watch 到變化調(diào)用容器運(yùn)行時(shí)創(chuàng)建容器。運(yùn)行時(shí)設(shè)置 cgroup容器運(yùn)行時(shí)比如 containerd在 cgroup 目錄里創(chuàng)建對應(yīng)的控制組并把 limits 數(shù)值寫進(jìn)內(nèi)核文件。CPU 對應(yīng)cpu.max或cpu.cfs_quota_us內(nèi)存對應(yīng)memory.max或memory.limit_in_bytes。內(nèi)核執(zhí)行限制進(jìn)程運(yùn)行后一旦 CPU 使用超過配額CFS 帶寬控制會強(qiáng)制“節(jié)流”內(nèi)存超過上限內(nèi)核就會回收頁面回收不動(dòng)就 OOM。kubelet 回收狀態(tài)容器被殺或驅(qū)逐后kubelet 更新 Pod 狀態(tài)Controller 決定是否重啟或重新調(diào)度。關(guān)鍵結(jié)論是requests 是調(diào)度器用來簽“工位合同”的limits 是內(nèi)核用來執(zhí)行“上限刑罰”的兩者根本不在同一層生效。這也是為什么很多人把 limit 調(diào)得再大調(diào)度問題依然解決不了。1.3 為什么“調(diào)大 limit”經(jīng)常解決不了問題結(jié)合上面的鏈路調(diào)大 limit 只在一種情況下有效容器確實(shí)是死在自己 cgroup 內(nèi)存上限太低導(dǎo)致的 OOM。但如果問題出在節(jié)點(diǎn)物理內(nèi)存被耗盡或者根本就是磁盤水位觸發(fā)了驅(qū)逐那你改 limit 等于改了個(gè)寂寞。還有個(gè)更容易忽略的場景內(nèi)存工作集逼近 limit 時(shí)內(nèi)核會頻繁回收 page cache容器響應(yīng)變慢但還沒死。你以為“還沒到 limit 所以沒問題”其實(shí)性能已經(jīng)劣化到閾值邊緣了。比較靠譜的排查順序是先kubectl describe pod xxx看 Last State 的 Exit Code 和 Message再翻節(jié)點(diǎn)監(jiān)控確認(rèn)當(dāng)時(shí)的內(nèi)存水位、磁盤水位和 cgroup 實(shí)際用量最后才決定是不是要改 resource 定義。這個(gè)順序看著簡單但真實(shí)環(huán)境里很多人是直接跳到最后一步的。2. requests和limits一個(gè)是工位合同一個(gè)是天花板限高2.1 request調(diào)度器簽工位合同的依據(jù)request 本質(zhì)上是在告訴調(diào)度器“我這個(gè) Pod 至少要占用這么多資源你把我放到節(jié)點(diǎn)上后這塊資源別人就不能用了?!?一個(gè)節(jié)點(diǎn)的可分配資源被所有 Pod 的 requests 總和瓜分不管這些 Pod 實(shí)際用沒用完。想象一個(gè)辦公室你給這個(gè)項(xiàng)目組劃了 10 個(gè)工位即使項(xiàng)目組只來了 3 個(gè)人剩下的 7 個(gè)工位也在合同期內(nèi)鎖著別的團(tuán)隊(duì)搬不進(jìn)來。Pod 的 request 就是這張工位合同。K8S 調(diào)度器按“工位數(shù)”不按 requests 總和來算剩余容量。所以在資源緊張的集群里把 request 調(diào)大會導(dǎo)致調(diào)度明顯變困難調(diào)小調(diào)度容易但節(jié)點(diǎn)超賣風(fēng)險(xiǎn)上升。很多人只關(guān)心 limit 夠不夠卻不知道真正卡調(diào)度的是 request。2.2 limitkubelet設(shè)置運(yùn)行上限的依據(jù)limit 是運(yùn)行時(shí)上限。kubelet 會要求容器運(yùn)行時(shí)把這個(gè)值寫進(jìn) cgroup內(nèi)核據(jù)此限制進(jìn)程使用。這跟調(diào)度器沒有一毛錢關(guān)系調(diào)度器在過濾節(jié)點(diǎn)時(shí)根本不看 limit。這意味著你完全可以把 request 設(shè)成 100mlimit 設(shè)成 8 核。調(diào)度器只會按 100m 幫你找位置但實(shí)際運(yùn)行時(shí)這個(gè)容器可以沖高到 8 核。這種配置是合法的也常用于“允許突發(fā)但保底調(diào)度”的場景但代價(jià)是節(jié)點(diǎn)可能被突發(fā)流量打穿。反過來你也不能把 limit 設(shè)成 100m 但 request 設(shè)成 2 核因?yàn)檎{(diào)度器會按 2 核記賬而內(nèi)核會把你限制在 100m等于白白浪費(fèi)調(diào)度配額。2.3 CPU可壓縮與內(nèi)存不可壓縮兩種limit的本質(zhì)差異CPU 和內(nèi)存的 limit 行為有著本質(zhì)區(qū)別維度CPU內(nèi)存資源性質(zhì)可壓縮不可壓縮超過 limit 時(shí)CPU 節(jié)流throttle進(jìn)程不停止觸發(fā)內(nèi)核 OOM進(jìn)程可能被殺死對同節(jié)點(diǎn)影響節(jié)流后讓出 CPU影響相對可控內(nèi)存耗盡可能拖垮整臺節(jié)點(diǎn)關(guān)鍵監(jiān)控指標(biāo)container_cpu_cfs_throttled_periodscontainer_memory_working_set_bytes拿生活場景類比CPU limit 像高速公路的限速牌超速不是扣車而是被慢悠悠地壓在限速上走內(nèi)存 limit 像一張信用卡的額度你刷爆了不是被警告而是直接被???。這條差異決定了配置策略上的大方向CPU 可以靠 introspection 和擴(kuò)容扛過去內(nèi)存問題則必須留足緩沖。CPU limit 設(shè)小了你最多看到容器變慢、耗時(shí)上升、被 throttled但它不會死內(nèi)存 limit 設(shè)小了那就是一場事故。所以要給內(nèi)存留的余量通常比 CPU 高一個(gè)量級。3. 調(diào)度器只讀request看清“看得見的賬”和“看不見的墻”3.1 節(jié)點(diǎn)到底有多少可分Allocatable、預(yù)留與驅(qū)逐閾值很多人的資源賬是這么算的節(jié)點(diǎn) 4 核 16G那我放 4 個(gè) 1 核 4G 的 Pod 總沒問題吧實(shí)際一調(diào)度就 Pending報(bào)錯(cuò)Insufficient cpu或Insufficient memory。原因是節(jié)點(diǎn)并不是所有 Capacity 都能分給 Pod。kubelet 在計(jì)算節(jié)點(diǎn)可分配資源時(shí)會扣掉兩塊系統(tǒng)預(yù)留通過--system-reserved和--kube-reserved指定給操作系統(tǒng)守護(hù)進(jìn)程、kubelet、容器運(yùn)行時(shí)預(yù)留的份額。驅(qū)逐閾值比如memory.available低于 100Mi 時(shí)觸發(fā)驅(qū)逐這部分空間也不能算作可分配。Allocatable Capacity - 系統(tǒng)預(yù)留 - 驅(qū)逐閾值。實(shí)際生產(chǎn)環(huán)境里很多人沒配置--system-reserved。這意味著 kubelet、containerd、sshd 這些進(jìn)程用的內(nèi)存沒有從任何 Pod 的 request 里扣除它們會和業(yè)務(wù) Pod 搶物理內(nèi)存。結(jié)果節(jié)點(diǎn)明明“還有空閑”卻提前進(jìn)入 MemoryPressure業(yè)務(wù) Pod 莫名被驅(qū)逐。這就是“看不見的墻”。3.2 明明節(jié)點(diǎn)很閑卻調(diào)度不上去碎片化的本質(zhì)另一種常見 Pending 是節(jié)點(diǎn) CPU 實(shí)際使用率才 20%但新 Pod 就是放不上去。這不是 Bug而是因?yàn)檎{(diào)度器記賬用的是 requests 總和不是實(shí)時(shí)用量。舉個(gè)直觀例子某節(jié)點(diǎn) 4 核上面跑著 4 個(gè) Pod每個(gè) requests 都是 900m實(shí)際用量都只有 100m。此時(shí)節(jié)點(diǎn)剩余 request 是 400m實(shí)際空閑卻接近 3.6 核。你想放一個(gè) requests 為 500m 的新 Pod調(diào)度器一看剩余 400m直接拒絕。這就像奶茶店收銀抽屜里全是零錢你要給一張 100 元整鈔店員就是找不開。每個(gè) Pod 的 request 都是預(yù)占用的“整鈔”哪怕它實(shí)際消費(fèi)很小別人也借不了這塊。要緩解碎片化我能給的思路有四條把長期穩(wěn)定服務(wù)的 request 調(diào)到貼近真實(shí)用量而不是拍腦袋寫大合理使用節(jié)點(diǎn)池讓規(guī)格差異不要過大用 PriorityClass 加搶占高優(yōu)先級 Pod 實(shí)在插不進(jìn)去時(shí)可以擠掉低優(yōu)先級 Pod接受一定程度的超賣但必須配合監(jiān)控和驅(qū)逐兜底。3.3 親和性、污點(diǎn)與拓?fù)浞植假Y源賬之外的隱藏成本還有一類 Pending連Insufficient cpu都不是而是調(diào)度器在別的維度上卡死。比如節(jié)點(diǎn)上有污點(diǎn)而 Pod 沒有對應(yīng)容忍Pod 帶了nodeAffinity把可選節(jié)點(diǎn)鎖死在一小撮機(jī)器上開了topologySpreadConstraints要求 Pod 必須打散到不同可用區(qū)或節(jié)點(diǎn)哪怕某個(gè)區(qū)資源明明更空。這些約束和資源是兩套獨(dú)立系統(tǒng)但常常疊加在一起。排障的時(shí)候如果只盯著資源很容易陷進(jìn)去。我一般先看kubectl describe pod里的 Events里面會明確寫“0/N nodes are available”以及具體原因是Insufficient cpu、node(s) didnt match node selector還是node(s) had untolerated taint。原因不一樣解法完全不同。4. 內(nèi)核如何執(zhí)行l(wèi)imit從CPU周期到OOM Killer的完整鏈路4.1 CFS帶寬控制100ms周期里的時(shí)間片游戲CPU 的 limit 不是“每秒只能用 0.5 秒”這么簡單。內(nèi)核的 CFS 帶寬控制把時(shí)間切成一段段的周期默認(rèn) 100ms再給每個(gè)容器分配一個(gè)配額。比如 limit 為 500m意味著在每個(gè) 100ms 周期里容器最多能占用 50ms 的 CPU 時(shí)間。如果容器在周期內(nèi)把配額用完內(nèi)核會把它“節(jié)流”到下一個(gè)周期。這相當(dāng)于一個(gè)閘機(jī)你不是被禁止前進(jìn)而是排隊(duì)到下一輪再走。對延遲敏感的服務(wù)來說節(jié)流直接表現(xiàn)為 P99 毛刺和超時(shí)但 CPU 使用率看起來又沒滿。判斷是否被節(jié)流監(jiān)控指標(biāo)要盯container_cpu_cfs_throttled_periods和container_cpu_cfs_throttled_periods / container_cpu_cfs_periods。如果節(jié)流比例長期高于 10%要么調(diào)高 CPU limit要么減少容器內(nèi)的線程競爭。一個(gè)容易踩的坑是Java 或 Go 這類運(yùn)行時(shí)內(nèi)部有多線程limit2 只是一個(gè)周期最多 200ms CPU 時(shí)間但它可以在 2 個(gè)核上同時(shí)跑滿 100ms。千萬別把進(jìn)程內(nèi)的線程數(shù)理解成“受 limit 保護(hù)”limit 只限制總量不限制并發(fā)形態(tài)。4.2 內(nèi)存cgroup上限與OOM評分內(nèi)存的 limit 寫在 cgroup 的memory.max里。內(nèi)核會持續(xù)監(jiān)控這個(gè) cgroup 的內(nèi)存使用當(dāng)接近上限時(shí)先嘗試回收 page cache 等可回收頁面回收完還不夠就觸發(fā) OOM Killer。OOM Killer 不是隨機(jī)殺它按照每個(gè)進(jìn)程的oom_score排序分高的先殺。這個(gè)分?jǐn)?shù)大致由進(jìn)程的物理內(nèi)存占用和 oom_score_adj 共同決定。容器里的 pid 1 如果吃內(nèi)存最狠通常它自己就是第一個(gè)犧牲品。對 Java 應(yīng)用來說這里有個(gè)典型悲劇老版本 JVM 不感知容器 cgroup limit默認(rèn)堆大小按物理機(jī)內(nèi)存來算結(jié)果堆一擴(kuò)立刻撞 limit進(jìn)程反復(fù)被殺。JDK 8u191 之后默認(rèn)開啟UseContainerSupport但如果你還在用老鏡像得顯式加-XX:MaxRAMPercentage75.0這類參數(shù)。排查內(nèi)存問題不要只看container_memory_usage_bytes更準(zhǔn)的是container_memory_working_set_bytes。它排除了可以被內(nèi)核回收的 page cache反映的是“真正臟著的、賴在內(nèi)存里不走的部分”。工作集貼著 limit 走才是崩潰的前兆。4.3 從網(wǎng)上抄limit值為什么容易翻車我在社區(qū)里見過太多“通用模板”什么“Java 服務(wù) memory limit 設(shè) 2G 準(zhǔn)沒錯(cuò)”“Go 服務(wù) requests 給 500m 就行”。這些數(shù)值對別人可能合理但換一個(gè)業(yè)務(wù)就完全不是一回事。舉個(gè)實(shí)際例子同樣是 Nginx 網(wǎng)關(guān)靜態(tài)文件緩存命中率高的工作集可能只有 100Mi但開啟了 Lua 腳本和復(fù)雜 access log 后工作集能沖到 500Mi。你照著網(wǎng)上模板寫 256Mi容器三天兩頭 OOM寫 4G又白白占著節(jié)點(diǎn)內(nèi)存調(diào)度器按 request 記賬后面全是資源浪費(fèi)。正確姿勢是結(jié)合第 6 節(jié)說的基線采集法拿自己業(yè)務(wù)的數(shù)據(jù)來定。別人的模板只能作為初始參考不能作為長期配置。5. QoS三兄弟與節(jié)點(diǎn)驅(qū)逐次序危機(jī)關(guān)頭的生存排序5.1 三檔QoS怎么判定只看request和limit的設(shè)定關(guān)系K8S 會根據(jù) Pod 里每個(gè)容器的 requests 和 limits 設(shè)定蓋一個(gè) QoS 章共三檔Guaranteed、Burstable、BestEffort。判定規(guī)則如下QoS 等級判定條件風(fēng)險(xiǎn)傾向Guaranteed每個(gè)容器都設(shè)置了 requests 和 limits且同一資源的二者相等被驅(qū)逐優(yōu)先級最低Burstable至少一個(gè)容器設(shè)置了 requests 或 limits但不滿足 Guaranteed 條件常見主形態(tài)超用風(fēng)險(xiǎn)中等BestEffort所有容器都沒有設(shè)置任何 requests 和 limits被驅(qū)逐優(yōu)先級最高注意這個(gè)判定是“每個(gè)容器”維度的。如果 Pod 里有一個(gè) Java 容器配了 Guaranteed另一個(gè) sidecar 只寫了 requests 沒寫 limits整個(gè) Pod 就會被降級成 Burstable。所以想拿 Guaranteed 的穩(wěn)定性所有容器都得嚴(yán)格配齊。QoS 最重要的意義是當(dāng)節(jié)點(diǎn)資源告急輪到 kubelet 決定“誰先走”的時(shí)候它是分檔排序的核心依據(jù)之一。但它只是排序規(guī)則并不保證 Guaranteed 就一定不死。5.2 驅(qū)逐流程先來后到但又不完全是kubelet 的驅(qū)逐不是簡單的 FIFO。實(shí)際排序邏輯大致是按 PriorityClass 排序優(yōu)先級低的先被驅(qū)逐優(yōu)先級相同時(shí)按 QoS 排序BestEffort 先于 BurstableGuaranteed 最后仍然相同時(shí)按 Pod 內(nèi)存使用量相對于 request 的超用比例排序超用比例大的先走。這個(gè)排序在 Eviction API 的代碼里有明確實(shí)現(xiàn)不是玄學(xué)。對你的啟示是核心在線服務(wù)Priority 和 QoS 都要拉滿做成 Guaranteed離線任務(wù)、Batch Job可以安心用 Burstable 或 BestEffort反正它優(yōu)先級低犧牲起來不心疼只是 QoS 高但 Priority 低在驅(qū)逐場景下依然可能先被殺。一個(gè)常被忽略的細(xì)節(jié)是Pod 被驅(qū)逐后狀態(tài)是FailedEvent 里寫Evicted。Pod 對象還在只是容器沒了配套的 PVC 可能還占著。做清理的時(shí)候別忘了kubectl delete pod把尸骨收走。5.3 Guaranteed不是免死金牌很多人以為 QoS 設(shè)成 Guaranteed、Priority 設(shè)高Pod 就安全了。這是認(rèn)知盲區(qū)。kubelet 驅(qū)逐確實(shí)會盡量不碰 Guaranteed但別忘了還有一個(gè)獨(dú)立于 kubelet 的“暴力部門”——內(nèi)核 OOM Killer。如果你的容器內(nèi)存工作集超過了 cgroup limit內(nèi)核會直接殺進(jìn)程這個(gè)時(shí)候 QoS 章一點(diǎn)用都沒有。QoS 管的是 kubelet 的驅(qū)逐順序OOM Killer 管的是內(nèi)核的內(nèi)存戰(zhàn)備線兩層機(jī)制完全平行。另外還有個(gè)場景整臺節(jié)點(diǎn)陷入 MemoryPressurekubelet 的硬驅(qū)逐閾值已經(jīng)觸發(fā)了但如果根因是節(jié)點(diǎn)上的系統(tǒng)進(jìn)程吃內(nèi)存就算你把所有業(yè)務(wù) Pod 都調(diào)成 Guaranteed該被殃及還是會被殃及。所以配好節(jié)點(diǎn)級--system-reserved、--kube-reserved比在 Pod 層面死磕 QoS 更治本。6. 從原理到策略一次靠譜的資源清單長什么樣6.1 基線采集三步法不看監(jiān)控改配置等于閉眼開車講了這么多原理最后落到實(shí)操。我自己的習(xí)慣是給任何一個(gè)服務(wù)寫 resource 之前先做三天到一周的“基線采集”。第一步部署監(jiān)控用 Prometheus 抓container_cpu_usage_seconds_total和container_memory_working_set_bytes。注意是 working set不是 raw usage。第二步統(tǒng)計(jì) P95 / P99。requests 建議取 P95 附近再乘 1.1~1.2 的保險(xiǎn)系數(shù)。為什么不用 P99因?yàn)?P99 往往被毛刺抬高翻倍配置會讓 request 虛高白白浪費(fèi)節(jié)點(diǎn)容量。如果一個(gè)服務(wù)的內(nèi)存工作集長期穩(wěn)定在 200Mi突然某天 2 分鐘沖到 400Mi那可能是 GC 或緩存填充把 limit 留在 512Mi 更合適而不是把 request 改成 400Mi。第三步定 limits。CPU limit 一般是 request 的 1.5~2 倍內(nèi)存 limit 是 request 的 1.5~2.5 倍具體看業(yè)務(wù)對延遲敏感度和緩存的突刺程度。拿不準(zhǔn)的時(shí)候?qū)幙上确艑?limit也不要放窄——內(nèi)存 limit 設(shè)小了是會出人命的CPU throttled 只是變慢而已。6.2 結(jié)合HPA/VPA的容量規(guī)劃requests不再是拍腦袋如果你的服務(wù)掛了 HPA那 requests 的準(zhǔn)確性就更加關(guān)鍵因?yàn)?HPA 的擴(kuò)縮容計(jì)算用的是CPU 當(dāng)前使用量 / request不是 limit。這句話翻譯一下如果 requests 設(shè)得過大HPA 永遠(yuǎn)算不出高利用率結(jié)果就是副本數(shù)漲不起來流量全壓在少數(shù)幾個(gè)實(shí)例上如果 requests 設(shè)得過小HPA 又會被輕微的 CPU 毛刺刺激得瘋狂擴(kuò)容Pod 數(shù)暴增但每個(gè) Pod 都在節(jié)流。VPA 能自動(dòng)推薦 requests但默認(rèn)只給建議不會改你 YAML。即便你開了 Auto 模式它調(diào)整 requests 時(shí)也需要重新創(chuàng)建 Pod對在線服務(wù)多少有影響。我的建議是把 VPA 當(dāng)“測量儀器”跑一段時(shí)間看它推薦的值跟你手工算的 P95 是否一致再決定要不要采納別一上來就全自動(dòng)。6.3 一套可直接套用的初始配置示例最后給一份模板適合中等規(guī)模的 web 服務(wù)你可以按自己采集到的基線調(diào)整apiVersion: apps/v1 kind: Deployment metadata: name: demo-web spec: replicas: 3 strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 0 template: spec: containers: - name: app image: demo:1.0.2 resources: requests: cpu: 200m memory: 256Mi limits: cpu: 500m memory: 512Mi這份配置的設(shè)計(jì)邏輯是CPU requests 200m 保證調(diào)度器給它一個(gè)穩(wěn)定的物理位置CPU limits 500m 給突發(fā)留了 2.5 倍空間避免節(jié)流嚴(yán)重內(nèi)存 requests 256Mi 貼近多數(shù) web 服務(wù)的空閑工作集內(nèi)存 limits 512Mi 就是為了給 GC 和高峰留緩沖。同時(shí)別忽略滾動(dòng)更新的資源疊加maxSurge: 1意味著發(fā)布瞬間集群里會有 4 個(gè)副本同時(shí)跑峰值容量大概是4 × 512Mi 2Gi。如果你按“3 副本剛好打滿節(jié)點(diǎn)”去規(guī)劃容量發(fā)布時(shí)就會因?yàn)橘Y源不夠而卡住滾動(dòng)更新。這是 Deployment 交付時(shí)最常見的隱性故障很多人沒把 Surge 算進(jìn)資源賬。我在實(shí)際配置中的體會是資源參數(shù)沒有“一勞永逸”業(yè)務(wù)流量和鏡像版本一變工作集就會跟著漂。最有效的做法是每個(gè)月回頭看一眼監(jiān)控問自己三個(gè)問題節(jié)流比例漲了嗎工作集離 limit 多遠(yuǎn)HPA 擴(kuò)容頻率正常嗎如果這三項(xiàng)里有兩項(xiàng)不對勁就該重新走一遍基線采集調(diào)整 resource 了。這才是讓資源模型長期健康運(yùn)轉(zhuǎn)的方式而不是每次出事都靠臨時(shí)加 limit 續(xù)命。