计算资源管理

十一、计算资源管理

到目前为止,我们在创建pod时并不关心它们使用CPU和内存资源的最大值。但是在某些场景下,为一个pod配置资源的预期使用量和最大使用量是pod定义中的重要组成部分。通过设置这两组参数,可以确保pod公平地使用Kubernetes集群资源,同时也影响着整个集群pod的调度方式。

1 基本概念

1.1 请求和约束

如果 Pod 运行所在的节点具有足够的可用资源,容器可能(且可以)使用超出对应资源 request 属性所设置的资源量。不过,容器不可以使用超出其资源 limit 属性所设置的资源量。

1.2 资源类型

CPU 和内存都是资源类型。每种资源类型具有其基本单位。 CPU 表达的是计算处理能力,其单位是 Kubernetes CPUs。 内存的单位是字节。

CPU 和内存统称为计算资源,或简称为资源。计算资源的数量是可测量的,可以被请求、被分配、被消耗。它们与API 资源不同。 API 资源(如 Pod 和 Service)是可通过Kubernetes API服务器读取和修改的对象。

1.3 Kubernetes中的资源单位

CPU资源的约束和请求以CPU为单位。

我们知道2核2线程的CPU,可被系统识别为4个逻辑CPU,在K8s中对CPU的分配限制是对逻辑CPU做分片限制的。也就是说分配给容器一个CPU,实际是分配一个逻辑CPU。而且1个逻辑CPU还可被单独划分子单位,即1个逻辑CPU,还可被划分为1000个millicore(毫核) 简单说就是1个逻辑CPU,继续逻辑分割为1000个毫核。

表达式 0.1 等价于表达式 100m, 可以看作 “100 millicpu”。有些人说成是“一百毫cpu”,其实说的是同样的事情。 具有小数点(如 0.1)的请求由 API 转换为 100m;最大精度是 1m。 因此,或许你应该优先考虑使用 100m 的形式。

CPU 总是按绝对数量来请求的,不可以使用相对数量; 0.1 的 CPU 在单核、双核、48 核的机器上的意义是一样的。

内存的约束和请求以字节为单位。

你可以使用以下后缀之一以一般整数或定点数字形式来表示内存: E、P、T、G、M、k。你也可以使用对应的 2 的幂数:Ei、Pi、Ti、Gi、Mi、Ki。 例如,以下表达式所代表的是大致相同的值:

128974848、129e6、129M、123Mi

接下来,通过一个例子,逐步介绍如何通过请求和约束进行计算资源管理。

2 为pod中的容器申请资源

我们创建一个pod时,可以指定容器对CPU和内存的资源请求量(requests) 以及资源限制(约束)量(limits)。它们并不在pod里定义,而是针对每个容器单独指定。pod对资源的请求量和限制量是它所包含的所有容器的请求量和限制量之和。

你可以将需求限制requests称为软限制,将约束限制limits称为硬限制。

2.1 创建一个资源请求的pod

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: main
    image: busybox
    command: ["dd", "if=/dev/zero", "of=/dev/null"]
    resources:  # 为容器定义资源请求量
      requests:
        cpu: 200m  # 容器申请200毫核(一个CPU核心时间的1/5)
        memory: 5OMi  # 容器申请50M内存

我们声明了一个容器需要1/5核(200毫核)的CPU才能正常运行。换句话说,五个同样的pod可以足够快地运行在一个CPU核上。

当我们不指定CPU requests时,表示我们并不关心系统为容器内的进程分配了多少CPU时间。在最坏情况下进程可能根本分不到CPU时间(当其他进程对CPU需求量很大时会发生)。这对一些时间不敏感、低优先级的批处理任务没有问题,但对于处理用户请求的容器这样配置显然不太合适。

我们同时为容器申请了50MB的内存,说明我们期望容器内的进程最大消耗50MB的RAM。它们可能实际占用较小,但在正常情况下我们并不希望它们占用超过这个值。在后面我们将看到如果超过会发生什么。

现在运行pod。当pod启动时,可以通过在容器中运行top命令快速查看进程的CPU使用:

kubectl exec -it mypod top

结果如下
计算资源管理

我们在容器内执行dd命令会消耗尽可能多的CPU,但因为它是单线程运行所以最多只能跑满一个核,而工作节点拥有四个核,这就是为什么top命令显示进程只占用了将近25%CPU的原因。25%显然就是指一个核,说明容器实际使用量超过了我们在pod定义中申请的200毫核,这是符合预期的,因为requests不会限制容器可以使用的CPU数量。我们后续需要指定CPU限制实现这一点。

不过首先我们看看在pod中指定资源requests对pod调度的影响。

2.2 requests如何影响调度

通过设置资源requests我们指定了pod对资源需求的最小值。调度器在将pod调度到节点的过程中会用到该信息。每个节点可分配给pod的CPU和内存数量都是一定的。调度器在调度时只考虑那些未分配资源量满足pod需求量的节点。如果节点的未分配资源量小于pod需求量,这时节点没有能力提供pod对资源需求的最小量,因此Kubernetes不会将该pod调度到这个节点。

这里比较重要而且会令人觉得意外的是,调度器在调度时并不关注各类资源在当前时刻的实际使用量,而只关心节点上部署的所有pod的资源申请量之和。尽管现有pods的资源实际使用量可能小于它的申请量,但如果使用基于实际资源消耗量的调度算法将打破系统为这些已部署成功的pods提供足够资源的保证。

如下图,节点上部署了三个pod。它们共申请了节点80%的CPU和60%的内存资源。图右下方的pod D将无法调度到这个节点上,因为它25%的CPU requests大于节点未分配的20%CPU。而实际上,这与当前三个pods仅使用70%的CPU没有什么关系。
计算资源管理

在第八章中介绍过,调度器首先会对节点列表进行过滤,排除那些不满足需求的节点,然后根据预先配置的优先级函数对其余节点进行排序。其中有两个基于资源请求量的优先级排序函数:LeastRequestedPriorityMostRequestedPriority。前者优先将pod调度到请求量少的节点上(也就是拥有更多未分配资源的节点),而后者相反,优先调度到请求量多的节点(拥有更少未分配资源的节点)。但是,正如我们刚刚解释的,它们都只考虑资源请求量,而不关注实际使用资源量。

调度器只能配置一种优先级函数。你可能在想为什么有人会使用MostRequestedPriority函数。毕竟如果你有一组节点,通常会使其负载平均分布,但是在随时可以增加或删除节点的云基础设施上运行时并非如此。配置调度器使用MostRequestedPriority函数,可以在为每个pod提供足量CPU/内存资源的同时,确保Kubernetes使用尽可能少的节点。通过使pod紧凑地编排,一些节点可以保待空闲并可随时从集群中移除。由于通常会按照单个节点付费, 这样便可以节省一笔开销。

接下来我们看看调度器的行为。我们将部署另一个资源请求量是之前4倍的pod。但在这之前, 我们先看看什么是节点资源总量。因为调度器需要知道每个节点拥有多少CPU和内存资源,Kubelet会向API服务器报告相关数据,并通过节点资源对外提供访问,可以使用kubectl describe命令进行查看:

kubectl describe nodes

结果如下(截取):

Name:               k8s-node-1
Capacity:
 cpu:                4
 ephemeral-storage:  51175Mi
 hugepages-2Mi:      0
 memory:             4028688Ki
 pods:               110
Allocatable:
 cpu:                4
 ephemeral-storage:  48294789041
 hugepages-2Mi:      0
 memory:             3926288Ki
 pods:               110
 
Name:               k8s-node-2
Capacity:
 cpu:                4
 ephemeral-storage:  51175Mi
 hugepages-2Mi:      0
 memory:             4028688Ki
 pods:               110
Allocatable:
 cpu:                4
 ephemeral-storage:  48294789041
 hugepages-2Mi:      0
 memory:             3926288Ki
 pods:               110

参数Capacity表示节点的资源总量,Allocatable表示可分配给pod的资源量。资源总量代表节点所有的资源总和,包括那些可能对pod 不可用的资源。有些资源会为Kubernetes或者系统组件预留。调度器的决策仅仅基于可分配资源量。

从上面的例子中可以看到节点没有预留资源,全部CPU都可以分配给pod。因此,调度器再调度另一个申请了800毫核的pod是没有问题的。由于我们有两个节点可以被调度,为了控制变量,又不想通过高级调度(污点等)的方式干预调度器的工作过程,在运行第二个pod之前,我们先将k8s-node-2退出,集群中只保留一个节点,然后再运行第二个pod,下面是它的资源清单:

apiVersion: v1
kind: Pod
metadata:
  name: mypod2
spec:
  containers:
  - name: main
    image: busybox
    command: ["dd", "if=/dev/zero", "of=/dev/null"]
    resources:  # 为容器定义资源请求量
      requests:
        cpu: 800m  # 容器申请800毫核
        memory: 20Mi  # 容器申请20M内存

如下图,可以看到它已经被调度了:
计算资源管理

我们现在部署了两个pod,共申请了1000毫核CPU。所以理论上我们应该还剩下3核可供其他pod使用。因此我们再部署一个资源申请量为3核的pod。资源清单就不再赘述了,创建该pod,并且API接收了这个请求:

[root@k8s-master test]# kubectl apply -f threecores.yaml 
pod/mypod3 created

但是,当我们查看pod时,会发现pod会卡在Pending状态:

[root@k8s-master test]# kubectl get po
NAME     READY   STATUS    RESTARTS   AGE
mypod    1/1     Running   0          5m42s
mypod2   1/1     Running   0          5m38s
mypod3   0/1     Pending   0          94s

使用describe查看详细原因(截取):

[root@k8s-master test]# kubectl describe po mypod3
Name:         mypod3
Namespace:    default
Node:         <none>  # 没有与pod关联的节点
Status:       Pending  # 处于Pending状态
...
Conditions:
  Type           Status
  PodScheduled   False   # pod没有被调度成功
...
Events:
  Type     Reason            Age                  From               Message
  ----     ------            ----                 ----               -------
  Warning  FailedScheduling  40s (x4 over 3m34s)  default-scheduler  0/3 nodes are available: 1 Insufficient cpu, 2 node(s) had taints that the pod didn't tolerate.

Events.Message中,提示我们有3个节点可用,由于k8s-node-2被我们手动关闭,所以显示两个节点(另外一个是主节点)存在污点导致无法调度,而k8s-node-1由于CPU资源不足导致调度失败。但是为什么呢?三个pod的CPU requests总和是4核,我们的节点正好可以提供,是哪里出了问题?

可以通过检查节点资源找出为什么pod没有成功调度。让我们再次执行kubectl describe node k8s-node-1命令并仔细地检查输出:

Name:               k8s-node-1

Non-terminated Pods:         (4 in total)
  Namespace                  Name                     CPU Requests  CPU Limits  Memory Requests  Memory Limits  AGE
  ---------                  ----                     ------------  ----------  ---------------  -------------  ---
  default                    mypod                    200m (5%)     0 (0%)      50Mi (1%)        0 (0%)         16m
  default                    mypod2                   800m (20%)    0 (0%)      20Mi (0%)        0 (0%)         16m
  kube-system                kube-flannel-ds-828wp    100m (2%)     100m (2%)   50Mi (1%)        50Mi (1%)      35h
  kube-system                kube-proxy-7pvcm         0 (0%)        0 (0%)      0 (0%)           0 (0%)         35h
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests     Limits
  --------           --------     ------
  cpu                1100m (27%)  100m (2%)
  memory             120Mi (3%)   50Mi (1%)
  ephemeral-storage  0 (0%)       0 (0%)
Events:              <none>

Allocated resources中查看已分配的资源,发现一共有1100毫核的CPU被申请,比我们先前部署的两个pod的总和1000毫核多了100毫核,看来有些东西吃掉了额外的CPU资源。

我们可以在上面的Non-terminated Pods列表中找到罪魁祸首。来自kube-system名称空间下的一个pod申请了100毫核CPU,导致我们只剩2900毫核CPU可用。第三个pod需要3000毫核,因此调度器不会将其调度到这个节点上。

只有当节点资源释放后(比如删除之前两个pod中的一个) pod才会调度上来。如果我们删除mypod2,调度器将获取到删除通知(监控机制),并在该pod成功终止后立即调度第三个pod。
计算资源管理

在以上所有例子中,我们也指定了内存申请量,不过它并没有对调度产生影响,因为我们的节点拥有足够多的内存来容纳所有pod的需求。不过,调度器处理CPU和内存requests的方式基本相同。与内存requests不同的是,pod的CPU requests在其运行时也扮演着一个角色,我们接下来将讨论这个话题。

2.3 CPU requests如何影响CPU时间分配

现在有两个pod运行在集群中(暂且忽略系统pod)。一个请求了200毫核,另一个为3000毫核(前者的15倍)。Kubernetes会将requests资源和limits资源区别对待。我们目前还没有定义任何limits,因此每个pod分别可以消耗多少CPU并没有做任何限制。

假设每个pod内的进程都尽情消耗CPU时间,每个pod最终能分到多少CPU时间?

CPU requests不仅仅在调度时起作用,它还决定着剩余(未使用) 的CPU时间如何在pod之间分配。因为第一个pod请求了200毫核,另一个请求了3000毫核,所以未使用的CPU将按照1:15的比例来划分给这两个pod。如果两个pod都全力使用CPU,第一个pod将获得6.25%的CPU时间,另一个将获得93.75%的CPU时间。

另一方面,如果一个容器能够跑满CPU,而另一个容器在该时段处于空闲状态,那么前者将可以使用整个CPU时间(当然会减掉第二个容器消耗的少量时间)。毕竟当没有其他人使用时提高整个CPU的利用率也是有意义的。当然,第二个容器需要CPU时间的时候,也会获取到,同时第一个容器会被限制回来。

再举一个通俗的例子,你坐飞机买了一张普通票,另一个人买了一张豪华票。在那个人还没有上飞机之前(容器处于空闲状态),你可以“霸占”它的座位先坐一会儿,同时享有你的座位和他的座位(占用它的CPU时间);当他上飞机找自己的座位时(容器开始工作),你就要把座位让出来,回到你的座位上去(限制容器的CPU分配)。

3 限制容器的可用资源

设置pod的容器资源申请量requests保证了每个容器能够获得它所需要资源的最小量。现在我们再看看硬币的另一面一一容器可以消耗资源的最大量limits。

3.1 设置容器可使用资源量的硬限制

之前提到当其他进程处于空闲状态时容器可以被允许使用所有CPU资源。但是你可能想防止一些容器使用超过指定数量的CPU,而且经常会希望限制容器的可消耗内存数量。

CPU是一种可压缩资源,意味着我们可以在不对容器内运行的进程产生不利影响的同时,对其使用量进行限制,也可以在使用中动态回收。而内存明显不同,它是一种不可压缩资源。一旦系统为进程分配了一块内存,这块内存在进程主动释放之前将无法被回收。这就是我们为什么需要限制容器的最大内存分配量的根本原因。

如果不对内存进行限制,工作节点上的容器(或者pod )可能会吃掉所有可用内存,会对该节点上所有其他pod和任何新调度上来的pod(新调度的pod是基于内存的申请量而不是实际使用量)造成影响。单个故障pod或恶意pod几乎可以导致整个节点不可用。

3.2 创建一个带有资源limits的pod

为了防止这种情况发生,Kubernetes允许用户为每个容器指定资源limits (与设置资源requests几乎相同),如下所示:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: main
    image: busybox
    command: ["dd", "if=/dev/zero", "of=/dev/null"]
    resources:  # 为容器定义资源请求量
      limits:
        cpu: 1  # 容器最多允许使用1核CPU
        memory: 100Mi  # 容器最大允许使用100M内存

这个pod的容器包含了CPU和内存资源limits配置。容器内的进程不允许消耗超过1核CPU和100MB内存。因为没有指定资源requests,它将被设置为与资源limits相同的值。

与资源requests不同的是,资源limits不受节点可分配资源量的约束。所有limits的总和允许超过节点资源总量的100%,换句话说,资源limits可以超卖。如果节点资源使用量超过100% ,一些容器将被杀掉,如下图所示:
计算资源管理

3.3 超过limits

当容器内运行的进程尝试使用比限额更多的资源时会发生什么?

CPU是可压缩资源,当进程不等待IO操作时消耗所有的CPU时间是非常常见的。正如我们所知道的,对一个进程的CPU使用率可以进行限制,因此当为一个容器设置CPU限额时,该进程只会分不到比限额更多的CPU而己。

而内存却有所不同。当进程尝试申请分配比限额更多的内存时会被杀掉,如果容器可重新启动,则与所有其他类型的运行时失效一样,kubelet将重新启动容器,用户可能根本察觉不到它被杀掉。但是如果它继续超限并被杀死,kubelet会再次尝试重启,并开始增加下次重启的间隔时间。这种情况下用户会看到pod处于CrashLoopBackOff状态。

CrashLoopBackOff状态表示Kubelet还没有放弃,它意味着在每次崩溃之后,Kubelet就会增加下次重启之前的间隔时间。第一次崩渍之后,Kubelet立即重启容器,如果容器再次崩溃,Kubelet会等待10秒钟后再重启。随着不断崩溃,延迟时间也会按照20、40、80、160秒以几何倍数增长,最终收敛在300秒。一旦间隔时间达到300 秒,Kubelet将以5分钟为间隔时间对容器进行无限重启,直到容器正常运行或被删除。

因此,如果你不希望容器被杀掉,重要的一点就是不要将内存limits设置得很低。现在让我们讨论一下在大多数用户首次指定limits时需要注意的地方。

3.4 容器中的应用如何看待limits

现在,我们创建了一个带有资源limits的pod,容器内的进程不允许消耗超过1核CPU和100MB内存。现在我们在容器内运行top命令查看一下:

kubectl exec -it mypod top

结果如下
计算资源管理

查看used和free内存量,这些数值远超出我们为容器设置的100MB限额。同样地,我们设置了CPU限额为1核,即使我们使用的dd命令通常会消耗所有可用的CPU资源,但主进程似乎只用到了25% 。所以究竟发生了什么呢?

原因是,在容器内看到的始终是节点的内存, 而不是容器本身的内存。即使你为容器设置了最大可用内存的限额,top命令显示的是运行该容器的节点的内存数量,而容器无法感知到此限制。

与内存完全一样,无论有没有配置CPU limits,容器内也会看到节点所有的CPU。将CPU限额配置为1,并不会神奇地只为容器暴露一个核。CPU limits做的只是限制容器使用的CPU时间。换句话说,容器内同样可以看到节点所有的CPU核。因此如果一个拥有1核CPU限额的容器运行在64核CPU上,只能获得1/64的全部CPU时间。而且即使限额设置为1核,容器进程也不会只运行在一个核上,不同时刻,代码还是会在多个核上执行。

4 Pod QoS等级

前面己经提到资源limits可以超卖, 一个节点不一定能提供所有pod所指定的资源limits之和那么多的资源量。

假设有两个pod,pod A使用了节点内存的90%,pod B突然需要比之前更多的内存,这时节点无法提供足量内存,哪个容器将被杀掉呢?应该是pod B吗?因为节点无法满足它的内存请求。或者应该是pod A吗?这样释放的内存就可以提供给pod B了。

显然,这要分情况讨论。Kubernetes无法自己做出正确决策,因此就需要一种方式,我们通过这种方式可以指定哪种pod在该场景中优先级更高。Kubernetes将pod划分为3种QoS等级:

  • BestEffort (优先级最低)
  • Burstable
  • Guaranteed (优先级最高)

4.1 定义pod的QoS等级

QoS等级来源于pod所包含的容器的资源requests和limits的配置。下面介绍分配QoS等级的方法。

  1. 为pod分配BestEffort 等级

最低优先级的QoS等级是BestEffort。会分配给那些没有(为任何容器)设置任何requests和limits的pod 。前面章节创建的pod都是这个等级。在这个等级运行的容器没有任何资源保证。在最坏情况下,它们分不到任何CPU时间,同时在需要为其他pod释放内存时,这些容器会第一批被杀死。不过因为BestEffort pod没有配置内存limits,当有充足的可用内存时,这些容器可以使用任意多的内存。

  1. 为pod分配Guaranteed等级

与Burstable相对的是Guaranteed等级,会分配给那些所有资源request和limits相等的pod。对于一个Guaranteed级别的pod,有以下几个条件:

  • CPU和内存都要设置requests和limits
  • 每个容器都需要设置资源量
  • 它们必须相等(每个容器的每种资源的requests和limits必须相等)

如果容器的资源requests没有显式设置,默认与limits相同,所以只设置所有资源(pod内每个容器的每种资源)的限制量就可以使pod 的QoS等级为Guaranteed。这些pod的容器可以使用它所申请的等额资源,但是无法消耗更多的资源(因为它们的limits和requests相等)。

  1. 为pod分配Burstable等级

Burstable QoS等级介于BestEffort和Guaranteed之间。其他所有的pod都属于这个等级。包括容器的requests和limits不相同的单容器pod,至少有一个容器只定义了requests但没有定义limits的pod,以及一个容器的request和limits相等,但是另一个容器不指定requests或limits的pod。Burstable pod可以获得它们所申请的等额资源,并可以使用额外的资源(不超过limits) 。

下图展示了三种Qos等级和它们与request和limits之间的关系:
计算资源管理

考虑一个pod应该属于哪个QoS等级足以令人脑袋快速运转,因为它涉及多个容器、多种资源,以及requests和limits之间所有可能的关系。如果一开始从容器级别考虑QoS(尽管它并不是容器的属性,而是pod 的属性),然后从容器QoS推导出pod QoS,这样可能更容易理解。

下表显示了基于资源requests和limits如何为单个容器定义QoS等级。对于单容器pod,容器的QoS等级也适用于pod。

CPU requests vs. limits 内存的requests vs. limits 容器的QoS等级
未设置 未设置 BestEffort
未设置 Requests < Limits Burstable
未设置 Requests = Limits Burstable
Requests < Limits 未设置 Burstable
Requests < Limits Requests < Limits Burstable
Requests < Limits Requests = Limits Burstable
Requests = Limits Requests = Limits Guaranteed

注意,如果设置了requests而没有设置limits,参考表中requests小于limits那一行。如果设置了limits,requests默认与limits相等,参考request等于limits那一行。

对千多容器pod,如果所有的容器的QoS等级相同, 那么这个等级就是pod的QoS等级。如果至少有一个容器的QoS等级与其他不同,无论这个容器是什么等级,这个pod的QoS等级都是Burstable等级。如下表所示:

容器1的QoS等级 容器2的QoS等级 pod的QoS等级
BestEffort BestEffort BestEffort
BestEffort Burstable Burstable
BestEffort Guaranteed Burstable
Burstable Burstable Burstable
Burstable Guaranteed Burstable
Guaranteed Guaranteed Guaranteed

超过两个容器的pod也可以根据上表类推。

使用命令kubectl describe pod可以查看pod的QoS等级。

4.2 内存不足时哪个进程会被杀死

在一个超卖的系统,QoS等级决定着哪个容器第一个被杀掉,这样释放出的资源可以提供给高优先级的pod使用。BestEffort等级的pod首先被杀掉,其次是Burstable pod,最后是Guaranteed pod。Guaranteed pod只有在系统进程需要内存时才会被杀掉。

举个例子:
计算资源管理

假设两个单容器的pod,第一个属于BestEffort QoS等级, 第二个属于Burstable等级。当节点的全部内存已经用完,还有进程尝试申请更多的内存时,系统必须杀死其中一个进程(甚至包括尝试申请额外内存的进程)以兑现内存分配请求。这种情况下,BestEffort pod的进程会在Guaranteed pod的进程之前被杀掉。同样地,Burstable pod的进程也先于Guaranteed pod的进程被杀掉。但如果只有两个Burstable pod会发生什么呢? 很明显需要选择一个优先于另一个的进程。

如何处理相同QoS等级的容器呢?

每个运行中的进程都有一个称为OutOfMemory (OOM)分数的值。系统通过比较所有运行进程的OOM分数来选择要杀掉的进程。当需要释放内存时,分数最高的进程将被杀死。

OOM分数由两个参数计算得出:进程已消耗内存占可用内存的百分比,与一个基于pod QoS等级和容器内存申请量固定的OOM分数调节因子。对于两个属于Burstable等级的单容器的pod,系统会杀掉内存实际使用量占内存申请量比例更高的pod。这就是上图中使用了内存申请量90%的pod B在pod C (只使用了70%)之前被杀掉的原因,尽管pod C比pod B使用了更多内存。

这说明我们不仅要注意requests和limits之间的关系,还要留心requests和预期实际消耗内存之间的关系。

5 LimitRanger和ResourceQuota

我们已经了解到如何为单个容器设置资源requests和limits。如果我们不做限制,这个容器将处于其他所有设置了requests和limits的容器的控制之下。换句话说,为每个容器设置requests和limits是有意义的。

5.1 LimitRange

用户可以通过创建一个LimitRange资源来避免必须配置每个容器。LimitRange资源不仅允许用户(为每个命名空间)指定能给容器配置的每种资源的最小和最大限额,还支持在没有显式指定资源requests时为容器设置默认值。

LimitRanger是一个准入控制器插件(在第十章介绍过),API服务器接收到带有pod描述信息的POST请求时,LimitRanger插件对pod spec进行校验。如果校验失败,将直接拒绝。因此, LimitRange对象的一个广泛应用场景就是阻止用户创建大于单个节点资源量的pod。如果没有LimitRange,API服务器将欣然接收pod创建请求,但永远无法调度成功。

有关具体的使用,可以参阅官方文档示例

这个插件应用于同一个命名空间中每个独立的pod、容器,或者其他类型的对象。但是,它并不会限制这个命名空间中所有pod可用资源的总量,这就需要介绍另一个插件——ResourceQuota了。

5.2 ResourceQuota

LimitRange只应用于单独的pod,而我们同时也需要一种手段可以限制命名空间中的可用资源总量。这通过创建一个ResourceQuota对象来实现。关于二者的区别,如下图所示,LimitRange应用于单独的pod;ResourceQuota应用于命名空间中所有的pod。
计算资源管理

有关ResourceQuota的相关使用,请参阅资源配额为命名空间配置内存和CPU配额

上一篇:Docker 与 K8S学习笔记(十五)—— 核心概念梳理


下一篇:kubernetes