資源配額
當多個使用者或團隊共用節點數量固定的叢集時,會擔心一個團隊可能使用超過其公平份額的資源。
資源配額是管理員用來解決此問題的工具。
資源配額由 ResourceQuota
物件定義,提供約束來限制每個命名空間的彙總資源消耗。它可以限制命名空間中可依類型建立的物件數量,以及該命名空間中資源可能消耗的運算資源總量。
資源配額的運作方式如下
不同的團隊在不同的命名空間中工作。這可以使用 RBAC 來強制執行。
管理員為每個命名空間建立一個 ResourceQuota。
使用者在命名空間中建立資源 (Pod、服務等),配額系統會追蹤使用量,以確保其不超過 ResourceQuota 中定義的硬性資源限制。
如果建立或更新資源違反配額約束,則請求將失敗,並顯示 HTTP 狀態碼
403 FORBIDDEN
以及說明將會違反的約束的訊息。如果在命名空間中針對
cpu
和memory
等運算資源啟用配額,使用者必須為這些值指定請求或限制;否則,配額系統可能會拒絕 Pod 建立。提示:使用LimitRanger
許可控制器,針對未提出任何運算資源需求的 Pod 強制執行預設值。請參閱 逐步解說,以取得如何避免此問題的範例。
注意
- 針對
cpu
和memory
資源,ResourceQuotas 強制要求在該命名空間中的每個(新的)Pod 都必須為該資源設定限制。如果您在命名空間中針對cpu
或memory
資源強制執行資源配額,您和其他用戶端必須為您提交的每個新 Pod 指定該資源的requests
或limits
。如果您不這樣做,控制平面可能會拒絕該 Pod 的准入請求。 - 對於其他資源:ResourceQuota 運作時會忽略命名空間中未設定該資源的限制或請求的 Pod。這表示如果資源配額限制了此命名空間的臨時儲存空間,您可以建立一個新的 Pod,而無需設定臨時儲存空間的限制/請求。
您可以使用 LimitRange 來自動為這些資源設定預設請求。
ResourceQuota 物件的名稱必須是有效的 DNS 子網域名稱。
以下是可以使用命名空間和配額建立的策略範例
- 在一個容量為 32 GiB RAM 和 16 個核心的叢集中,讓團隊 A 使用 20 GiB 和 10 個核心,讓團隊 B 使用 10 GiB 和 4 個核心,並保留 2 GiB 和 2 個核心作為未來分配的預留空間。
- 限制 "testing" 命名空間使用 1 個核心和 1 GiB RAM。讓 "production" 命名空間使用任何數量。
如果叢集的總容量小於命名空間配額的總和,則可能會發生資源爭用。這將以先到先得的方式處理。
爭用或配額變更都不會影響已建立的資源。
啟用資源配額
許多 Kubernetes 發行版本預設啟用 ResourceQuota 支援。當 API 伺服器 的 --enable-admission-plugins=
標誌包含 ResourceQuota
作為其參數之一時,即會啟用。
當特定命名空間中存在 ResourceQuota 時,就會在該命名空間中強制執行資源配額。
計算資源配額
您可以限制在給定命名空間中可以請求的 計算資源總和。
支援以下資源類型
資源名稱 | 描述 |
---|---|
limits.cpu | 在所有非終止狀態的 Pod 中,CPU 限制的總和不能超過此值。 |
limits.memory | 在所有非終止狀態的 Pod 中,記憶體限制的總和不能超過此值。 |
requests.cpu | 在所有非終止狀態的 Pod 中,CPU 請求的總和不能超過此值。 |
requests.memory | 在所有非終止狀態的 Pod 中,記憶體請求的總和不能超過此值。 |
hugepages-<size> | 在所有非終止狀態的 Pod 中,指定大小的巨頁請求數量不能超過此值。 |
cpu | 與 requests.cpu 相同 |
memory | 與 requests.memory 相同 |
擴充資源的資源配額
除了上述資源外,在 1.10 版本中,還新增了對 擴充資源的配額支援。
由於擴充資源不允許超量配置 (overcommit),因此在配額中為同一個擴充資源同時指定 requests
和 limits
是沒有意義的。因此,對於擴充資源,只允許使用帶有 requests.
前綴的配額項目。
以 GPU 資源為例,如果資源名稱是 nvidia.com/gpu
,並且您想要將命名空間中請求的 GPU 總數限制為 4 個,您可以如下定義配額
requests.nvidia.com/gpu: 4
有關更多詳細資訊,請參閱 檢視和設定配額。
儲存資源配額
您可以限制在給定命名空間中可以請求的 儲存資源總和。
此外,您可以根據相關聯的 storage-class 限制儲存資源的消耗。
資源名稱 | 描述 |
---|---|
requests.storage | 在所有持久卷聲明中,儲存請求的總和不能超過此值。 |
persistentvolumeclaims | 可以在命名空間中存在的 PersistentVolumeClaims 總數。 |
<storage-class-name>.storageclass.storage.k8s.io/requests.storage | 在所有與 <storage-class-name> 相關聯的持久卷聲明中,儲存請求的總和不能超過此值。 |
<storage-class-name>.storageclass.storage.k8s.io/persistentvolumeclaims | 在所有與 <storage-class-name> 相關聯的持久卷聲明中,可以在命名空間中存在的 持久卷聲明 總數。 |
例如,如果您想要將使用 gold
StorageClass 的儲存空間與 bronze
StorageClass 的儲存空間分開配額,您可以如下定義配額
gold.storageclass.storage.k8s.io/requests.storage: 500Gi
bronze.storageclass.storage.k8s.io/requests.storage: 100Gi
在 1.8 版本中,本機臨時儲存空間的配額支援作為 alpha 功能新增。
資源名稱 | 描述 |
---|---|
requests.ephemeral-storage | 在命名空間中的所有 Pod 中,本機臨時儲存空間請求的總和不能超過此值。 |
limits.ephemeral-storage | 在命名空間中的所有 Pod 中,本機臨時儲存空間限制的總和不能超過此值。 |
ephemeral-storage | 與 requests.ephemeral-storage 相同。 |
注意
當使用 CRI 容器執行時期時,容器日誌將計入臨時儲存空間配額。這可能會導致已耗盡其儲存空間配額的 Pod 被意外驅逐。有關詳細資訊,請參閱 日誌架構。物件計數配額
您可以使用以下語法,在 Kubernetes API 中為*特定資源類型的總數*設定配額
count/<resource>.<group>
用於來自非核心群組的資源count/<resource>
用於來自核心群組的資源
以下是用戶可能希望置於物件計數配額下的資源範例集
count/persistentvolumeclaims
count/services
count/secrets
count/configmaps
count/replicationcontrollers
count/deployments.apps
count/replicasets.apps
count/statefulsets.apps
count/jobs.batch
count/cronjobs.batch
如果您以這種方式定義配額,它將適用於 Kubernetes API 伺服器的一部分 API,以及任何由 CustomResourceDefinition 支援的自訂資源。如果您使用 API 聚合 來新增未定義為 CustomResourceDefinition 的其他自訂 API,則核心 Kubernetes 控制平面不會對聚合 API 強制執行配額。擴充 API 伺服器應在自訂 API 適用時提供配額強制執行。例如,若要在 example.com
API 群組中的 widgets
自訂資源上建立配額,請使用 count/widgets.example.com
。
當使用此類資源配額(幾乎適用於所有物件類型)時,如果物件類型存在(已在控制平面中定義),則物件將計入配額。這些類型的配額可用於防止儲存資源耗盡。例如,您可能想要限制伺服器中 Secrets 的數量,因為它們的體積很大。叢集中過多的 Secrets 實際上可能會阻止伺服器和控制器啟動。您可以為 Jobs 設定配額,以防止配置不當的 CronJob。在命名空間中建立過多 Jobs 的 CronJob 可能會導致阻斷服務 (DoS)。
還有另一種語法僅用於為某些資源設定相同類型的配額。支援以下類型
資源名稱 | 描述 |
---|---|
configmaps | 可以在命名空間中存在的 ConfigMaps 總數。 |
persistentvolumeclaims | 可以在命名空間中存在的 PersistentVolumeClaims 總數。 |
pods | 可以在命名空間中存在的非終止狀態 Pod 的總數。如果 .status.phase in (Failed, Succeeded) 為 true,則 Pod 處於終止狀態。 |
replicationcontrollers | 可以在命名空間中存在的 ReplicationControllers 總數。 |
resourcequotas | 可以在命名空間中存在的 ResourceQuotas 總數。 |
services | 可以在命名空間中存在的 Services 總數。 |
services.loadbalancers | 可以在命名空間中存在的 LoadBalancer 類型 Services 的總數。 |
services.nodeports | 可以分配給 NodePort 或 LoadBalancer 類型 Services 的 NodePorts 總數,且這些 Services 可以在命名空間中存在。 |
secrets | 可以在命名空間中存在的 Secrets 總數。 |
例如,pods
配額會計數並強制限制在單個命名空間中建立的非終止 pods
數量上限。您可能需要在命名空間上設定 pods
配額,以避免使用者建立過多小型 Pod 並耗盡叢集 Pod IP 供應的情況。
您可以在 檢視和設定配額 中找到更多範例。
配額範圍
每個配額都可以有一組相關聯的 scopes
。只有當資源符合列舉範圍的交集時,配額才會衡量該資源的使用量。
當將範圍新增至配額時,它會將其支援的資源數量限制為與該範圍相關的資源。在配額上指定的資源如果超出允許的集合,將會導致驗證錯誤。
範圍 | 描述 |
---|---|
Terminating(終止中) | 匹配 .spec.activeDeadlineSeconds >= 0 的 Pod |
NotTerminating(非終止中) | 匹配 .spec.activeDeadlineSeconds 為 nil 的 Pod |
BestEffort(盡力而為) | 匹配具有盡力而為服務品質的 Pod。 |
NotBestEffort(非盡力而為) | 匹配不具有盡力而為服務品質的 Pod。 |
PriorityClass | 匹配參考指定 優先順序類別 的 Pod。 |
CrossNamespacePodAffinity(跨命名空間 Pod 親和性) | 匹配具有跨命名空間 Pod (反)親和性條款的 Pod。 |
BestEffort
範圍將配額限制為追蹤以下資源
pods
Terminating
、NotTerminating
、NotBestEffort
和 PriorityClass
範圍將配額限制為追蹤以下資源
pods
cpu
memory
requests.cpu
requests.memory
limits.cpu
limits.memory
請注意,您不能在同一個配額中同時指定 Terminating
和 NotTerminating
範圍,也不能在同一個配額中同時指定 BestEffort
和 NotBestEffort
範圍。
scopeSelector
在 operator
欄位中支援以下值
In(在其中)
NotIn(不在其中)
Exists(存在)
DoesNotExist(不存在)
當在定義 scopeSelector
時,使用以下其中一個值作為 scopeName
時,operator
必須是 Exists
。
Terminating(終止中)
NotTerminating(非終止中)
BestEffort(盡力而為)
NotBestEffort(非盡力而為)
如果 operator
是 In
或 NotIn
,則 values
欄位必須至少有一個值。例如
scopeSelector:
matchExpressions:
- scopeName: PriorityClass
operator: In
values:
- middle
如果 operator
是 Exists
或 DoesNotExist
,則 *不應* 指定 values
欄位。
每個 PriorityClass 的資源配額
Kubernetes v1.17 [穩定]
可以使用特定的 優先順序建立 Pod。您可以透過在配額規範中使用 scopeSelector
欄位,根據 Pod 的優先順序來控制 Pod 對系統資源的消耗。
只有當配額規範中的 scopeSelector
選取了 Pod 時,配額才會被匹配和消耗。
當使用 scopeSelector
欄位將配額範圍限定為優先順序類別時,配額物件會被限制為僅追蹤以下資源
pods
cpu
memory
ephemeral-storage
limits.cpu
limits.memory
limits.ephemeral-storage
requests.cpu
requests.memory
requests.ephemeral-storage
此範例建立了一個配額物件,並將其與具有特定優先順序的 Pod 進行匹配。範例運作方式如下
- 叢集中的 Pod 具有三個優先順序類別之一:「low」、「medium」、「high」。
- 為每個優先順序建立一個配額物件。
將以下 YAML 儲存到檔案 quota.yml
。
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-high
spec:
hard:
cpu: "1000"
memory: 200Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["high"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-medium
spec:
hard:
cpu: "10"
memory: 20Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["medium"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-low
spec:
hard:
cpu: "5"
memory: 10Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["low"]
使用 kubectl create
套用 YAML。
kubectl create -f ./quota.yml
resourcequota/pods-high created
resourcequota/pods-medium created
resourcequota/pods-low created
使用 kubectl describe quota
驗證 Used
配額為 0
。
kubectl describe quota
Name: pods-high
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 1k
memory 0 200Gi
pods 0 10
Name: pods-low
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 5
memory 0 10Gi
pods 0 10
Name: pods-medium
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 10
memory 0 20Gi
pods 0 10
建立一個優先順序為「high」的 Pod。將以下 YAML 儲存到檔案 high-priority-pod.yml
。
apiVersion: v1
kind: Pod
metadata:
name: high-priority
spec:
containers:
- name: high-priority
image: ubuntu
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello; sleep 10;done"]
resources:
requests:
memory: "10Gi"
cpu: "500m"
limits:
memory: "10Gi"
cpu: "500m"
priorityClassName: high
使用 kubectl create
套用它。
kubectl create -f ./high-priority-pod.yml
驗證「high」優先順序配額 pods-high
的「Used」統計資訊已變更,而其他兩個配額保持不變。
kubectl describe quota
Name: pods-high
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 500m 1k
memory 10Gi 200Gi
pods 1 10
Name: pods-low
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 5
memory 0 10Gi
pods 0 10
Name: pods-medium
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 10
memory 0 20Gi
pods 0 10
跨命名空間 Pod 親和性配額
Kubernetes v1.24 [穩定]
運算子可以使用 CrossNamespacePodAffinity
配額範圍來限制哪些命名空間允許擁有具有跨命名空間親和性條款的 Pod。具體來說,它控制哪些 Pod 允許在 Pod 親和性條款中設定 namespaces
或 namespaceSelector
欄位。
阻止使用者使用跨命名空間親和性條款可能是必要的,因為具有反親和性約束的 Pod 可能會阻止來自所有其他命名空間的 Pod 在故障域中進行排程。
透過使用此範圍,運算子可以透過在該命名空間中建立具有 CrossNamespacePodAffinity
範圍且硬性限制為 0 的資源配額物件,來防止某些命名空間(以下範例中的 foo-ns
)擁有使用跨命名空間 Pod 親和性的 Pod。
apiVersion: v1
kind: ResourceQuota
metadata:
name: disable-cross-namespace-affinity
namespace: foo-ns
spec:
hard:
pods: "0"
scopeSelector:
matchExpressions:
- scopeName: CrossNamespacePodAffinity
operator: Exists
如果運算子想要預設不允許使用 namespaces
和 namespaceSelector
,而僅允許特定命名空間使用,他們可以透過將 kube-apiserver 標誌 --admission-control-config-file
設定為以下組態檔案的路徑,將 CrossNamespacePodAffinity
配置為受限資源。
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: "ResourceQuota"
configuration:
apiVersion: apiserver.config.k8s.io/v1
kind: ResourceQuotaConfiguration
limitedResources:
- resource: pods
matchScopes:
- scopeName: CrossNamespacePodAffinity
operator: Exists
透過以上配置,Pod 只有在其建立所在的命名空間具有 CrossNamespacePodAffinity
範圍且硬性限制大於或等於使用這些欄位的 Pod 數量的資源配額物件時,才能在 Pod 親和性中使用 namespaces
和 namespaceSelector
。
請求與限制的比較
在分配計算資源時,每個容器可以為 CPU 或記憶體指定請求和限制值。配額可以配置為配額其中一個值。
如果配額為 requests.cpu
或 requests.memory
指定了值,則它要求每個傳入的容器都必須對這些資源提出明確的請求。如果配額為 limits.cpu
或 limits.memory
指定了值,則它要求每個傳入的容器都必須為這些資源指定明確的限制。
檢視和設定配額
kubectl 支援建立、更新和檢視配額
kubectl create namespace myspace
cat <<EOF > compute-resources.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
requests.nvidia.com/gpu: 4
EOF
kubectl create -f ./compute-resources.yaml --namespace=myspace
cat <<EOF > object-counts.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
configmaps: "10"
persistentvolumeclaims: "4"
pods: "4"
replicationcontrollers: "20"
secrets: "10"
services: "10"
services.loadbalancers: "2"
EOF
kubectl create -f ./object-counts.yaml --namespace=myspace
kubectl get quota --namespace=myspace
NAME AGE
compute-resources 30s
object-counts 32s
kubectl describe quota compute-resources --namespace=myspace
Name: compute-resources
Namespace: myspace
Resource Used Hard
-------- ---- ----
limits.cpu 0 2
limits.memory 0 2Gi
requests.cpu 0 1
requests.memory 0 1Gi
requests.nvidia.com/gpu 0 4
kubectl describe quota object-counts --namespace=myspace
Name: object-counts
Namespace: myspace
Resource Used Hard
-------- ---- ----
configmaps 0 10
persistentvolumeclaims 0 4
pods 0 4
replicationcontrollers 0 20
secrets 1 10
services 0 10
services.loadbalancers 0 2
kubectl 也支援使用 count/<resource>.<group>
語法,針對所有標準命名空間資源的物件計數配額。
kubectl create namespace myspace
kubectl create quota test --hard=count/deployments.apps=2,count/replicasets.apps=4,count/pods=3,count/secrets=4 --namespace=myspace
kubectl create deployment nginx --image=nginx --namespace=myspace --replicas=2
kubectl describe quota --namespace=myspace
Name: test
Namespace: myspace
Resource Used Hard
-------- ---- ----
count/deployments.apps 1 2
count/pods 2 3
count/replicasets.apps 1 4
count/secrets 1 4
配額和叢集容量
ResourceQuotas 與叢集容量無關。它們以絕對單位表示。因此,如果您向叢集新增節點,這*不會*自動讓每個命名空間都能夠消耗更多資源。
有時可能需要更複雜的策略,例如
- 在多個團隊之間按比例分配叢集總資源。
- 允許每個租戶根據需要增加資源使用量,但設定寬裕的限制以防止意外的資源耗盡。
- 偵測來自一個命名空間的需求,新增節點,並增加配額。
可以使用 ResourceQuotas
作為建構區塊來實作此類策略,方法是編寫一個「控制器」,該控制器監控配額使用情況,並根據其他訊號調整每個命名空間的配額硬性限制。
請注意,資源配額劃分了彙總的叢集資源,但它沒有對節點建立任何限制:來自多個命名空間的 Pod 可能會在同一個節點上執行。
預設限制 Priority Class 消耗量
可能會希望只有在存在匹配的配額物件時,才允許在命名空間中使用具有特定優先順序(例如「cluster-services」)的 Pod。
透過此機制,運算子可以限制特定高優先順序類別的使用範圍,使其僅限於少數命名空間,而非預設情況下每個命名空間都能取用這些優先順序類別。
為了強制執行此操作,應使用 kube-apiserver
旗標 --admission-control-config-file
傳遞至以下組態檔的路徑
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: "ResourceQuota"
configuration:
apiVersion: apiserver.config.k8s.io/v1
kind: ResourceQuotaConfiguration
limitedResources:
- resource: pods
matchScopes:
- scopeName: PriorityClass
operator: In
values: ["cluster-services"]
接著,在 kube-system
命名空間中建立資源配額物件
apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-cluster-services
spec:
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["cluster-services"]
kubectl apply -f https://k8s.io/examples/policy/priority-class-resourcequota.yaml -n kube-system
resourcequota/pods-cluster-services created
在此情況下,Pod 建立將在以下情況允許:
- 未指定 Pod 的
priorityClassName
。 - Pod 的
priorityClassName
指定為cluster-services
以外的值。 - Pod 的
priorityClassName
設定為cluster-services
,且將在kube-system
命名空間中建立,並已通過資源配額檢查。
若 Pod 建立請求的 priorityClassName
設定為 cluster-services
,且將在 kube-system
以外的命名空間中建立,則該請求會被拒絕。
下一步
- 請參閱 ResourceQuota 設計文件 以取得更多資訊。
- 請參閱 如何使用資源配額的詳細範例。
- 閱讀 優先順序類別設計文件的配額支援。
- 請參閱 LimitedResources。