K8s如何合理規定對象資源使用
基本概念
- Kubernetes中,占用資源的最小單元為
單個Pod
- Kubernetes中,資源占用主要針對服務器的
CPU
、內存
為什么要做資源限制
- 對于Kubernetes集群而言,所有Pod都會占用K8s集群所在服務器的資源,如果不做資源控制,則很有可能出現某些Pod無限制占用資源(CPU、內存),導致系統崩潰
資源限制設置方式
Pod、Container級別控制
關鍵參數:request、limits
-
request參數
- controller做調度時,創建Pod的最低資源占用標準
-
limits參數
- 單個Pod在運行時的資源占用上限 –
真正限制資源可用到多少
- 當容器試圖使用超過limits指定的CPU時會被 CFS 限流;試圖使用超過limits指定的內存時會被 OOM Killer 殺掉并重啟。
- 單個Pod在運行時的資源占用上限 –
使用示例
apiVersion: v1kind: Podmetadata:name: demo-podspec:containers:- name: appimage: nginx:latestresources: # k8s中定義資源規格的關鍵字,主要針對CPU和內存requests: # Pod最低的資源占用。調度器在將Pod指派給某個節點時,會檢查該節點“可分配資源”是否滿足request要求cpu: "100m" # 0.1 核memory: "128Mi" # 128 MBlimits: # Pod運行時的最大資源使用上限,cpu: "500m" # 0.5 核(上限)memory: "256Mi" # 256 MB(上限)
命名空間級別控制
關鍵策略對象:LimitRange
- 在命名空間級別,可以使用LimitRange給整個命名空間設置默認值/最大值
- LimitRange不僅僅是默認值的概念,也是一道硬性檢查
- 默認值:如果 Pod 或容器未顯式聲明 requests 或 limits,LimitRange 會自動注入默認值
- 硬性檢查:如果Pod或容器顯式聲明了request或者limits,但是不在 LimitRange的允許范圍內,不允許創建Pod
使用示例
apiVersion: v1
kind: LimitRange #LimitRange類型對象
metadata:name: cpu-mem-limit #LimitRange對象名稱namespace: dev #該策略適用的命名空間
spec: #定義策略具體規則limits: #limits為一個列表,可以包含多個限制策略- type: Container #表示該限制針對的是容器級別,而不是Pod或其他級別min: #指定容器資源的最小值,如果容器請求的資源低于這個值,K8s 會拒絕創建cpu: 100m #最少請求 0.1 個 CPU 核心memory: 128Mi #最少請求128M內存max: #超過這個值的容器會被拒絕創建cpu: 1 #最大請求1個CPU核心memory: 1Gi #最大請求1G內存default: #默認配置,當容器和Pod沒有顯式聲明resources.limits,自動使用這里配置的默認值cpu: 500m #當容器和Pod沒有顯式聲明resources.limits,默認resources.limits.cpu=500mmemory: 512Mi #當容器和Pod沒有顯式聲明resources.limits,默認resources.limits.memory=512Mi defaultRequest: #默認配置,當容器和Pod沒有顯式聲明resources.request,默認的requests數量,request: Pod最低的資源占用。調度器在將Pod指派給某個節點時,會檢查該節點“可分配資源”是否滿足request要求cpu: 200mmemory: 256MimaxLimitRequestRatio: #限制比例:限制與請求的最大比例,控制 limit/request 的最大比例。作用:防止用戶設置過高的 limit 而請求很低的資源,防止節點資源被過度使用或者其他Pod的資源無法保證cpu: 2 # CPU的限制值不能超過請求值的2倍。如果請求是250M內存,則限制不能超過500M。如果超過這個比例,Pod 會被拒絕創建
命名空間/集群級別總量限制
關鍵對象:ResourceQuota
- ResourceQuota是一種命名空間級別的硬限制機制,作用是給每個命名空間設定資源總量紅線
- 一旦配額用滿,任何導致超配的對象創建都會被拒絕,包括通過Deployment、StatefulSet等控制器間接創建的Pod
ResourceQuota作用范圍
- ResourceQuota控制的是集群節點級別的總量,還是命名空間的總量?
- ResourceQuota控制的是單個命名空間資源的總量
- 如果希望控制集群節點級別,需要多命名空間+ResourceQuota 或 集群級策略(如 ClusterPolicy、PodNodeSelector、多集群聯邦)來實現
ResourceQuota和LimitRange有什么區別
- ResourceQuota限制的是整個命名空間資源的總量
- LimitRange限制的是這個命名空間內,單個資源的限制量和默認值
- 兩者需要結合使用才能達到最佳效果
使用示例
- 確保準入控制器已啟用
- 大多數發行版默認已包含 --enable-admission-plugins=ResourceQuota;若手動搭建,需在 kube-apiserver 啟動參數里加入
- 編寫YML并應用
apiVersion: v1
kind: ResourceQuota #類型為ResourceQuota
metadata:name: team-a-quota #名稱namespace: team-a #作用的命名空間
spec:hard: #hard 是一個 map,key 是被限制的資源類型,value 是字符串形式的硬性上限requests.cpu: "20" #該命名空間內所有 非終止狀態 Pod 的 spec.containers[*].resources.requests.cpu 之和 ≤ 20 CPU(= 20 核)requests.memory: 40Gi #所有 Pod 的 requests.memory 總和 ≤ 40 GiBlimits.cpu: "40" #所有 Pod 的 limits.cpu 總和 ≤ 40 核limits.memory: 80Gi #所有 Pod 的 limits.memory 總和 ≤ 80 GiBpods: "50" #命名空間里當前存在的 Pod 對象數量 ≤ 50 個(Running / Pending / Succeeded 都算,Failed 或 Completed 且 TTL 已過的不算)persistentvolumeclaims: "10" #PVC 對象總數 ≤ 10 個count/deployments.apps: "15" #apps/v1 組下的 Deployment 對象 ≤ 15 個
- 查看配額使用/剩余
kubectl describe quota <ResourceQuota名稱> -n <命名空間>
引申問題1:LimitRange限制了容器最大使用資源,如果使用中超過這個限制,會發生什么
- 結論
- 最終表現是容器會被OOMKilled
- 原因
- LimitRange屬于準入控制,即在Pod創建/更新時作限制校驗,如果超出或低于限制要求,則不允許創建
- 當Pod創建完后,LimitRange任務結束,不再發揮作用
- 實際的運行時限制,是由cgroup 和 kubelet 負責,限制的方式也不是拒絕分配,而是直接殺掉
引申問題2:如果容器資源一旦超限就OOMKilled,如何保證應用穩定性?
- 預估
- 在配置上線前,充分壓測評估出最大峰值
- 給足安全余量,一般要在壓測峰值上再加20%-50%作為安全余量
- 觀察
- 上線后持續觀察,并設置預警措施
- 調優
- 發現不足就及時調大,并滾動升級
- 垂直擴容(加大limit限制值)
- 水平擴容(拆業務、分片、增加副本數,降低單實例負載)
- 應用層優化(減少緩存大小、調整GC參數、使用內存池、對象復用)**
- 兜底
- 保證即使有實例被OOMKilled,其余實例還可以承載流量
引申問題3:LimitRange 和 ResourceQuota 對已有 Pod 有什么影響
這是一個非常重要的問題,涉及 Kubernetes 中資源限制策略的生效范圍和時效性。
? 1. LimitRange 對已有 Pod 的影響
- 不會影響已存在的 Pod。
LimitRange
只在 新創建的 Pod 或容器 時生效。- 它的作用是在 Pod 創建時:
- 自動補全
resources.requests
和resources.limits
。 - 驗證資源是否在允許范圍內。
- 自動補全
🔍 如果已有 Pod 的資源配置超過了 LimitRange
的 max 限制:
- 不會強制修改或終止這些 Pod。
- 它們會繼續運行,直到被手動刪除或更新。
- 只有在重新創建或更新 Pod 時,才會觸發
LimitRange
的驗證。
? 2. ResourceQuota 對已有 Pod 的影響
- 不會強制終止或修改已存在的 Pod。
ResourceQuota
是針對命名空間資源總量的限制。- 它在創建新資源時檢查是否超過配額。
🔍 如果已有資源已經超過了配額限制:
- 不會影響這些資源的運行。
- 但無法再創建新的資源,直到資源使用量低于配額。
🧠 舉個例子
假設你在 dev
命名空間中設置了如下配額:
limits.cpu: "4"
而已有 Pod 總共使用了 5
個 CPU:
- ? 已有 Pod 不會被刪除或停止。
- ? 新 Pod 無法創建,除非已有 Pod 被刪除或資源使用量降低。
📌 總結
特性 | LimitRange | ResourceQuota |
---|---|---|
是否影響已有 Pod | ? 不影響 | ? 不影響 |
是否影響新建 Pod | ? 生效 | ? 生效 |
是否強制修改已有資源 | ? 不會 | ? 不會 |
是否阻止新資源創建 | ?(不符合規則) | ?(超出配額) |
? 建議做法
- 在設置
LimitRange
和ResourceQuota
前,先評估當前命名空間資源使用情況。 - 使用
kubectl describe quota
和kubectl top pod
查看資源使用。 - 如果想讓“老 Pod”也受新限制,只能人工或自動化地做:手動滾動重啟 Deployment/StatefulSet → 新 Pod 走新規則。
- 配合策略引擎(如 Kyverno)實現更強的資源治理。
注意事項
- LimitRange 和 ResourceQuota設置前,已有存在的pod,這部分Pod不會不受影響
- 一個命名空間建議只創建一個
- 多租戶集群,防止某個用戶的 Pod 占用過多資源
- CICD環境,限制測試 Pod 的最大資源,防止資源爭搶
- 為未聲明資源的容器自動分配合理默認值,避免調度失敗