第 9 章 配额
9.1. 项目的资源配额
资源配额 由 ResourceQuota
对象定义,提供约束来限制各个项目的聚合资源消耗。它可根据类型限制项目中创建的对象数量,以及该项目中资源可以消耗的计算资源和存储的总和。
本指南阐述了资源配额如何工作,集群管理员如何以项目为基础设置和管理资源配额,以及开发人员和集群管理员如何查看配额。
9.1.1. 配额管理的资源
下方描述了可通过配额管理的一系列计算资源和对象类型。
如果 status.phase in (Failed, Succeeded)
为 true,则 Pod 处于终端状态。
资源名称 | 描述 |
---|---|
|
非终端状态的所有 Pod 的 CPU 请求总和不能超过这个值。 |
|
非终端状态的所有 Pod 的 内存请求总和不能超过这个值。 |
|
非终端状态的所有 Pod 的 CPU 请求总和不能超过这个值。 |
|
非终端状态的所有 Pod 的 内存请求总和不能超过这个值。 |
| 非终端状态的所有 Pod 的 CPU 限值总和不能超过这个值。 |
| 非终端状态的所有 Pod 的内存限值总和不能超过这个值。 |
资源名称 | 描述 |
---|---|
| 处于任何状态的所有持久性卷声明的存储请求总和不能超过这个值。 |
| 项目中可以存在的持久性卷声明的总数。 |
| 在处于任何状态且具有匹配存储类的所有持久性卷声明中,存储请求总和不能超过这个值。 |
| 项目中可以存在的具有匹配存储类的持久性卷声明的总数。 |
|
非终端状态的所有本地临时存储请求总和不能超过这个值。 |
|
非终端状态的所有临时存储请求总和不能超过这个值。 |
| 非终端状态的所有 Pod 的临时存储限值总和不能超过这个值。 |
资源名称 | 描述 |
---|---|
| 项目中可以存在的处于非终端状态的 Pod 总数。 |
| 项目中可以存在的 ReplicationController 的总数。 |
| 项目中可以存在的资源配额总数。 |
| 项目中可以存在的服务总数。 |
|
项目中可以存在的 |
|
项目中可以存在的 |
| 项目中可以存在的 secret 的总数。 |
|
项目中可以存在的 |
| 项目中可以存在的持久性卷声明的总数。 |
| 项目中可以存在的镜像流的总数。 |
9.1.2. 配额范围
每个配额都有一组关联的范围。配额只在与枚举的范围交集匹配时才会测量资源的使用量。
为配额添加范围会限制该配额可应用的资源集合。指定允许的集合之外的资源会导致验证错误。
影响范围 | 描述 |
|
匹配 |
|
匹配 |
BestEffort
范围将配额仅限为限制以下资源:
-
pods
NotBestEffort
范围限制配额跟踪以下资源:
-
pods
-
memory
-
requests.memory
-
limits.memory
-
cpu
-
requests.cpu
-
limits.cpu
9.1.3. 配额强制
在项目中首次创建资源配额后,项目会限制您创建可能会违反配额约束的新资源,直到它计算了更新后的使用量统计。
在创建了配额并且更新了使用量统计后,项目会接受创建新的内容。当您创建或修改资源时,配额使用量会在请求创建或修改资源时立即递增。
在您删除资源时,配额使用量在下一次完整重新计算项目的配额统计时才会递减。可配置的时间量决定了将配额使用量统计降低到其当前观察到的系统值所需的时间。
如果项目修改超过配额使用量限值,服务器会拒绝该操作,并将对应的错误消息返回给用户,解释违反了配额约束,并说明系统中目前观察到的使用量统计。
9.1.4. 请求与限值
在分配计算资源时,每个容器可能会为 CPU、内存和临时存储各自指定请求和限制值。配额可以限制任何这些值。
如果配额具有为 requests.cpu
或 requests.memory
指定的值,那么它要求每个传入的容器都明确请求那些资源。如果配额具有为 limits.cpu
或 limits.memory
指定的值,那么它要求每个传入的容器为那些资源指定一个显性限值。
9.1.5. 资源配额定义示例
core-object-counts.yaml
apiVersion: v1 kind: ResourceQuota metadata: name: core-object-counts spec: hard: configmaps: "10" 1 persistentvolumeclaims: "4" 2 replicationcontrollers: "20" 3 secrets: "10" 4 services: "10" 5 services.loadbalancers: "2" 6
openshift-object-counts.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: openshift-object-counts
spec:
hard:
openshift.io/imagestreams: "10" 1
- 1
- 项目中可以存在的镜像流的总数。
compute-resources.yaml
apiVersion: v1 kind: ResourceQuota metadata: name: compute-resources spec: hard: pods: "4" 1 requests.cpu: "1" 2 requests.memory: 1Gi 3 limits.cpu: "2" 4 limits.memory: 2Gi 5
besteffort.yaml
apiVersion: v1 kind: ResourceQuota metadata: name: besteffort spec: hard: pods: "1" 1 scopes: - BestEffort 2
compute-resources-long-running.yaml
apiVersion: v1 kind: ResourceQuota metadata: name: compute-resources-long-running spec: hard: pods: "4" 1 limits.cpu: "4" 2 limits.memory: "2Gi" 3 scopes: - NotTerminating 4
compute-resources-time-bound.yaml
apiVersion: v1 kind: ResourceQuota metadata: name: compute-resources-time-bound spec: hard: pods: "2" 1 limits.cpu: "1" 2 limits.memory: "1Gi" 3 scopes: - Terminating 4
storage-consumption.yaml
apiVersion: v1 kind: ResourceQuota metadata: name: storage-consumption spec: hard: persistentvolumeclaims: "10" 1 requests.storage: "50Gi" 2 gold.storageclass.storage.k8s.io/requests.storage: "10Gi" 3 silver.storageclass.storage.k8s.io/requests.storage: "20Gi" 4 silver.storageclass.storage.k8s.io/persistentvolumeclaims: "5" 5 bronze.storageclass.storage.k8s.io/requests.storage: "0" 6 bronze.storageclass.storage.k8s.io/persistentvolumeclaims: "0" 7 requests.ephemeral-storage: 2Gi 8 limits.ephemeral-storage: 4Gi 9
- 1
- 项目中的持久性卷声明总数
- 2
- 在一个项目中的所有持久性卷声明中,请求的存储总和不能超过这个值。
- 3
- 在一个项目中的所有持久性卷声明中,金级存储类中请求的存储总和不能超过这个值。
- 4
- 在一个项目中的所有持久性卷声明中,银级存储类中请求的存储总和不能超过这个值。
- 5
- 在一个项目中的所有持久性卷声明中,银级存储类中声明总数不能超过这个值。
- 6
- 在一个项目中的所有持久性卷声明中,铜级存储类中请求的存储总和不能超过这个值。如果此值设为
0
,则表示铜级存储类无法请求存储。 - 7
- 在一个项目中的所有持久性卷声明中,铜级存储类中请求的存储总和不能超过这个值。如果此值设为
0
,则表示铜级存储类无法创建声明。 - 8
- 在非终端状态的所有 Pod 中,临时存储请求总和不能超过 2Gi。
- 9
- 在非终端状态的所有 Pod 中,临时存储限值总和不能超过 4Gi。
9.1.6. 创建配额
您可以通过创建配额,来约束给定项目中的资源使用量。
流程
- 在一个文件中定义配额。
使用该文件创建配额,并将其应用到项目:
$ oc create -f <file> [-n <project_name>]
例如:
$ oc create -f core-object-counts.yaml -n demoproject
9.1.6.1. 创建对象数配额
您可以为 OpenShift Container Platform 上的所有标准命名空间资源类型创建对象数配额,如 BuildConfig
和 DeploymentConfig
对象。对象配额数将定义的配额施加于所有标准命名空间资源类型。
在使用资源配额时,对象会根据创建的配额进行收费。这些类型的配额对防止耗尽资源很有用处。只有在项目中有足够的备用资源时,才能创建配额。
流程
为资源配置对象数配额:
运行以下命令:
$ oc create quota <name> \ --hard=count/<resource>.<group>=<quota>,count/<resource>.<group>=<quota> 1
- 1
<resource>
变量是资源名称,<group>
则是 API 组(如果适用)。使用oc api-resources
命令可以列出资源及其关联的 API 组。
例如:
$ oc create quota test \ --hard=count/deployments.extensions=2,count/replicasets.extensions=4,count/pods=3,count/secrets=4
输出示例
resourcequota "test" created
本例将列出的资源限制为集群中各个项目的硬限值。
验证是否创建了配额:
$ oc describe quota test
输出示例
Name: test Namespace: quota Resource Used Hard -------- ---- ---- count/deployments.extensions 0 2 count/pods 0 3 count/replicasets.extensions 0 4 count/secrets 0 4
9.1.6.2. 为扩展资源设定资源配额
扩展资源不允许过量使用资源,因此您必须在配额中为相同扩展资源指定 requests
和 limits
。目前,扩展资源只允许使用带有前缀 requests.
配额项。以下是如何为 GPU 资源 nvidia.com/gpu
设置资源配额的示例场景。
流程
确定集群中某个节点中有多少 GPU 可用。例如:
# oc describe node ip-172-31-27-209.us-west-2.compute.internal | egrep 'Capacity|Allocatable|gpu'
输出示例
openshift.com/gpu-accelerator=true Capacity: nvidia.com/gpu: 2 Allocatable: nvidia.com/gpu: 2 nvidia.com/gpu 0 0
本例中有 2 个 GPU 可用。
在命名空间
nvidia
中设置配额。本例中配额为1
:# cat gpu-quota.yaml
输出示例
apiVersion: v1 kind: ResourceQuota metadata: name: gpu-quota namespace: nvidia spec: hard: requests.nvidia.com/gpu: 1
创建配额:
# oc create -f gpu-quota.yaml
输出示例
resourcequota/gpu-quota created
验证命名空间是否设置了正确的配额:
# oc describe quota gpu-quota -n nvidia
输出示例
Name: gpu-quota Namespace: nvidia Resource Used Hard -------- ---- ---- requests.nvidia.com/gpu 0 1
定义一个请求单个 GPU 的 Pod。以下示例定义文件名为
gpu-pod.yaml
:apiVersion: v1 kind: Pod metadata: generateName: gpu-pod- namespace: nvidia spec: restartPolicy: OnFailure containers: - name: rhel7-gpu-pod image: rhel7 env: - name: NVIDIA_VISIBLE_DEVICES value: all - name: NVIDIA_DRIVER_CAPABILITIES value: "compute,utility" - name: NVIDIA_REQUIRE_CUDA value: "cuda>=5.0" command: ["sleep"] args: ["infinity"] resources: limits: nvidia.com/gpu: 1
创建 pod:
# oc create -f gpu-pod.yaml
验证 Pod 是否在运行:
# oc get pods
输出示例
NAME READY STATUS RESTARTS AGE gpu-pod-s46h7 1/1 Running 0 1m
验证配额计数器
Used
是否正确:# oc describe quota gpu-quota -n nvidia
输出示例
Name: gpu-quota Namespace: nvidia Resource Used Hard -------- ---- ---- requests.nvidia.com/gpu 1 1
尝试在
nvidia
命名空间中创建第二个 GPU Pod。从技术上讲这是可行的,因为它有 2 个 GPU:# oc create -f gpu-pod.yaml
输出示例
Error from server (Forbidden): error when creating "gpu-pod.yaml": pods "gpu-pod-f7z2w" is forbidden: exceeded quota: gpu-quota, requested: requests.nvidia.com/gpu=1, used: requests.nvidia.com/gpu=1, limited: requests.nvidia.com/gpu=1
应该会显示此 Forbidden 错误消息,因为您有设为 1 个 GPU 的配额,但这一 Pod 试图分配第二个 GPU,而这超过了配额。
9.1.7. 查看配额
您可以在 Web 控制台导航到项目的 Quota 页面,查看与项目配额中定义的硬限值相关的使用量统计。
您还可以使用命令行来查看配额详情。
流程
获取项目中定义的配额列表。例如,对于名为
demoproject
的项目:$ oc get quota -n demoproject
输出示例
NAME AGE besteffort 11m compute-resources 2m core-object-counts 29m
描述您关注的配额,如
core-object-counts
配额:$ oc describe quota core-object-counts -n demoproject
输出示例
Name: core-object-counts Namespace: demoproject Resource Used Hard -------- ---- ---- configmaps 3 10 persistentvolumeclaims 0 4 replicationcontrollers 3 20 secrets 9 10 services 2 10
9.1.8. 配置显式资源配额
在项目请求模板中配置显式资源配额,以便在新项目中应用特定资源配额。
先决条件
- 使用具有 cluster-admin 角色的用户访问集群。
-
安装 OpenShift CLI(
oc
)。
流程
在项目请求模板中添加资源配额定义:
如果集群中不存在项目请求模板:
创建 bootstrap 项目模板并将其输出到名为
template.yaml
的文件:$ oc adm create-bootstrap-project-template -o yaml > template.yaml
在
template.yaml
中添加资源配额定义。以下示例定义了名为 'storage-consumption' 的资源配额。定义必须在模板的parameter:
部分前添加:- apiVersion: v1 kind: ResourceQuota metadata: name: storage-consumption namespace: ${PROJECT_NAME} spec: hard: persistentvolumeclaims: "10" 1 requests.storage: "50Gi" 2 gold.storageclass.storage.k8s.io/requests.storage: "10Gi" 3 silver.storageclass.storage.k8s.io/requests.storage: "20Gi" 4 silver.storageclass.storage.k8s.io/persistentvolumeclaims: "5" 5 bronze.storageclass.storage.k8s.io/requests.storage: "0" 6 bronze.storageclass.storage.k8s.io/persistentvolumeclaims: "0" 7
- 1
- 项目中的持久性卷声明总数。
- 2
- 在一个项目中的所有持久性卷声明中,请求的存储总和不能超过这个值。
- 3
- 在一个项目中的所有持久性卷声明中,金级存储类中请求的存储总和不能超过这个值。
- 4
- 在一个项目中的所有持久性卷声明中,银级存储类中请求的存储总和不能超过这个值。
- 5
- 在一个项目中的所有持久性卷声明中,银级存储类中声明总数不能超过这个值。
- 6
- 在一个项目中的所有持久性卷声明中,铜级存储类中请求的存储总和不能超过这个值。如果此值设为
0
,则 bronze 存储类无法请求存储。 - 7
- 在一个项目中的所有持久性卷声明中,铜级存储类中请求的存储总和不能超过这个值。如果此值设为
0
,则 bronze 存储类无法创建声明。
通过
openshift-config
命名空间中修改的template.yaml
文件创建项目请求模板:$ oc create -f template.yaml -n openshift-config
注意要将配置作为
kubectl.kubernetes.io/last-applied-configuration
注解包括,将--save-config
选项添加到oc create
命令中。默认情况下,模板称为
project-request
。
如果项目请求模板已在集群中存在:
注意如果您使用配置文件以声明性或必要方式管理集群中的对象,请使用这些文件编辑现有项目请求模板。
列出
openshift-config
命名空间中的模板:$ oc get templates -n openshift-config
编辑现有项目请求模板:
$ oc edit template <project_request_template> -n openshift-config
-
将资源配额定义(如前面的
storage-consumption
示例)添加到现有模板中。定义必须在模板的parameter:
部分前添加。
如果您创建了项目请求模板,在集群的项目配置资源中引用它:
访问项目配置资源进行编辑:
使用 web 控制台:
-
导航至 Administration
Cluster Settings 页面。 - 单击 Configuration 以查看所有配置资源。
- 找到 Project 的条目,并点击 Edit YAML。
-
导航至 Administration
使用 CLI:
编辑
project.config.openshift.io/cluster
资源:$ oc edit project.config.openshift.io/cluster
更新项目配置资源的
spec
部分,使其包含projectRequestTemplate
和name
参数。以下示例引用了默认项目请求模板(名称为project-request
):apiVersion: config.openshift.io/v1 kind: Project metadata: ... spec: projectRequestTemplate: name: project-request
验证在创建项目时是否应用了资源配额:
创建一个项目:
$ oc new-project <project_name>
列出项目的资源配额:
$ oc get resourcequotas
详细描述资源配额:
$ oc describe resourcequotas <resource_quota_name>