Kubernetes下pod控制组管理解析

开始之前我们先了解下Kubernetes QoS概念

Kubernetes里面,将资源分成不同的QoS类别,并且通过pod里面的资源定义来区分pod对于平台提供的资源保障的SLA等级:

  • Guaranteed: pod中每个容器都为CPU和内存设置了相同的requestslimits,此类pod具有最高优先级
  • Burstable: 至少有一个容器设置了CPU或内存的requests属性,但不满足Guaranteed类别要求的pod,它们具有中等优先级
  • BestEffort: 未为任何一个容器设置requestslimits属性的pod,它们的优先级为最低级别

针对不同的优先级的业务,在资源紧张或者超出的时候会有不同的处理策略。
同时,针对CPU和内存两类不同类型的资源,一种是可压缩的,一种是不可压缩的,所以资源的分配和调控策略也会有很大区别。

CPU资源紧缺时,如果节点处于超卖状态,则会根据各自的requests配置,按比例分配CPU时间片,而内存资源紧缺时需要内核的oom killer进行管控,
Kubernetes负责为OOM killer提供管控依据:

  1. BestEfford类容器由于没有要求系统供任何级别的资源保证,将最先被终止;但是在资源不紧张时,它们能尽可能多地占用资源,实现资源的复用和部署密度的提高
  2. 如果BestEfford类容器都已经终止,Burstable中等优先级的的pod将被终止
  3. Guaranteed类容器拥有最高优先级,只有在内存资源使用超出limits的时候或者节点OOM时得分最高,才会被终止;

OOM得分主要根据QoS类和容器的requests内存占机器总内存比来计算:

oom-score.png

OOM得分越高,该进程的优先级越低,越容易被终止;根据公式,Burstable优先级的pod中,requests内存申请越多,越容易在OOM的时候被终止。

pod的cpu控制组解析

首先我们先看下pod的控制组层级

$ ls -l /sys/fs/cgroup/cpu/kubepods.slice
total 0
-rw-r--r--  1 root root 0 Aug 23 16:32 cgroup.clone_children
-rw-r--r--  1 root root 0 Aug 23 16:32 cgroup.procs
-r--r--r--  1 root root 0 Aug 23 16:32 cpuacct.stat
-rw-r--r--  1 root root 0 Aug 23 16:32 cpuacct.usage
-r--r--r--  1 root root 0 Aug 23 16:32 cpuacct.usage_all
-r--r--r--  1 root root 0 Aug 23 16:32 cpuacct.usage_percpu
-r--r--r--  1 root root 0 Aug 23 16:32 cpuacct.usage_percpu_sys
-r--r--r--  1 root root 0 Aug 23 16:32 cpuacct.usage_percpu_user
-r--r--r--  1 root root 0 Aug 23 16:32 cpuacct.usage_sys
-r--r--r--  1 root root 0 Aug 23 16:32 cpuacct.usage_user
-rw-r--r--  1 root root 0 Aug 23 16:32 cpu.cfs_period_us
-rw-r--r--  1 root root 0 Aug 23 16:32 cpu.cfs_quota_us
-rw-r--r--  1 root root 0 Aug 23 16:32 cpu.rt_period_us
-rw-r--r--  1 root root 0 Aug 23 16:32 cpu.rt_runtime_us
-rw-r--r--  1 root root 0 Sep  1 17:38 cpu.shares
-r--r--r--  1 root root 0 Aug 23 16:32 cpu.stat
drwxr-xr-x 55 root root 0 Aug 23 16:32 kubepods-besteffort.slice
drwxr-xr-x 51 root root 0 Aug 23 16:32 kubepods-burstable.slice
drwxr-xr-x  4 root root 0 Aug 23 16:54 kubepods-pod934b0aa2_1d1b_4a81_bfcf_89c4beef899e.slice
drwxr-xr-x  4 root root 0 Aug 23 16:39 kubepods-podca849e84_aa86_4402_bf31_e7e73faa77fe.slice
-rw-r--r--  1 root root 0 Aug 23 16:32 notify_on_release
-rw-r--r--  1 root root 0 Aug 23 16:32 tasks

其中kubepods-besteffort.slice存放besteffort类型pod控制组配置,kubepods-burstable.slice存放burstable类型pod控制组配置。

kubepods-pod934b0aa2_1d1b_4a81_bfcf_89c4beef899e.slicekubepods-podca849e84_aa86_4402_bf31_e7e73faa77fe.slice则为Guaranteed类型pod

为了更好的解释说明,我们创建一个新的Guaranteed类型的pod用于测试:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: nginx-demo
spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        cpu: "1"
        memory: 1Gi
      requests:
        cpu: 1
        memory: 1Gi
EOF
  1. 再次查看/sys/fs/cgroup/cpu/kubepods.slice下,发现新增了一个kubepods-podf56bf66f_3efb_4c80_8818_37de69ee5b72.slice目录

  2. 名称解析

kubepods-podf56bf66f_3efb_4c80_8818_37de69ee5b72.slice这个名称是怎么命名的呢?

命名格式为:kubepods-pod<pod uid>.slice,并且会将uid-转换为_

$ kubectl get pod nginx-demo -o yaml|grep uid
  uid: f56bf66f-3efb-4c80-8818-37de69ee5b72
  1. 目录解析
$ ls -l /sys/fs/cgroup/cpu/kubepods.slice/kubepods-podf56bf66f_3efb_4c80_8818_37de69ee5b72.slice
-rw-r--r-- 1 root root 0 Nov 17 11:23 cgroup.clone_children
-rw-r--r-- 1 root root 0 Nov 17 11:23 cgroup.procs
-r--r--r-- 1 root root 0 Nov 17 11:23 cpuacct.stat
-rw-r--r-- 1 root root 0 Nov 17 11:23 cpuacct.usage
-r--r--r-- 1 root root 0 Nov 17 11:23 cpuacct.usage_all
-r--r--r-- 1 root root 0 Nov 17 11:23 cpuacct.usage_percpu
-r--r--r-- 1 root root 0 Nov 17 11:23 cpuacct.usage_percpu_sys
-r--r--r-- 1 root root 0 Nov 17 11:23 cpuacct.usage_percpu_user
-r--r--r-- 1 root root 0 Nov 17 11:23 cpuacct.usage_sys
-r--r--r-- 1 root root 0 Nov 17 11:23 cpuacct.usage_user
-rw-r--r-- 1 root root 0 Nov 17 11:23 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 Nov 17 11:23 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 Nov 17 11:23 cpu.rt_period_us
-rw-r--r-- 1 root root 0 Nov 17 11:23 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 Nov 17 11:23 cpu.shares
-r--r--r-- 1 root root 0 Nov 17 11:23 cpu.stat
drwxr-xr-x 2 root root 0 Nov 17 11:23 docker-08974ffd61043b34e4cd5710d5446eb423c6371afb4c9d106e608f08cc1182a3.scope
drwxr-xr-x 2 root root 0 Nov 17 11:24 docker-d33dc12340fd32b35148293c21f84dab14f2274046056bbeef9e9666d1d0dc2a.scope
-rw-r--r-- 1 root root 0 Nov 17 11:23 notify_on_release
-rw-r--r-- 1 root root 0 Nov 17 11:23 tasks

我们发现怎么有两个容器呢?(docker-08974ffd61043b34e4cd5710d5446eb423c6371afb4c9d106e608f08cc1182a3.scopedocker-d33dc12340fd32b35148293c21f84dab14f2274046056bbeef9e9666d1d0dc2a.scope

其实是业务容器 + infra沙箱容器,并且命名格式遵循:docker-<container id>.scope

$ docker ps|grep nginx
d33dc12340fd   nginx                                                                         "/docker-entrypoint.…"    7 minutes ago   Up 7 minutes             k8s_nginx_nginx-demo_default_f56bf66f-3efb-4c80-8818-37de69ee5b72_0
08974ffd6104   harbor.chs.neusoft.com/kubesphere/pause:3.2                                   "/pause"                  8 minutes ago   Up 8 minutes             k8s_POD_nginx-demo_default_f56bf66f-3efb-4c80-8818-37de69ee5b72_0

我们可根据以下命令获取业务容器id

$ kubectl get pod nginx-demo -o yaml|grep containerID
  - containerID: docker://d33dc12340fd32b35148293c21f84dab14f2274046056bbeef9e9666d1d0dc2a
  1. 业务容器cgroup解析
$ cd /sys/fs/cgroup/cpu/kubepods.slice/kubepods-podf56bf66f_3efb_4c80_8818_37de69ee5b72.slice/docker-d33dc12340fd32b35148293c21f84dab14f2274046056bbeef9e9666d1d0dc2a.scope
$ ls -l 
total 0
-rw-r--r-- 1 root root 0 Nov 17 11:24 cgroup.clone_children
-rw-r--r-- 1 root root 0 Nov 17 11:24 cgroup.procs
-r--r--r-- 1 root root 0 Nov 17 11:24 cpuacct.stat
-rw-r--r-- 1 root root 0 Nov 17 11:24 cpuacct.usage
-r--r--r-- 1 root root 0 Nov 17 11:24 cpuacct.usage_all
-r--r--r-- 1 root root 0 Nov 17 11:24 cpuacct.usage_percpu
-r--r--r-- 1 root root 0 Nov 17 11:24 cpuacct.usage_percpu_sys
-r--r--r-- 1 root root 0 Nov 17 11:24 cpuacct.usage_percpu_user
-r--r--r-- 1 root root 0 Nov 17 11:24 cpuacct.usage_sys
-r--r--r-- 1 root root 0 Nov 17 11:24 cpuacct.usage_user
-rw-r--r-- 1 root root 0 Nov 17 11:24 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 Nov 17 11:24 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 Nov 17 11:24 cpu.rt_period_us
-rw-r--r-- 1 root root 0 Nov 17 11:24 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 Nov 17 11:24 cpu.shares
-r--r--r-- 1 root root 0 Nov 17 11:24 cpu.stat
-rw-r--r-- 1 root root 0 Nov 17 11:24 notify_on_release
-rw-r--r-- 1 root root 0 Nov 17 11:24 tasks

我们上述对pod配额的定义为:

resources:
  limits:
    cpu: "1"
    memory: 1Gi
  requests:
    cpu: 1
    memory: 1Gi

其实等同于以以下方式启动docker容器:

$ docker run --rm -dt --cpu-shares=1024 --cpu-quota=1024 --memory=1g nginx

我们可以看下docker容器的配额:

$ docker inspect d33dc12340fd32b35148293c21f84dab14f2274046056bbeef9e9666d1d0dc2a -f {{.HostConfig.CpuShares}}
1024
$ docker inspect d33dc12340fd32b35148293c21f84dab14f2274046056bbeef9e9666d1d0dc2a -f {{.HostConfig.CpuQuota}}
100000
$ docker inspect d33dc12340fd32b35148293c21f84dab14f2274046056bbeef9e9666d1d0dc2a -f {{.HostConfig.CpuPeriod}}
100000

.HostConfig.CpuShares对应控制内的cpu.shares文件内容
.HostConfig.CpuPeriod对应控制内的cpu.cpu.cfs_period_us文件内容
.HostConfig.CpuQuota对应控制内的cpu.cfs_quota_us文件内容

并且我们发现k8s基于pod管理控制组(同一pod内的容器所属同一控制组)

"CgroupParent": "kubepods-podf56bf66f_3efb_4c80_8818_37de69ee5b72.slice",

我们可以得出记录:k8s通过控制组的cpu.sharescpu.cpu.cfs_period_uscpu.cfs_quota_us配置,达到限制CPU的目的。

那么这三个文件是用来干嘛的?

cpu.shares解析

  1. cpu.shares用来设置CPU的相对值,并且是针对所有的CPU(内核),默认值是1024等同于一个cpu核心。
    CPU Shares将每个核心划分为1024个片,并保证每个进程将按比例获得这些片的份额。如果有1024个片(即1核),并且两个进程设置cpu.shares均为1024,那么这两个进程中每个进程将获得大约一半的cpu可用时间。

当系统中有两个cgroup,分别是ABAshares值是1024,B 的shares值是512
那么A将获得1024/(1024+512)=66%CPU资源,而B将获得33%CPU资源。shares有两个特点:

  • 如果A不忙,没有使用到66%CPU时间,那么剩余的CPU时间将会被系统分配给B,即BCPU使用率可以超过33%
  • 如果添加了一个新的cgroup C,且它的shares值是1024,那么A的限额变成了1024/(1024+512+1024)=40%B的变成了20%

从上面两个特点可以看出:

在闲的时候,shares基本上不起作用,只有在CPU忙的时候起作用,这是一个优点。

由于shares是一个绝对值,需要和其它cgroup的值进行比较才能得到自己的相对限额,而在一个部署很多容器的机器上,cgroup的数量是变化的,所以这个限额也是变化的,自己设置了一个高的值,但别人可能设置了一个更高的值,所以这个功能没法精确的控制CPU使用率。

  1. cpu.shares对应k8s内的resources.requests.cpu字段:

值对应关系为:resources.requests.cpu * 1024 = cpu.shares

如:resources.requests.cpu为3的时候,cpu.shares值为3072resources.requests.cpu100m的时候,cpu.shares值为102

cpu.cpu.cfs_period_uscpu.cfs_quota_us解析

  1. cpu.cfs_period_us用来配置时间周期长度,cpu.cfs_quota_us用来配置当前cgroup在设置的周期长度内所能使用的CPU时间数。
    两个文件配合起来设置CPU的使用上限。两个文件的单位都是微秒(us),cfs_period_us的取值范围为1毫秒(ms)到1秒(s),cfs_quota_us的取值大于1ms即可,如果cfs_quota_us的值为-1(默认值),表示不受cpu时间的限制。

  2. cpu.cpu.cfs_period_uscpu.cfs_quota_us对应k8s中的resources.limits.cpu字段:

resources.limits.cpu = cpu.cfs_quota_us/cpu.cfs_period_us

并且k8s下容器控制组的cpu.cpu.cfs_period_us值固定为100000,实际只设置cpu.cfs_quota_us

例如:

cpu.cpu.cfs_period_us100000(单位微妙,即0.1秒),cpu.cfs_quota_us500000(单位微妙,即0.5秒)时,resources.limits.cpu为5,即5个cpu核心。
cpu.cpu.cfs_period_us100000(单位微妙,即0.1秒),cpu.cfs_quota_us10000(单位微妙,即0.01秒)时,resources.limits.cpu为0.1(或100m),即0.1个cpu核心。

pod的内存控制组解析

cpu不同,k8spod容器的requests.memory在控制组内没有对应的属性,未起到限制作用,只是协助k8s调度计算。
pod容器的limits.memory对应控制组里的memory.limit_in_bytes值。

总结

  1. k8s基于pod管理控制组,同一pod内的容器所属同一控制组,并且每个控制组内包含一个infra沙箱容器

  2. k8s基于.spec.containers[x].resourcespod划分了三种类型,对应控制组路径如下:

Pod类型 描述 控制组
Guaranteed 内存与CPU设置了相同的requests和limits /sys/fs/cgroup/<subsystem>/kubepods.slice/kubepods-pod<pod uid>.slice
Burstable 至少有一个容器设置了CPU或内存的requests属性 /sys/fs/cgroup/<subsystem>/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod<pod uid>.slice
BestEffort 所有容器均未设置requests和limits /sys/fs/cgroup/<subsystem>/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod<pod uid>.slice
  1. 控制组中cpu.shares对应k8s内的resources.requests.cpu字段,值对应关系为:
resources.requests.cpu * 1024 = cpu.shares
  1. 控制组中cpu.cpu.cfs_period_uscpu.cfs_quota_us对应k8s中的resources.limits.cpu字段,值对应关系为:
resources.limits.cpu = cpu.cfs_quota_us/cpu.cfs_period_us
  1. 控制组里的memory.limit_in_bytes对应k8s中的resources.limits.memory

参考文章

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 1.Etcd的容量 集群的节点数的多少除了要顾及性能压力外,还要考虑etcd的存储容量。可以反向的从内存大小去推断...
    doublegao阅读 392评论 0 2
  • kubernetes 中的 Qos QoS(Quality of Service) 即服务质量,QoS 是一种控制...
    田飞雨阅读 975评论 6 4
  • 在内存管理篇,我们研究了Kubernetes(K8s)requests和limits的资源含义,以及Docker容...
    吕信阅读 2,649评论 0 2
  • Pod 资源管理主要有两个指标:CPU Request与Memory Request。 在未定义指标时,K8s任务...
    ZYvette阅读 780评论 0 2
  • k8s是云时代的“操作系统”,对于k8s的理解,我们可以对照操作系统来学习理解。本篇我们对schduler组件进行...
    Wu杰语阅读 686评论 0 0