一、基础了解

1.1 资源说明

为什么会有资源配额管理?

可以提高集群稳定性,确保指定的资源对象在任何时候都不会超量占用系统物理资源,避免业务进程在设计或实现上的缺陷导致整个系统运行紊乱甚至意外宕机。

资源配额管理维度解释?

1. 容器级别,定义每个Pod上资源配额相关的参数,比如CPU/Memory、Request/Limit;
2. Pod级别,自动为每个没有定义资源配额的Pod添加资源配额模板,比如LimitRanger。
3. Namespace级别,从总量上限制一个租户(应用)所能使用的资源配额,比如ResourceQuota,包括资源有:Pod数量、Replication Controller数量、Service数量、ResourceQuota数量、Secret数量和可持有的PV数量。

资源配额参数有什么?

程序所使用的CPU与Memory是一个动态的量,跟负载密切相关,当负载增加时,CPU和Memory的使用量也会增加。
spec.container[].resources.requests.cpu:容器初始要求的CPU数量。
spec.container[].resources.limits.cpu:容器所能使用的最大CPU数量。
spec.container[].resources.requests.memory:容器初始要求的内存数量
spec.container[].resources.limits.memory:容器所能使用的最大内存数量。

1.1 资源计算

Pod的Requests或Limits指该Pod中所有容器的Requests或Limits的总和,若Pod中没有设置Requests或Limits的容器,则该项的值被当作0或者按照集群配置的默认值来计算。
  • 计算CPU

CPU的Requests和Limits是通过CPU数(cpus)来度量的。
CPU的资源值是绝对值,而不是相对值,比如0.1CPU在单核或多核机器上是一样的,都严格等于0.1 CPU core。

  • 计算Memory

内存的Requests和Limits计量单位是字节数。使用整数或者定点整数加上国际单位制来表示内存值。
国际单位制包括十进制的E、P、T、G、M、K、m,或二进制的Ei、Pi、Ti、Gi、Mi、Ki。
KiB与MiB是以二进制表示的字节单位,常见的KB与MB则是以十进制表示的字节单位,比如: 1 KB=1000 Bytes=8000Bits; 1 KiB=2^10 Bytes=1024 Bytes=8192 Bits。

  • 注意事项

计算资源单位大小写敏感,m表示千分之一单位,M表示十进制的1000,二者的含义不同。

1.2 调度机制

基于Requests和Limits的Pod调度机制:

调度器在调度时,首先要确保调度后该节点上所有Pod的CPU和内存的Requests总和,不超过该节点能提供给Pod使用的CPU和Memory的最大容量值。

例如,某个节点上的CPU资源充足,而内存为4GB,其中3GB可以运行Pod,而某Pod的Memory Requests为1GB、Limits为2GB,那么在这个节点上最多可以运行3个这样的Pod。

Requests和Limits的背后机制:

>> kubelet在启动Pod的某个容器时,会将容器的Requests和Limits值转化为相应的容器启动参数传递给容器执行器(Docker或者rkt)。

>> 若容器的执行环境是Docker,那么容器的4个参数传递给Docker的过程如下:
	1. spec.container[].resources.requests.cpu:参数值会被转化为core数(比如配置的100m会转化为0.1),然后乘以1024,再将这个结果作为–cpu-shares参数的值传递给docker run命令。
	2. spec.container[].resources.limits.cpu:参数值会被转化为millicore数(比如配置的1被转化为1000,配置的100m被转化为100),将此值乘以100000,再除以1000,然后将结果值作为–cpu-quota参数的值传递给docker run命令。
	3. spec.container[].resources.requests.memory:参数值只提供给Kubernetes调度器作为调度和管理的依据,不会作为任何参数传递给Docker。
	4. spec.container[].resources.limits.memory:参数值会被转化为单位为Bytes的整数,值作为–memory参数传递给docker run命令。

常见问题分析:

1. 若Pod状态为Pending,错误信息为FailedScheduling。若调度器在集群中找不到合适的节点来运行Pod,那么这个Pod会一直处于未调度状态,直到调度器找到合适的节点为止。每次调度器尝试调度失败时,Kubernetes都会产生一个事件。
2. 容器被强行终止(Terminated)。如果容器使用的资源超过了它配置的Limits,那么该容器可能被强制终止。我们可以通过kubectl describe pod命令来确认容器是否因为这个原因被终止

1.3 服务质量等级

  • Pod的三种QoS级别:
  • Guaranteed(完全可靠的):如果Pod中的所有容器对所有资源类型都定义了Limits和Requests,并且所有容器的Limits值都和Requests值相等(且都不为0),那么该Pod的QoS级别就是Guaranteed。未定义Requests值,所以其默认等于Limits值。 其中定义的Requests与Limits的值完全相同。
  • BestEffort(尽力而为、不太可靠的):如果Pod中所有容器都未定义资源配置(Requests和Limits都未定义),那么该Pod的QoS级别就是BestEffort。
  • Burstable(弹性波动、较可靠的):当一个Pod既不为Guaranteed级别,也不为BestEffort级别时,该Pod的QoS级别就是Burstable。Pod中的一部分容器在一种或多种资源类型的资源配置中定义了Requests值和Limits值(都不为0),且Requests值小于Limits值。Pod中的一部分容器未定义资源配置(Requests和Limits都未定义)。
  • 工作特点:
  • BestEffort:Pod的优先级最低,在这类Pod中运行的进程会在系统内存紧缺时被第一优先“杀掉”。当然,从另一个角度来看,BestEffortPod由于没有设置资源Limits,所以在资源充足时,它们可以充分使用所有闲置资源。
  • Burstable:Pod的优先级居中,这类Pod在初始时会被分配较少的可靠资源,但可以按需申请更多的资源。当然,如果整个系统内存紧缺,又没有BestEffort容器可以被杀掉以释放资源,那么这类Pod中的进程可能被“杀掉”。
  • Guaranteed:Pod的优先级最高,而且一般情况下这类Pod只要不超过其资源Limits的限制就不会被“杀掉”。当然,如果整个系统内存紧缺,又没有其他更低优先级的容器可以被“杀掉”以释放资源,那么这类Pod中的进程也可能会被“杀掉”。

二、资源配额 ResourceQuota

为何会有资源配额?

当多个团队、多个用户共享使用K8s集群时,会出现不均匀资源使用,默认情况下先到先得,这时可以通过ResourceQuota来对命名空间资源使用总量做限制,从而解决这个问题。
  • 使用流程

k8s管理员为每个命名空间创建一个或多个ResourceQuota对象,定义资源使用总量,K8s会跟踪命名空间资源使用情况,当超过定义的资源配额会返回拒绝。

  • 注意事项

如果在集群中新添加了节点,资源配额不会自动更新,该资源配额所对应的命名空间中的对象也不能自动增加资源上限。

2.1 支持的限制资源

  • 资源限制对象

容器资源请求值(requests):命名空间下的所有pod申请资源时设置的requests总和不能超过这个值。
容器资源限制值(limits):命名空间下的所有pod申请资源时设置的limits总和不能超过这个值。

  • 注意事项
  1. CPU单位:可以写m也可以写浮点数,例如0.5=500m,1=1000m;
  2. requests必须小于limits,建议一个理论值:requests值小于limits的20%-30%,一般是limits的70%;
  3. limits尽量不要超过所分配宿主机物理配置的80%,否则没有限制意义;
  4. requests只是一个预留性质,并非实际的占用,用于k8s合理的分配资源(每个节点都有可分配的资源,k8s抽象的将这些节点资源统一分配)。比如requests分配1核1G,在满足的节点上创建完容器后实际资源可能只有0.5C1G;
  5. requests会影响pod调度,k8s只能将pod分配到能满足该requests值的节点上;
  6. ResourceQuota功能是一个准入控制插件,默认已经启用;
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐