Kubernetes 源码 (15) 计算资源管理

Submitted by Lizhe on Thu, 07/16/2020 - 03:11

先来说一下这个话题的重要性,如果创建pod时不对 容器 的资源进行限制,很可能会发生以下情况

某个 container 在 某个时刻 消耗光了所有的 cpu 时间或者 node 的内存,造成 kubelet 进程本身无响应或者是 node 心跳停止

此时,master 会认为这个 node 节点已经下线,然后会导致这个node上所有的pod开始向其他node节点迁移

 

在创建一个pod时,可以指定 容器对cpu和内存的资源请求量 和 限制量
这里所有的配置都是对于 容器 生效的,并不是对 pod。pod 使用的资源是 它所运行的所有容器的资源总和

 

对于 cpu 资源

Request 表现出来的是 Cgroups 中的进程在 CFS 调度器上的 cpu.shares,而 Limit 则是 CFS 上的带宽限制

简而言之,request 和 docker 本身的 cpu 资源分配原理一样,是按照使用百分比分配的,例如

容器A 和 容器B 按照 1:4 分配,那么当两个容器满载时,容器A最高可以使用20%的cpu资源,容器B最高可以使用80%的cpu资源

但是如果只有容器A自己工作,它几乎可以得到100%的cpu资源

Limits 表现出来的是 cpu.cfs_period_us和cpu.cfs_quota_us属性

cpu.cfs_period_us: 设定时间周期(单位为微秒(μs)), 必须与 cfs_quota_us 配合使用。
cpu.cfs_quota_us : 设定周期内最多可使用的时间(单位为微秒(μs))。 这里的配置指 task对单个 cpu 的使用上限。

例如要设置成限制为 50%

将 cpu.cfs_quota_us 设为 50000,相对于 cpu.cfs_period_us 的 100000 是 50%

 

实验环境,总之我一共有2个node,一共4个内核,16GB内存

20200716043604

 

实验一

如果部署一个nginx,设置cpu最大需求2.5个内核,这里 2.5 个内核超过了单个 node 的2个内核,但是还在整个集群的4个内核之内

结论是,分配不了,不能夸node使用内核

20200716045431

 

我们把cpu request 改到 1.5 , 可以看到 有一个 node 的cpu 占用变成了 1.9,并且 pod 正确被创建了

20200716051238

 

我们再来试一下内存的情况,设置内存到 10GB,也是超出了单个node,但是没有超出集群的全部内存

结论跟cpu是一样的,pod分配失败

20200716052037

内存 request 改成 7GB 之后,pod 被成功创建了

然后其中一个node的内存也被吃满了

20200716052440

 


 

实验二

limits的超卖,先试试cpu,我们安装一个 cpu burn 应用,用来消耗cpu

在毫无限制的情况下,可以看到 只有一个 node 的cpu占用率达到了 100%,并且这个node上的两个 cpu 内核都被占用了 100%

20200716062516

 

接下来我对cpu限制到 0.5个内核 (500m),可以看到基本上占用率降到了 25% , 也就是说 持有2个内核的 node一共有2000个微核,使用了500个

20200716063521

 

设置成1000个微核,占用率是50%

20200716071301

 

设置成 2000个微核,也就是吃满一个node

20200716065411

 

设置成3000,超过了一个node的容量,也就是说 超卖,可以看到实际上 cpu burn 还是只能消耗掉一个node的2个内核,并不能横跨多个node使用cpu

20200716071818

 

最后我们变态一点,把上限设置成 30 个内核,这已经完全超出了当前集群的所有资源,仍然是只有一个node被吃满了

20200716072137

 

 


 

 

实验三 

如果只设置 limits,那么requests 会和 limit 一致

20200716072454

20200716072559

 

内存的情况也是如此

20200716073051

20200716073058

 

 

在 rancher 中,如果你修改了deployment 的 yaml 像这样 ,只设置了 limits

20200716073418

在pod的yaml中你可以看到,pod被自动添加了 request

20200716073535

 


 

实验四

对 namespace 设置限额

先设置limit 到 500微核,2G 内存

20200716074214

然后我们把 cpu burn的 配额设置成

        resources:
          limits:
            cpu: 1000m
            memory: 3Gi

也就是说,命名空间说 你最大 只能使用 500m cpu 和 2G 内存,

在仅仅是重启了 pod,或者是 redeploy 的情况下,原来创建的pod似乎没有受到影响,配额是按照 pod 的设置运行的

20200716074530

重新部署之后仍然没有影响

20200716074928

 

如果我们把 deployment 的 yaml 中的资源限制拿掉

20200716075221

 

此时好玩的事情发生了,namespace的配置虽然没有对 deployment生效,但是在 deployment没有设置 limit的情况下,对 pod 生效了

可以看到pod默认被配置了 限额,然后cpu占用率也对上了

20200716075511

20200716075359

 

那么此时如果我把 pod 的数量改成 3个 拷贝,是否可以看到 cpu 占用率变成 500*3 / 2000 = 75% 呢

20200716075704

确实是这样的,其中两个pod 吃掉了一个 node 的 1000 也就是50%,另一个pod 吃掉了 另一个node 的 500 也就是25%

20200716075757

 


 

 

实验五

关于内存 超卖

首先我们部署一个 tomcat ,看一下占用了 63.81m 内存

20200717100111

我尝试把内存分配成

        resources:
          limits:
            cpu: 500m
            memory: 30Mi

出现了 OOMKilled 

20200717100746

内存当然可以超卖

        resources:
          requests:
            cpu: 500m
            memory: 100Mi
          limits:
            cpu: 500m
            memory: 100Gi

不过实际上超卖的内存,和没有限制的随意使用是一样的,如果程序运行时使用了过大的内存,还是会出现OOM