Kubernetes 資源配額

2022-05-23 14:03 更新

資源配額

當多個用戶或團隊共享具有固定節(jié)點數(shù)目的集群時,人們會擔心有人使用超過其基于公平原則所分配到的資源量。

資源配額是幫助管理員解決這一問題的工具。

資源配額,通過 ?ResourceQuota ?對象來定義,對每個命名空間的資源消耗總量提供限制。 它可以限制命名空間中某種類型的對象的總數(shù)目上限,也可以限制命令空間中的 Pod 可以使用的計算資源的總上限。

資源配額的工作方式如下:

  • 不同的團隊可以在不同的命名空間下工作,目前這是非約束性的,在未來的版本中可能會通過 ACL (Access Control List 訪問控制列表) 來實現(xiàn)強制性約束。
  • 集群管理員可以為每個命名空間創(chuàng)建一個或多個 ResourceQuota 對象。
  • 當用戶在命名空間下創(chuàng)建資源(如 Pod、Service 等)時,Kubernetes 的配額系統(tǒng)會 跟蹤集群的資源使用情況,以確保使用的資源用量不超過 ResourceQuota 中定義的硬性資源限額。
  • 如果資源創(chuàng)建或者更新請求違反了配額約束,那么該請求會報錯(HTTP 403 FORBIDDEN), 并在消息中給出有可能違反的約束。
  • 如果命名空間下的計算資源 (如 ?cpu ?和 ?memory?)的配額被啟用,則用戶必須為 這些資源設定請求值(request)和約束值(limit),否則配額系統(tǒng)將拒絕 Pod 的創(chuàng)建。 提示: 可使用 ?LimitRanger ?準入控制器來為沒有設置計算資源需求的 Pod 設置默認值。

ResourceQuota 對象的名稱必須是合法的 DNS 子域名。

下面是使用命名空間和配額構(gòu)建策略的示例:

  • 在具有 32 GiB 內(nèi)存和 16 核 CPU 資源的集群中,允許 A 團隊使用 20 GiB 內(nèi)存 和 10 核的 CPU 資源, 允許 B 團隊使用 10 GiB 內(nèi)存和 4 核的 CPU 資源,并且預留 2 GiB 內(nèi)存和 2 核的 CPU 資源供將來分配。
  • 限制 "testing" 命名空間使用 1 核 CPU 資源和 1GiB 內(nèi)存。允許 "production" 命名空間使用任意數(shù)量。

在集群容量小于各命名空間配額總和的情況下,可能存在資源競爭。資源競爭時,Kubernetes 系統(tǒng)會遵循先到先得的原則。

不管是資源競爭還是配額的修改,都不會影響已經(jīng)創(chuàng)建的資源使用對象。

啟用資源配額

資源配額的支持在很多 Kubernetes 版本中是默認啟用的。 當 API 服務器 的命令行標志 ?--enable-admission-plugins=? 中包含 ?ResourceQuota ?時, 資源配額會被啟用。

當命名空間中存在一個 ResourceQuota 對象時,對于該命名空間而言,資源配額就是開啟的。

計算資源配額

用戶可以對給定命名空間下的可被請求的 計算資源 總量進行限制。

配額機制所支持的資源類型:

資源名稱 描述
limits.cpu 所有非終止狀態(tài)的 Pod,其 CPU 限額總量不能超過該值。
limits.memory 所有非終止狀態(tài)的 Pod,其內(nèi)存限額總量不能超過該值。
requests.cpu 所有非終止狀態(tài)的 Pod,其 CPU 需求總量不能超過該值。
requests.memory 所有非終止狀態(tài)的 Pod,其內(nèi)存需求總量不能超過該值。
hugepages-<size> 對于所有非終止狀態(tài)的 Pod,針對指定尺寸的巨頁請求總數(shù)不能超過此值。
cpu 與 requests.cpu 相同。
memory 與 requests.memory 相同。

擴展資源的資源配額

除上述資源外,在 Kubernetes 1.10 版本中,還添加了對 擴展資源 的支持。

由于擴展資源不可超量分配,因此沒有必要在配額中為同一擴展資源同時指定 ?requests ?和 ?limits?。 對于擴展資源而言,目前僅允許使用前綴為 ?requests.? 的配額項。

以 GPU 拓展資源為例,如果資源名稱為 ?nvidia.com/gpu?,并且要將命名空間中請求的 GPU 資源總數(shù)限制為 4,則可以如下定義配額:

  • ?requests.nvidia.com/gpu: 4 ?

存儲資源配額

用戶可以對給定命名空間下的存儲資源 總量進行限制。

此外,還可以根據(jù)相關(guān)的存儲類(Storage Class)來限制存儲資源的消耗。

資源名稱 描述
requests.storage 所有 PVC,存儲資源的需求總量不能超過該值。
persistentvolumeclaims 在該命名空間中所允許的 PVC 總量。
<storage-class-name>.storageclass.storage.k8s.io/requests.storage 在所有與 <storage-class-name> 相關(guān)的持久卷申領中,存儲請求的總和不能超過該值。
<storage-class-name>.storageclass.storage.k8s.io/persistentvolumeclaims 在與 storage-class-name 相關(guān)的所有持久卷申領中,命名空間中可以存在的持久卷申領總數(shù)。

例如,如果一個操作人員針對 ?gold ?存儲類型與 ?bronze ?存儲類型設置配額, 操作人員可以定義如下配額:

  • ?gold.storageclass.storage.k8s.io/requests.storage: 500Gi ?
  • ?bronze.storageclass.storage.k8s.io/requests.storage: 100Gi?

在 Kubernetes 1.8 版本中,本地臨時存儲的配額支持已經(jīng)是 Alpha 功能:

資源名稱 描述
requests.ephemeral-storage 在命名空間的所有 Pod 中,本地臨時存儲請求的總和不能超過此值。
limits.ephemeral-storage 在命名空間的所有 Pod 中,本地臨時存儲限制值的總和不能超過此值。
ephemeral-storage 與 requests.ephemeral-storage 相同。
Note:
如果所使用的是 CRI 容器運行時,容器日志會被計入臨時存儲配額。 這可能會導致存儲配額耗盡的 Pods 被意外地驅(qū)逐出節(jié)點。

對象數(shù)量配額

你可以使用以下語法對所有標準的、命名空間域的資源類型進行配額設置:

  • ?count/<resource>.<group>?:用于非核心(core)組的資源
  • ?count/<resource>?:用于核心組的資源

這是用戶可能希望利用對象計數(shù)配額來管理的一組資源示例。

  • ?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?

相同語法也可用于自定義資源。 例如,要對 ?example.com? API 組中的自定義資源 ?widgets ?設置配額,請使用 ?count/widgets.example.com?。

當使用 ?count/*? 資源配額時,如果對象存在于服務器存儲中,則會根據(jù)配額管理資源。 這些類型的配額有助于防止存儲資源耗盡。例如,用戶可能想根據(jù)服務器的存儲能力來對服務器中 Secret 的數(shù)量進行配額限制。 集群中存在過多的 Secret 實際上會導致服務器和控制器無法啟動。 用戶可以選擇對 Job 進行配額管理,以防止配置不當?shù)?nbsp;CronJob 在某命名空間中創(chuàng)建太多 Job 而導致集群拒絕服務。

對有限的一組資源上實施一般性的對象數(shù)量配額也是可能的。 此外,還可以進一步按資源的類型設置其配額。

支持以下類型:

資源名稱 描述
configmaps 在該命名空間中允許存在的 ConfigMap 總數(shù)上限。
persistentvolumeclaims 在該命名空間中允許存在的 PVC 的總數(shù)上限。
pods 在該命名空間中允許存在的非終止狀態(tài)的 Pod 總數(shù)上限。Pod 終止狀態(tài)等價于 Pod 的 .status.phase in (Failed, Succeeded) 為真。
replicationcontrollers 在該命名空間中允許存在的 ReplicationController 總數(shù)上限。
resourcequotas 在該命名空間中允許存在的 ResourceQuota 總數(shù)上限。
services 在該命名空間中允許存在的 Service 總數(shù)上限。
services.loadbalancers 在該命名空間中允許存在的 LoadBalancer 類型的 Service 總數(shù)上限。
services.nodeports 在該命名空間中允許存在的 NodePort 類型的 Service 總數(shù)上限。
secrets 在該命名空間中允許存在的 Secret 總數(shù)上限。

例如,?pods ?配額統(tǒng)計某個命名空間中所創(chuàng)建的、非終止狀態(tài)的 ?Pod ?個數(shù)并確保其不超過某上限值。 用戶可能希望在某命名空間中設置 ?pods ?配額,以避免有用戶創(chuàng)建很多小的 Pod, 從而耗盡集群所能提供的 Pod IP 地址。

配額作用域 

每個配額都有一組相關(guān)的 ?scope?(作用域),配額只會對作用域內(nèi)的資源生效。 配額機制僅統(tǒng)計所列舉的作用域的交集中的資源用量。

當一個作用域被添加到配額中后,它會對作用域相關(guān)的資源數(shù)量作限制。 如配額中指定了允許(作用域)集合之外的資源,會導致驗證錯誤。

作用域 描述
Terminating 匹配所有 spec.activeDeadlineSeconds 不小于 0 的 Pod。
NotTerminating 匹配所有 spec.activeDeadlineSeconds 是 nil 的 Pod。
BestEffort 匹配所有 Qos 是 BestEffort 的 Pod。
NotBestEffort 匹配所有 Qos 不是 BestEffort 的 Pod。
PriorityClass 匹配所有引用了所指定的優(yōu)先級類的 Pods。
CrossNamespacePodAffinity 匹配那些設置了跨名字空間 (反)親和性條件的 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 ?字段。

基于優(yōu)先級類(PriorityClass)來設置資源配額

FEATURE STATE: Kubernetes v1.17 [stable]

Pod 可以創(chuàng)建為特定的優(yōu)先級。 通過使用配額規(guī)約中的 ?scopeSelector ?字段,用戶可以根據(jù) Pod 的優(yōu)先級控制其系統(tǒng)資源消耗。

僅當配額規(guī)范中的 ?scopeSelector ?字段選擇到某 Pod 時,配額機制才會匹配和計量 Pod 的資源消耗。

如果配額對象通過 ?scopeSelector ?字段設置其作用域為優(yōu)先級類,則配額對象只能 跟蹤以下資源:

  • ?pods ?
  • ?cpu ?
  • ?memory ?
  • ?ephemeral-storage ?
  • ?limits.cpu ?
  • ?limits.memory ?
  • ?limits.ephemeral-storage ?
  • ?requests.cpu ?
  • ?requests.memory ?
  • ?requests.ephemeral-storage?

本示例創(chuàng)建一個配額對象,并將其與具有特定優(yōu)先級的 Pod 進行匹配。 該示例的工作方式如下:

  • 集群中的 Pod 可取三個優(yōu)先級類之一,即 "low"、"medium"、"high"。
  • 為每個優(yōu)先級創(chuàng)建一個配額對象。

將以下 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? 命令運行以下操作。

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

創(chuàng)建優(yōu)先級為 "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" 優(yōu)先級配額 ?pods-high? 的 "Used" 統(tǒng)計信息已更改,并且其他兩個配額未更改。

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 親和性配額 

FEATURE STATE: Kubernetes v1.24 [stable]

集群運維人員可以使用 ?CrossNamespacePodAffinity ?配額作用域來 限制哪個名字空間中可以存在包含跨名字空間親和性規(guī)則的 Pod。 更為具體一點,此作用域用來配置哪些 Pod 可以在其 Pod 親和性規(guī)則 中設置 ?namespaces ?或 ?namespaceSelector ?字段。

禁止用戶使用跨名字空間的親和性規(guī)則可能是一種被需要的能力,因為帶有 反親和性約束的 Pod 可能會阻止所有其他名字空間的 Pod 被調(diào)度到某失效域中。

使用此作用域操作符可以避免某些名字空間(例如下面例子中的 ?foo-ns?)運行 特別的 Pod,這類 Pod 使用跨名字空間的 Pod 親和性約束,在該名字空間中創(chuàng)建 了作用域為 ?CrossNamespaceAffinity ?的、硬性約束為 0 的資源配額對象。

apiVersion: v1
kind: ResourceQuota
metadata:
  name: disable-cross-namespace-affinity
  namespace: foo-ns
spec:
  hard:
    pods: "0"
  scopeSelector:
    matchExpressions:
    - scopeName: CrossNamespaceAffinity

如果集群運維人員希望默認禁止使用 ?namespaces ?和 ?namespaceSelector?,而 僅僅允許在特定名字空間中這樣做,他們可以將 ?CrossNamespaceAffinity ?作為一個 被約束的資源。方法是為 ?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: CrossNamespaceAffinity

基于上面的配置,只有名字空間中包含作用域為 ?CrossNamespaceAffinity ?且 硬性約束大于或等于使用 ?namespaces ?和 ?namespaceSelector ?字段的 Pods 個數(shù)時,才可以在該名字空間中繼續(xù)創(chuàng)建在其 Pod 親和性規(guī)則中設置 ?namespaces ?或 ?namespaceSelector ?的新 Pod。

請求與限制的比較 

分配計算資源時,每個容器可以為 CPU 或內(nèi)存指定請求和約束。 配額可以針對二者之一進行設置。

如果配額中指定了 ?requests.cpu? 或 ?requests.memory? 的值,則它要求每個容器都顯式給出對這些資源的請求。 同理,如果配額中指定了 ?limits.cpu? 或 ?limits.memory? 的值,那么它要求每個容器都顯式設定對應資源的限制。

查看和設置配額

Kubectl 支持創(chuàng)建、更新和查看配額:

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>? 支持所有標準的、命名空間域的資源的對象計數(shù)配額:

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

配額和集群容量 

ResourceQuota 與集群資源總量是完全獨立的。它們通過絕對的單位來配置。 所以,為集群添加節(jié)點時,資源配額不會自動賦予每個命名空間消耗更多資源的能力。

有時可能需要資源配額支持更復雜的策略,比如:

  • 在幾個團隊中按比例劃分總的集群資源。
  • 允許每個租戶根據(jù)需要增加資源使用量,但要有足夠的限制以防止資源意外耗盡。
  • 探測某個命名空間的需求,添加物理節(jié)點并擴大資源配額值。

這些策略可以通過將資源配額作為一個組成模塊、手動編寫一個控制器來監(jiān)控資源使用情況, 并結(jié)合其他信號調(diào)整命名空間上的硬性資源配額來實現(xiàn)。

注意:資源配額對集群資源總體進行劃分,但它對節(jié)點沒有限制:來自不同命名空間的 Pod 可能在同一節(jié)點上運行。

默認情況下限制特定優(yōu)先級的資源消耗

有時候可能希望當且僅當某名字空間中存在匹配的配額對象時,才可以創(chuàng)建特定優(yōu)先級 (例如 "cluster-services")的 Pod。

通過這種機制,操作人員能夠?qū)⑾拗颇承└邇?yōu)先級類僅出現(xiàn)在有限數(shù)量的命名空間中, 而并非每個命名空間默認情況下都能夠使用這些優(yōu)先級類。

要實現(xiàn)此目的,應設置 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"]

現(xiàn)在在 ?kube-system? 名字空間中創(chuàng)建一個資源配額對象:

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

在這里,當以下條件滿足時可以創(chuàng)建 Pod:

  1. Pod 未設置 ?priorityClassName ?
  2. Pod 的 ?priorityClassName ?設置值不是 ?cluster-services ?
  3. Pod 的 ?priorityClassName ?設置值為 ?cluster-services?,它將被創(chuàng)建于 ?kube-system? 名字空間中,并且它已經(jīng)通過了資源配額檢查。

如果 Pod 的 ?priorityClassName ?設置為 ?cluster-services?,但要被創(chuàng)建到 ?kube-system? 之外的別的名字空間,則 Pod 創(chuàng)建請求也被拒絕。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號