资源配额

    资源配额是帮助管理员解决这一问题的工具。

    资源配额,通过 对象来定义,对每个命名空间的资源消耗总量提供限制。 它可以限制命名空间中某种类型的对象的总数目上限,也可以限制命令空间中的 Pod 可以使用的计算资源的总上限。

    资源配额的工作方式如下:

    • 不同的团队可以在不同的命名空间下工作,目前这是非约束性的,在未来的版本中可能会通过 ACL (Access Control List 访问控制列表) 来实现强制性约束。

    • 集群管理员可以为每个命名空间创建一个或多个 ResourceQuota 对象。

    • 当用户在命名空间下创建资源(如 Pod、Service 等)时,Kubernetes 的配额系统会 跟踪集群的资源使用情况,以确保使用的资源用量不超过 ResourceQuota 中定义的硬性资源限额。

    • 如果资源创建或者更新请求违反了配额约束,那么该请求会报错(HTTP 403 FORBIDDEN), 并在消息中给出有可能违反的约束。

    • 如果命名空间下的计算资源 (如 cpumemory)的配额被启用,则用户必须为 这些资源设定请求值(request)和约束值(limit),否则配额系统将拒绝 Pod 的创建。 提示: 可使用 LimitRanger 准入控制器来为没有设置计算资源需求的 Pod 设置默认值。

      若想避免这类问题,请参考 示例。

    ResourceQuota 对象的名称必须是合法的 DNS 子域名

    下面是使用命名空间和配额构建策略的示例:

    • 在具有 32 GiB 内存和 16 核 CPU 资源的集群中,允许 A 团队使用 20 GiB 内存 和 10 核的 CPU 资源, 允许 B 团队使用 10 GiB 内存和 4 核的 CPU 资源,并且预留 2 GiB 内存和 2 核的 CPU 资源供将来分配。
    • 限制 “testing” 命名空间使用 1 核 CPU 资源和 1GiB 内存。允许 “production” 命名空间使用任意数量。

    在集群容量小于各命名空间配额总和的情况下,可能存在资源竞争。资源竞争时,Kubernetes 系统会遵循先到先得的原则。

    不管是资源竞争还是配额的修改,都不会影响已经创建的资源使用对象。

    资源配额的支持在很多 Kubernetes 版本中是默认开启的。当 API 服务器的 --enable-admission-plugins= 参数中包含 ResourceQuota 时,资源配额会被启用。

    当命名空间中存在一个 ResourceQuota 对象时,对于该命名空间而言,资源配额就是开启的。

    计算资源配额

    用户可以对给定命名空间下的可被请求的 总量进行限制。

    配额机制所支持的资源类型:

    除上述资源外,在 Kubernetes 1.10 版本中,还添加了对 扩展资源 的支持。

    由于扩展资源不可超量分配,因此没有必要在配额中为同一扩展资源同时指定 requestslimits。 对于扩展资源而言,目前仅允许使用前缀为 requests. 的配额项。

    以 GPU 拓展资源为例,如果资源名称为 nvidia.com/gpu,并且要将命名空间中请求的 GPU 资源总数限制为 4,则可以如下定义配额:

    • requests.nvidia.com/gpu: 4

    有关更多详细信息,请参阅。

    存储资源配额

    此外,还可以根据相关的存储类(Storage Class)来限制存储资源的消耗。

    例如,如果一个操作人员针对 gold 存储类型与 bronze 存储类型设置配额, 操作人员可以定义如下配额:

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

    在 Kubernetes 1.8 版本中,本地临时存储的配额支持已经是 Alpha 功能:

    你可以使用以下语法对所有标准的、命名空间域的资源类型进行配额设置:

    • count/<resource>.<group>:用于非核心(core)组的资源
    • 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

    相同语法也可用于自定义资源。 例如,要对 example.com API 组中的自定义资源 widgets 设置配额,请使用 count/widgets.example.com

    当使用 count/* 资源配额时,如果对象存在于服务器存储中,则会根据配额管理资源。 这些类型的配额有助于防止存储资源耗尽。例如,用户可能想根据服务器的存储能力来对服务器中 Secret 的数量进行配额限制。 集群中存在过多的 Secret 实际上会导致服务器和控制器无法启动。 用户可以选择对 Job 进行配额管理,以防止配置不当的 CronJob 在某命名空间中创建太多 Job 而导致集群拒绝服务。

    对有限的一组资源上实施一般性的对象数量配额也是可能的。 此外,还可以进一步按资源的类型设置其配额。

    支持以下类型:

    例如,pods 配额统计某个命名空间中所创建的、非终止状态的 Pod 个数并确保其不超过某上限值。 用户可能希望在某命名空间中设置 pods 配额,以避免有用户创建很多小的 Pod, 从而耗尽集群所能提供的 Pod IP 地址。

    配额作用域

    每个配额都有一组相关的 scope(作用域),配额只会对作用域内的资源生效。 配额机制仅统计所列举的作用域的交集中的资源用量。

    当一个作用域被添加到配额中后,它会对作用域相关的资源数量作限制。 如配额中指定了允许(作用域)集合之外的资源,会导致验证错误。

    BestEffort 作用域限制配额跟踪以下资源:

    • pods

    TerminatingNotTerminatingNotBestEffortPriorityClass 这些作用域限制配额跟踪以下资源:

    • pods
    • cpu
    • memory
    • requests.cpu
    • requests.memory
    • limits.cpu
    • limits.memory

    需要注意的是,你不可以在同一个配额对象中同时设置 TerminatingNotTerminating 作用域,你也不可以在同一个配额中同时设置 BestEffortNotBestEffort 作用域。

    scopeSelector 支持在 operator 字段中使用以下值:

    • In
    • NotIn
    • Exists
    • DoesNotExist

    定义 scopeSelector 时,如果使用以下值之一作为 scopeName 的值,则对应的 operator 只能是 Exists

    • Terminating
    • NotTerminating
    • BestEffort
    • NotBestEffort

    如果 operator 是 或 NotIn 之一,则 values 字段必须至少包含一个值。 例如:

    如果 operatorExistsDoesNotExist,则可以设置 values 字段。

    基于优先级类(PriorityClass)来设置资源配额

    FEATURE STATE: Kubernetes v1.17 [stable]

    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 中。

    1. apiVersion: v1
    2. kind: List
    3. items:
    4. - apiVersion: v1
    5. kind: ResourceQuota
    6. metadata:
    7. name: pods-high
    8. spec:
    9. hard:
    10. cpu: "1000"
    11. memory: 200Gi
    12. pods: "10"
    13. scopeSelector:
    14. matchExpressions:
    15. - operator : In
    16. scopeName: PriorityClass
    17. - apiVersion: v1
    18. kind: ResourceQuota
    19. metadata:
    20. name: pods-medium
    21. spec:
    22. hard:
    23. cpu: "10"
    24. memory: 20Gi
    25. pods: "10"
    26. scopeSelector:
    27. matchExpressions:
    28. - operator : In
    29. scopeName: PriorityClass
    30. values: ["medium"]
    31. - apiVersion: v1
    32. kind: ResourceQuota
    33. metadata:
    34. name: pods-low
    35. spec:
    36. hard:
    37. cpu: "5"
    38. memory: 10Gi
    39. pods: "10"
    40. scopeSelector:
    41. matchExpressions:
    42. - operator : In
    43. scopeName: PriorityClass
    44. values: ["low"]

    使用 kubectl create 命令运行以下操作。

    1. kubectl create -f ./quota.yml
    1. resourcequota/pods-high created
    2. resourcequota/pods-medium created
    3. resourcequota/pods-low created

    使用 kubectl describe quota 操作验证配额的 Used 值为 0

    1. kubectl describe quota
    1. Name: pods-high
    2. Namespace: default
    3. Resource Used Hard
    4. -------- ---- ----
    5. cpu 0 1k
    6. memory 0 200Gi
    7. pods 0 10
    8. Name: pods-low
    9. Namespace: default
    10. Resource Used Hard
    11. -------- ---- ----
    12. cpu 0 5
    13. memory 0 10Gi
    14. pods 0 10
    15. Name: pods-medium
    16. Namespace: default
    17. Resource Used Hard
    18. -------- ---- ----
    19. cpu 0 10
    20. memory 0 20Gi
    21. pods 0 10

    创建优先级为 “high” 的 Pod。 将以下 YAML 保存到文件 high-priority-pod.yml 中。

    1. kind: Pod
    2. metadata:
    3. name: high-priority
    4. spec:
    5. containers:
    6. - name: high-priority
    7. image: ubuntu
    8. command: ["/bin/sh"]
    9. args: ["-c", "while true; do echo hello; sleep 10;done"]
    10. resources:
    11. requests:
    12. memory: "10Gi"
    13. cpu: "500m"
    14. limits:
    15. memory: "10Gi"
    16. cpu: "500m"
    17. priorityClassName: high

    使用 kubectl create 运行以下操作。

    1. kubectl create -f ./high-priority-pod.yml

    确认 “high” 优先级配额 pods-high 的 “Used” 统计信息已更改,并且其他两个配额未更改。

    1. kubectl describe quota

    请求与限制

    分配计算资源时,每个容器可以为 CPU 或内存指定请求和约束。 配额可以针对二者之一进行设置。

    如果配额中指定了 requests.cpurequests.memory 的值,则它要求每个容器都显式给出对这些资源的请求。 同理,如果配额中指定了 limits.cpulimits.memory 的值,那么它要求每个容器都显式设定对应资源的限制。

    Kubectl 支持创建、更新和查看配额:

      1. cat <<EOF > compute-resources.yaml
      2. apiVersion: v1
      3. kind: ResourceQuota
      4. metadata:
      5. name: compute-resources
      6. spec:
      7. hard:
      8. requests.cpu: "1"
      9. requests.memory: 1Gi
      10. limits.cpu: "2"
      11. limits.memory: 2Gi
      12. requests.nvidia.com/gpu: 4
      13. EOF
      1. kubectl create -f ./compute-resources.yaml --namespace=myspace
      1. cat <<EOF > object-counts.yaml
      2. apiVersion: v1
      3. kind: ResourceQuota
      4. metadata:
      5. name: object-counts
      6. spec:
      7. hard:
      8. configmaps: "10"
      9. persistentvolumeclaims: "4"
      10. pods: "4"
      11. replicationcontrollers: "20"
      12. secrets: "10"
      13. services: "10"
      14. services.loadbalancers: "2"
      15. EOF
      1. kubectl create -f ./object-counts.yaml --namespace=myspace
      1. kubectl get quota --namespace=myspace
      1. NAME AGE
      2. compute-resources 30s
      3. object-counts 32s
      1. kubectl describe quota compute-resources --namespace=myspace
      1. kubectl describe quota object-counts --namespace=myspace
      1. Name: object-counts
      2. Namespace: myspace
      3. Resource Used Hard
      4. -------- ---- ----
      5. configmaps 0 10
      6. persistentvolumeclaims 0 4
      7. pods 0 4
      8. replicationcontrollers 0 20
      9. secrets 1 10
      10. services 0 10
      11. services.loadbalancers 0 2

      kubectl 还使用语法 count/<resource>.<group> 支持所有标准的、命名空间域的资源的对象计数配额:

      1. kubectl create namespace myspace
      1. kubectl create quota test --hard=count/deployments.apps=2,count/replicasets.apps=4,count/pods=3,count/secrets=4 --namespace=myspace
      1. kubectl create deployment nginx --image=nginx --namespace=myspace --replicas=2
      1. kubectl describe quota --namespace=myspace
      1. Name: test
      2. Namespace: myspace
      3. Resource Used Hard
      4. -------- ---- ----
      5. count/deployments.apps 1 2
      6. count/pods 2 3
      7. count/replicasets.apps 1 4
      8. count/secrets 1 4

      配额和集群容量

      ResourceQuota 与集群资源总量是完全独立的。它们通过绝对的单位来配置。 所以,为集群添加节点时,资源配额不会自动赋予每个命名空间消耗更多资源的能力。

      有时可能需要资源配额支持更复杂的策略,比如:

      • 在几个团队中按比例划分总的集群资源。
      • 允许每个租户根据需要增加资源使用量,但要有足够的限制以防止资源意外耗尽。
      • 探测某个命名空间的需求,添加物理节点并扩大资源配额值。

      这些策略可以通过将资源配额作为一个组成模块、手动编写一个控制器来监控资源使用情况, 并结合其他信号调整命名空间上的硬性资源配额来实现。

      注意:资源配额对集群资源总体进行划分,但它对节点没有限制:来自不同命名空间的 Pod 可能在同一节点上运行。

      默认情况下限制特定优先级的资源消耗

      有时候可能希望当且仅当某名字空间中存在匹配的配额对象时,才可以创建特定优先级 (例如 “cluster-services”)的 Pod。

      通过这种机制,操作人员能够将限制某些高优先级类仅出现在有限数量的命名空间中, 而并非每个命名空间默认情况下都能够使用这些优先级类。

      要实现此目的,应设置 kube-apiserver 的标志 --admission-control-config-file 指向如下配置文件:

      1. apiVersion: apiserver.config.k8s.io/v1
      2. kind: AdmissionConfiguration
      3. plugins:
      4. - name: "ResourceQuota"
      5. configuration:
      6. apiVersion: apiserver.config.k8s.io/v1
      7. kind: ResourceQuotaConfiguration
      8. limitedResources:
      9. - resource: pods
      10. matchScopes:
      11. - scopeName: PriorityClass
      12. operator: In
      13. values: ["cluster-services"]

      现在,仅当命名空间中存在匹配的 scopeSelector 的配额对象时,才允许使用 “cluster-services” Pod。

      示例: