【kubernetes系列】Kubernetes之资源限制ResourceQuota

概述

当多个用户或团队共享具有固定节点数目的集群时,人们会担心有人使用超过其基于公平原则所分配到的资源量。我们可以通过ResourceQuota来解决这个问题,对每个namespace的资源消耗总量提供限制。它可以限制命名空间中某种类型的对象的总数目上限,也可以限制命名空间中的 Pod 可以使用的计算资源的总上限。

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

  • 不同的团队在不同的namespace下工作,这可以通过 RBAC 强制执行。
  • 管理员为每个namespace创建一个或多个ResourceQuota对象。
  • 用户在相应的namespace中创建资源时,quota 配额系统跟踪使用情况,来确保其不超过资源配额中定义的硬性资源限额
  • 如果资源的创建或更新违反了配额约束,则请求会失败,并返回 HTTP状态码 403 FORBIDDEN ,以及说明违反配额约束的信息。
  • 如果namespace下的计算资源 (如 cpu 和 memory)的配额被启用,则用户必须为这些资源设定请求值(request)和约束值(limit),否则配额系统将拒绝Pod的创建。
  • 资源配额的更改不会影响到已经创建的pod。

提示: 可使用 LimitRange 准入控制器来为没有设置计算资源需求的Pod设置默认值。
ResourceQuota官方文档地址https://kubernetes.io/zh-cn/docs/concepts/policy/resource-quotas/

启用资源配额

资源配额的支持在很多Kubernetes版本中是默认开启的。当 apiserver 的 --admission-control= 参数中包含 ResourceQuota 时,资源配额会被启用。当namespace中存在一个 ResourceQuota 对象时,该namespace即开始实施资源配额管理。

配额分类

计算资源配额

用户可以对指定namespace下的计算资源可使用总量进行限制。目前配额机制所支持的资源类型如下:

资源名称描述
cpu所有非终止状态的Pod中,其CPU需求(request)总量上限
limits.cpu所有非终止状态的Pod中,其CPU限额(limit)总量上限
limits.memory所有非终止状态的Pod中,其内存限额总量上限
memory所有非终止状态的Pod中,其内存需求总量上限
requests.cpu所有非终止状态的Pod中,其CPU需求总量上限
requests.memory所有非终止状态的Pod中,其内存需求总量上限
requests.nvidia.com/gpu所有非终止状态的Pod中,其GPU资源总数使请求上限

存储资源配额

用户可以对指定namespace下的存储资源总量进行限制。此外,还可以根据相关的存储类(Storage Class)来限制存储资源的消耗。

资源名称描述
requests.storage所有的PVC中,存储资源的需求声明总上限
persistentvolumeclaimsnamespace中所允许的 PVC个数上限
<storage-class-name>.storageclass.storage.k8s.io/requests.storage所有该storage-class-name相关的PVC中, 存储资源的需求声明总上限
<storage-class-name>.storageclass.storage.k8s.io/persistentvolumeclaimsnamespace中所允许的 PVC个数上限

对象数量配额

资源名称描述
configmaps在该命名空间中允许存在的 ConfigMap 总数上限
persistentvolumeclaims在该命名空间中允许存在的 PVC 的总数上限
pods在该命名空间中允许存在的非终止状态的 Pod 总数上限。Pod 终止状态等价于 Pod 的 .status.phase in (Failed, Succeeded) 为真
replicationcontrollers在该命名空间中允许存在的 ReplicationController 总数上限
resourcequotas在该命名空间中允许存在的 ResourceQuota 总数上限
services在该命名空间中允许存在的 Service 总数上限
services.loadbalancers在该命名空间中允许存在的 LoadBalancer 类型的 Service 总数上限
services.nodeports在该命名空间中允许存在的 NodePort 类型的 Service 总数上限
secrets在该命名空间中允许存在的 Secret 总数上限

配额作用域

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

范围描述
Terminating匹配 spec.activeDeadlineSeconds >= 0 的pod。
NotTerminating匹配 spec.activeDeadlineSeconds is nil 的pod。
BestEffort匹配"尽力而为(best effort)"服务类型的pod。
NotBestEffort匹配非"尽力而为(best effort)"服务类型的pod。
PriorityClass匹配所有引用了所指定的优先级类的 Pods。
CrossNamespacePodAffinity匹配那些设置了跨名字空间 (反)亲和性条件的 Pod。

BestEffort 作用域限制配额跟踪以下资源: pods
而Terminating、 NotTerminating 和 NotBestEffort 限制配额跟踪以下资源:

  • cpu
  • limits.cpu
  • limits.memory
  • memory
  • pods
  • requests.cpu
  • requests.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 字段。

示例

[root@k8s-m1 k8s-resource]# cat resource-list.yaml 
apiVersion: v1
kind: List
items:
- apiVersion: v1
  kind: ResourceQuota
  metadata:
    name: pods-high
  spec:
    hard:
      cpu: "100"
      memory: 50Gi
      pods: "10"
    scopeSelector:
      matchExpressions:
      - operator: In
        scopeName: PriorityClass
        values: ["high"]
- apiVersion: v1
  kind: ResourceQuota
  metadata:
    name: pods-medium
  spec:
    hard:
      cpu: "60"
      memory: 30Gi
      pods: "10"
    scopeSelector:
      matchExpressions:
      - operator: In
        scopeName: PriorityClass
        values: ["medium"]
- apiVersion: v1
  kind: ResourceQuota
  metadata:
    name: pods-low
  spec:
    hard:
      cpu: "40"
      memory: 10Gi
      pods: "10"
    scopeSelector:
      matchExpressions:
      - operator: In
        scopeName: PriorityClass
        values: ["low"]

[root@k8s-m1 k8s-resource]# kubectl apply -f resource-list.yaml 
resourcequota/pods-high created
resourcequota/pods-medium created
resourcequota/pods-low created
[root@k8s-m1 k8s-resource]# kubectl get resourcequotas 
NAME          AGE   REQUEST                                  LIMIT
pods-high     5s    cpu: 0/100, memory: 0/50Gi, pods: 0/10   
pods-low      5s    cpu: 0/40, memory: 0/10Gi, pods: 0/10    
pods-medium   5s    cpu: 0/60, memory: 0/30Gi, pods: 0/10    
[root@k8s-m1 k8s-resource]# kubectl describe quota 
Name:       pods-high
Namespace:  default
Resource    Used  Hard
--------    ----  ----
cpu         0     100
memory      0     50Gi
pods        0     10


Name:       pods-low
Namespace:  default
Resource    Used  Hard
--------    ----  ----
cpu         0     40
memory      0     10Gi
pods        0     10


Name:       pods-medium
Namespace:  default
Resource    Used  Hard
--------    ----  ----
cpu         0     60
memory      0     30Gi
pods        0     10

#priorityclass也需要自己手动创建,系统默认自带了两个
[root@k8s-m1 k8s-resource]# cat priorityclass.yaml 
apiVersion: scheduling.k8s.io/v1beta1
kind: PriorityClass
metadata:
  name: high
value: 10000   
globalDefault: true  
description: "high priority"

[root@k8s-m1 k8s-resource]# kubectl apply  -f priorityclass.yaml 
Warning: scheduling.k8s.io/v1beta1 PriorityClass is deprecated in v1.14+, unavailable in v1.22+; use scheduling.k8s.io/v1 PriorityClass
priorityclass.scheduling.k8s.io/high created

[root@k8s-m1 k8s-resource]# kubectl get priorityclasses.scheduling.k8s.io 
NAME                      VALUE        GLOBAL-DEFAULT   AGE
high                      10000        true             14s
system-cluster-critical   2000000000   false            431d
system-node-critical      2000001000   false            431d

[root@k8s-m1 k8s-resource]# cat higi-priority-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: high-priority-pod
spec:
  containers:
  - name: high-priority
    image: centos:7
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo hello; sleep 10;done"]
    resources:
      requests:
        memory: "2Gi"
        cpu: "500m"
      limits:
        memory: "4Gi"
        cpu: "500m"
  priorityClassName: high

[root@k8s-m1 k8s-resource]# kubectl apply -f higi-priority-pod.yaml 
pod/high-priority created

[root@k8s-m1 k8s-resource]# kubectl describe resourcequotas pods-high
Name:       pods-high
Namespace:  default
Resource    Used  Hard
--------    ----  ----
cpu         500m  100
memory      2Gi   50Gi
pods        1     10

请求/约束

分配计算资源时,可以为每个容器指定CPU或内存请求和约束,也可以设置两者中的任何一个。
如果配额中指定了 requests.cpu 或 requests.memory 的值,那么它要求每个进来的容器针对这些资源有明确的请求。 如果配额中指定了 limits.cpu 或 limits.memory的值,那么它要求每个进来的容器针对这些资源指定明确的约束。

示例

[root@k8s-m1 k8s-resource]# kubectl create namespace myspace
[root@k8s-m1 k8s-resource]# cat compute-resources.yaml 
apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-resources
  namespace: myspace
spec:
  hard:
    requests.cpu: "1"
    requests.memory: 1Gi
    limits.cpu: "2"
    limits.memory: 2Gi
    requests.nvidia.com/gpu: 4

[root@k8s-m1 k8s-resource]# cat object-counts.yaml 
apiVersion: v1
kind: ResourceQuota
metadata:
  name: object-counts
  namespace: myspace
spec:
  hard:
    configmaps: "10"
    persistentvolumeclaims: "4"
    pods: "4"
    replicationcontrollers: "20"
    secrets: "10"
    services: "10"
    services.loadbalancers: "2"

[root@k8s-m1 k8s-resource]# kubectl create -f compute-resources.yaml 
resourcequota/compute-resources created 
[root@k8s-m1 k8s-resource]# kubectl create -f object-counts.yaml 
resourcequota/object-counts created

[root@k8s-m1 k8s-resource]# kubectl get quota --namespace=myspace
NAME                AGE   REQUEST                                                                                                                                              LIMIT
compute-resources   15s   requests.cpu: 0/1, requests.memory: 0/1Gi, requests.nvidia.com/gpu: 0/4                                                                              limits.cpu: 0/2, limits.memory: 0/2Gi
object-counts       3s    configmaps: 0/10, persistentvolumeclaims: 0/4, pods: 0/4, replicationcontrollers: 0/20, secrets: 1/10, services: 0/10, services.loadbalancers: 0/2   

创建nginx测试,如果pod所需资源超过resourcequota设置的pod将不能正常创建出来

[root@k8s-m1 k8s-resource]# kubectl apply  -f nginx-resourcequota-deployment.yml 
deployment.apps/my-nginx created
[root@k8s-m1 k8s-resource]# cat nginx-resourcequota-deployment.yml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  namespace: myspace
  labels:
    app: nginx
spec:
  selector:
    matchLabels:
      tier: frontend
  replicas: 2
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
        - name: nginx-gateway
          image: nginx
          resources:
            requests:
              cpu: 1
              memory: 1Gi
            limits:
              cpu: 1
              memory: 1Gi
          ports:
            - containerPort: 80

[root@k8s-m1 k8s-resource]# kubectl apply  -f nginx-resourcequota-deployment.yml 
deployment.apps/my-nginx created

[root@k8s-m1 k8s-resource]# kubectl get pod -n myspace 
NAME                        READY   STATUS    RESTARTS   AGE
my-nginx-5c45dd8bc5-7zhw5   1/1     Running   0          83s
#只创建出来一个pod,而预期是2个

[root@k8s-m1 k8s-resource]# kubectl describe replicasets.apps  -n myspace my-nginx-5c45dd8bc5 
Name:           my-nginx-5c45dd8bc5
Namespace:      myspace
Selector:       pod-template-hash=5c45dd8bc5,tier=frontend
Labels:         pod-template-hash=5c45dd8bc5
                tier=frontend
Annotations:    deployment.kubernetes.io/desired-replicas: 2
                deployment.kubernetes.io/max-replicas: 3
                deployment.kubernetes.io/revision: 1
Controlled By:  Deployment/my-nginx
Replicas:       1 current / 2 desired
Pods Status:    1 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  pod-template-hash=5c45dd8bc5
           tier=frontend
  Containers:
   nginx-gateway:
    Image:      nginx
    Port:       80/TCP
    Host Port:  0/TCP
    Limits:
      cpu:     1
      memory:  1Gi
    Requests:
      cpu:        1
      memory:     1Gi
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type             Status  Reason
  ----             ------  ------
  ReplicaFailure   True    FailedCreate
Events:
  Type     Reason            Age                From                   Message
  ----     ------            ----               ----                   -------
  Normal   SuccessfulCreate  98s                replicaset-controller  Created pod: my-nginx-5c45dd8bc5-7zhw5
  Warning  FailedCreate      98s                replicaset-controller  Error creating: pods "my-nginx-5c45dd8bc5-5hjqq" is forbidden: exceeded quota: compute-resources, requested: requests.cpu=1,requests.memory=1Gi, used: requests.cpu=1,requests.memory=1Gi, limited: requests.cpu=1,requests.memory=1Gi

可以看到,由于所需资源已经超出当前命名空间设置的resourcequota,pod将不能正常创建。

更多关于kubernetes的知识分享,请前往博客主页。编写过程中,难免出现差错,敬请指出

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

margu_168

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值