14.【云原生-K8S】:资源与服务质量

234 阅读7分钟

资源

设置Pod/容器资源

我们可以精确到容器级别为其设置资源数量,资源resource由两部分组成,分别是请求requests和限制limits当我们设置limits时, kubelet和容器运行时以及底层的cgroup会保证容器使用的资源不超过设置的值;当我们设置requests时,调度器会根据这个值进行pod的调度,并且节点会预留对应大小的资源,以供容器运行时使用,避免出现资源不足的情况。

如果Pod所在的节点拥有足够的资源,那么容器可能并且可以使用超过requests设置的资源量,不过不能超过limits设置的资源量,这个限制可能是以主动的方式来实现,即通过cgroups来设置可使用的资源量;也可能是以被动的方式来实现,即发现超出设置量时进行系统级别的干预。常用的容器运行时如docker\containerd\CRI-O都是通过cgroups也就是主动的方式来实现的资源限制。

新版本k8s的默认容器运行时是containerd,这里minikube的默认运行时依旧是新版本的docker

kubectl describe node minikube,能看到allocated resources的具体情况,这是k8s集群认为该节点可分配的资源,当某Pod的资源超出对应的allocated resources,则无法调度到这个节点上。

⚠️ 如果只设置了Limits但是没有设置Requests,那么k8s将默认把Limits的值复制一份给Requests。

Kubelet将容器作为Pod的一部分启动时,它会将容器的CPU和内存请求与限制信息传递给容器运行时,在Linux系统上,容器运行时会配置内核CGroups,负责处理容器的请求和限制

  • CPU Limit是容器可使用的CPU时间的硬性上限,在每个操作系统时间片中,Linux内核会检查是否超出这个限制
  • CPU Request是一个权重值,如果若干不同的容器需要在一个共享的系统上竞争运行,CPU请求值大的负载会获得比请求值小的负载更多的CPU时间
  • Memory Request值主要用于K8S Pod的调度期间,容器运行时可能用内存请求值作为设置memory.min和memory.low的提示值
  • Memory Limit定义的是cgroup的内存限制,当容器尝试分配的内存量超出限制,则会停止分配容器中的某个进程内存
  • Pod和容器的内存限制也适用于通过内存供应的卷,比如emptyDir卷,kubelet会跟踪内存的卷用量,将其作为容器的内存用量,而不是临时存储用量

资源类型

K8S可为容器/Pod设置的资源类型分为三种,分别是CPU Memory 和 HugePages,对应Linux系统,我们可以设置HugePage值,这是Linux特有的功能,节点内核在其中分配的内存款会比默认页大小大得多。

这些资源都统称计算资源,计算资源的数量是可以测量的,并且可以被请求、分配、消耗,它们与API资源不同,API资源是可以通过K8S API服务器读取和修改的资源。

针对每个容器,你都可以指定它的资源请求和限制,包括以下选项

  • spec.containers[].resources.limits.cpu
  • spec.containers[].resources.limits.memory
  • spec.containers[].resources.limits.hugepages-<size>
  • spec.containers[].resources.requests.cpu
  • spec.containers[].resources.requests.memory
  • spec.containers[].resources.requests.hugepages-<size>

一个Pod的资源请求/限制是这个Pod中所有容器对这类资源的请求/限制的总和。

CPU资源的单位是核数,1CPU=一个物理CPU核心或者一个虚拟CPU核心,支持小数,比如0.5 = 500m

memory资源的单位是字节数,对应的后缀是E、P、T、G、M、k,注意区分m和MM代表MB,m代表的是毫字节 1M = 1024*1024字节 1m = 0.001字节

节点可用资源

节点资源分为两部分,一部分是已经分配给节点上某些k8s组件的资源,这是不可改变也不可取消的;另一部分则是可分配的资源,在调度pod到节点上时比较的就是这部分资源,如果allocatable资源不足,即allocatable < pod request,那么就不会分配到该节点上;已经在该节点上运行的pod消耗的也是这部分资源。

可以看到节点的allocated resources也是分为四种,我们用的最多的还是计算资源cpu/memory

节点通常是一台云服务器或者物理机,本身是有固定的资源配额的,这取决于节点的类型和资源。上图中的Request/Limit并不是指节点的资源情况,而是指节点上运行的Pod资源消耗的情况。

服务质量 QOS

服务质量QOS是一种对于Pod的评分分类机制,K8S会对运行中的Pod进行分类,不同QOS的Pod被处理的逻辑方式会不一样。

QOS的分类是基于Pod资源的,resource下的limitrequest都会影响到这个QOS,当节点压力比较大时(资源不足),kubelet会主动终止某些Pod以回收节点上的资源,当节点资源耗尽时,首先会驱逐该Node上运行的BestEffort等级的Pod,然后是Burstable等级的Pod,最后是GuaranteedPod。当这种驱逐是由于资源压力时,只有超出资源请求的Pod才是被驱逐的候选对象。

Guaranteed

这个级别的Pod具有最严格的资源限制,并且最不可能面临驱逐,只有在Pod使用超过了本身limit资源,或者节点上没有更低优先级的Pod,这些Pod才有可能被驱逐。

条件

  • Pod中的每个容器都需要有cpu + memoryrequestlimit
  • Pod中的每个容器资源的值都需要limit = request,包括cpu和memory

Burstable

这个级别的Pod有基于Request的资源下限保证,但不需要特定的limit。如果没有指定limit,那么默认为Node总量的资源,在驱逐Pod时,优先会驱逐BestEffort的Pod,然后才驱逐Burstable类型的Pod

条件

  • 不满足Guaranteed条件
  • Pod内至少有一个容器具有CPU的Request和limit

BestEffort

BestEffort类的Pod可以使用节点中剩下的资源,比如一个16核的节点,已经分配了8核给其他的Pod,那么这个Pod就只能使用剩下的8核,如果遇到资源压力,首先会驱逐这一类的Pod。

条件

  • 不满足Guaranteed条件
  • 不满足Burstable条件

独立于QOS

某些行为独立于 Kubernetes 分配的 QoS 类。例如:

  • 所有超过资源 limit 的容器都将被 kubelet 杀死并重启,而不会影响该 Pod 中的其他容器。
  • 如果一个容器超出了自身的资源 request,且该容器运行的节点面临资源压力,则该容器所在的 Pod 就会成为被驱逐的候选对象。 如果出现这种情况,Pod 中的所有容器都将被终止。Kubernetes 通常会在不同的节点上创建一个替代的 Pod。
  • Pod 的资源 request 等于其成员容器的资源 request 之和,Pod 的资源 limit 等于其成员容器的资源 limit 之和。
  • kube-scheduler 在选择要抢占的 Pod 时不考虑 QoS 类。当集群没有足够的资源来运行你所定义的所有 Pod 时,就会发生抢占。

实战

这个Pod因为没有设置request和limit,所以QOS=BestEffort

apiVersion: v1
kind: Pod
metadata:
  name: test-taint-pod-8
spec:
  nodeName: minikube
  containers:
  - name: container-a
    image: alpine:latest
    command: ["sh", "-c", "while true; do echo hello; sleep 10; done"]
  tolerations:
    - key: "test"
      operator: "Equal"
      value: "true"
      effect: "NoSchedule"
    - key: "test2"
      operator: "Exists"
      effect: "NoExecute"
~	

这个Pod设置了Request和Limit,但是二者不相等,所以QOS=Burstable

结语

这篇博客主要介绍了临时容器和Pod调试相关操作。《每天十分钟,轻松入门K8S》的第14篇14.【云原生-K8S】:资源与服务质量到这里就结束了,之后的几讲都会和Pod相关,深入源码级别探索K8S核心概念Pod相关内容,感兴趣的朋友欢迎点赞、评论、收藏、订阅,您的支持就是我最大的动力。

推荐阅读

08.源码级别Pod详解(四): Pod readiness与Container Probe

06.源码级别Pod详解(三):Container 生命周期

05.源码级别Pod详解(二):Pod生命周期

02.K8S架构详解