5

关于Kubernetes中资源限制的一些笔记整理

 2 years ago
source link: https://liruilongs.github.io/2022/08/06/K8s/%E5%85%B3%E4%BA%8E%20Kubernetes%E4%B8%ADpod%E8%B5%84%E6%BA%90%E9%99%90%E5%88%B6%E7%9A%84%E4%B8%80%E4%BA%9B%E7%AC%94%E8%AE%B0%E6%95%B4%E7%90%86/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

关于Kubernetes中资源限制的一些笔记整理

我们的痛苦来源于“夸父追日”一般的对“更好”的追求,也来自于自己的自卑与狂妄。——–duoduokk


  • 今天和小伙伴们分享K8s中pod资源限制的一些笔记
  • 博文内存涉及pod中通过request和limits实现资源的申请和限制
  • 理解不足小伙伴帮忙指正,生活加油 ^_^

我们的痛苦来源于“夸父追日”一般的对“更好”的追求,也来自于自己的自卑与狂妄。——–duoduokk


学习之前,我们要准备下实验环境,新建一个新的命名空间,并且切换过去

┌──[[email protected]]-[~/ansible]
└─$mkdir resources
┌──[[email protected]]-[~/ansible]
└─$cd resources/
┌──[[email protected]]-[~/ansible/resources]
└─$kubectl create ns resources
namespace/resources created
┌──[[email protected]]-[~/ansible/resources]
└─$kubectl config set-context $(kubectl config current-context) --namespace=resources
Context "kubernetes-admin@kubernetes" modified.
┌──[[email protected]]-[~/ansible/resources]
└─$cd ..
┌──[[email protected]]-[~/ansible]
└─$ansible node -m shell -a "docker pull hub.c.163.com/library/centos"

为什么要资源限制

一般在本地做实验,或者Demo的时候,不会对pod的资源进行限制,只有在生产环境会严格配置pod的资源限制。

当不对pod的资源做限制时,K8s的调度器会认为当前pod所需要的资源很少,并且可以调度到任意节点上,但是这样有一个很严重的弊端,如果不做资源限制,比如拿内存来讲,如果pod中的容器存在内存不回收的情况,那么会无休止的使用宿主节点的内存资源,从而会引发宿主机的OOM,甚至会触发宿主机内核OOM Killer(内存杀手),来保证宿主机不挂掉。

看一个Demo,创建一个没有限制资源的pod

┌──[[email protected]]-[~/ansible/resources]
└─$cat pod-demo.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod-demo
name: pod-demo
spec:
containers:
- image: hub.c.163.com/library/centos
imagePullPolicy: IfNotPresent
name: pod-demo
command: ['sh','-c','sleep 500000']
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}

pod创建成功后,我们可以看到调度到了vms83.liruilongs.github.io

┌──[[email protected]]-[~/ansible/resources]
└─$kubectl get pods -o wide
No resources found in resources namespace.
┌──[[email protected]]-[~/ansible/resources]
└─$vim pod-demo.yaml
┌──[[email protected]]-[~/ansible/resources]
└─$kubectl apply -f pod-demo.yaml
pod/pod-demo created
┌──[[email protected]]-[~/ansible/resources]
└─$kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-demo 1/1 Running 0 42s 10.244.70.50 vms83.liruilongs.github.io <none> <none>

这里我们在pod里安装一个内存分配工具bigmem,用于模拟pod中容器进程内存不回收的情况。

┌──[[email protected]]-[~/ansible]
└─$kubectl cp ./bigmem-7.0-1.r29766.x86_64.rpm pod-demo:/root/
┌──[[email protected]]-[~/ansible]
└─$kubectl exec -it pod-demo -- bin/bash
[root@pod-demo /]# cd root/
[root@pod-demo ~]# ls
anaconda-ks.cfg bigmem-7.0-1.r29766.x86_64.rpm original-ks.cfg
[root@pod-demo ~]# rpm -ivh bigmem-7.0-1.r29766.x86_64.rpm
Preparing... ################################# [100%]
Updating / installing...
1:bigmem-7.0-1.r29766 ################################# [100%]
[root@pod-demo ~]# bigmem 1000M
Attempting to allocate 1000 Mebibytes of resident memory...
Press <Enter> to exit^C
[root@pod-demo ~]# bigmem 2000M
Attempting to allocate 2000 Mebibytes of resident memory...
Killed

通过上下内存信息可以发现,当分配1000M内存时,宿主机用户使用内存增加了1000M,可用内存为117M,当申请内存为2000M时,超出宿主机可用内存, bigmem 2000M命令所在进程直接被kill了。

┌──[[email protected]]-[~/ansible]
└─$ansible vms83.liruilongs.github.io -m shell -a "free -h"
vms83.liruilongs.github.io | CHANGED | rc=0 >>
total used free shared buff/cache available
Mem: 4.4G 2.5G 583M 216M 1.4G 1.4G
Swap: 0B 0B 0B
┌──[[email protected]]-[~/ansible]
└─$ansible vms83.liruilongs.github.io -m shell -a "free -h"
vms83.liruilongs.github.io | CHANGED | rc=0 >>
total used free shared buff/cache available
Mem: 4.4G 3.5G 117M 216M 857M 456M
Swap: 0B 0B 0B

查看宿主机日志 /var/log/messages,可以发现bigmem 所在进程造成OOM。被OOM killer 杀掉了。

┌──[[email protected]]-[~]
└─$cat /var/log/messages | grep -i memory
Aug 10 20:37:27 vms83 kernel: [<ffffffff81186bd6>] out_of_memory+0x4b6/0x4f0
Aug 10 20:37:27 vms83 kernel: Out of memory: Kill process 25143 (bigmem) score 1347 or sacrifice child

如果不对pod做资源限制,他会认为宿主机的资源全是自己的,会无休止的使用,直到宿主机内存不足被OOM killer 直接杀了,为什么会被宿主机杀掉,容器的本质即运行在宿主机上的一个进程组。

通过 top 命令监控 node资源,可以发现由于 OOM的问题, 可能会造成的节点短暂性死机,无法采集同步节点信息。

┌──[[email protected]]-[~/ansible]
└─$kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
vms81.liruilongs.github.io 189m 9% 1816Mi 58%
vms82.liruilongs.github.io 112m 3% 819Mi 17%
vms83.liruilongs.github.io <unknown> <unknown> <unknown> <unknown>

必须对资源进行限制,虽然上面的OOM情况下,杀掉了bigmem进程,但是实际上 OOM Killer 杀进程是不确定的,确定OOM杀手应该杀死哪个进程,内核会为每个进程保持一个运行不良评分,分数越高,进程越有可能被OOM杀手杀死。许多因素被用来计算这个分数。

所以当前节点上的任何一个Pod 进程都有可以能被杀掉。但有些Pod可能担负着很重要的职责,比其他Pod更重要,比如与数据存储相关的、与登录相关的、与查询余额相关的,即使系统资源严重不足,也需要保障这些Pod的存活。

所以Kubernetes中该提供了一些保障机制:

  1. 通过资源限额来确保不同的Pod只能占用指定的资源
  2. 允许集群的资源被超额分配,以提高集群的资源利用率。
  3. 为Pod划分等级,确保不同等级的Pod有不同的服务质量(QoS),资源不足时,低等级的Pod会被清理,以确保高等级的Pod稳定运行。

今天和小伙伴分享的主要第一种方式

Kubernetes集群里的节点提供的资源主要是计算资源,计算资源是可计量的能被申请、分配和使用的基础资源,这使之区别于API资源(API Resources,例如Pod和Services等)。当前Kubernetes集群中的计算资源主要包括CPU、GPU及Memory,绝大多数常规应用是用不到GPU的,因此这里重点介绍CPU与Memory的资源管理问题。

我们知道,一个程序所使用的CPU与Memory是一个动态的量,确切地说,是一个范围,跟它的负载密切相关:负载增加时,CPU和Memory的使用量也会增加。因此最准确的说法是,某个进程的CPU使用量为0.1个CPU~1个CPU,内存占用则为500MB~1GB。对应到Kubernetes的Pod容器上,就是下面这4个参数:

  • spec.container[].resources.requests.cpu
  • spec.container[].resources.limits.cpu
  • spec.container[].resources.requests.memory
  • spec.container[].resources.limits.memory

Request&&limits

在配置Pod时可以通过参数Request为其中的每个容器指定所需使用的CPU与Memory量,类似于一种申请,Kubernetes会根据Request的值去查找有足够资源的Node来调度此Pod,如果没有,则调度失败。pod会一直处于pending

┌──[[email protected]]-[~/ansible/resources]
└─$cat pod-demo-momory.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod-demo
name: pod-demo
spec:
containers:
- image: hub.c.163.com/library/centos
imagePullPolicy: IfNotPresent
name: pod-demo
command: ['sh','-c','sleep 500000']
resources:
requests:
memory: "5000Mi"
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}

当前pod所调度的node只有4.4G内存,所以pod会一直处于pending

┌──[[email protected]]-[~/ansible/resources]
└─$kubectl apply -f pod-demo-momory.yaml
pod/pod-demo created
┌──[[email protected]]-[~/ansible/resources]
└─$kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-demo 0/1 Pending 0 6s
┌──[[email protected]]-[~/ansible/resources]
└─$

limits对应资源量的上限,即最多允许使用这个上限的资源量。

由于CPU资源是可压缩的,进程无论如何也不可能突破上限,因此设置起来比较容易。对于Memory这种不可压缩资源来说,它的Limit设置就是一个问题了,如果设置得小了,当进程在业务繁忙期试图请求超过Limit限制的Memory时,此进程就会被Kubernetes杀掉。因此,Memory的Request与Limit的值需要结合进程的实际需求谨慎设置。

┌──[[email protected]]-[~/ansible/resources]
└─$cat pod-demo-momory.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod-demo
name: pod-demo
spec:
containers:
- image: hub.c.163.com/library/centos
imagePullPolicy: IfNotPresent
name: pod-demo
command: ['sh','-c','sleep 500000']
resources:
requests:
memory: "2000Mi"
limits:
memory: "3000Mi"
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
┌──[[email protected]]-[~/ansible/resources]
└─$vim pod-demo-momory.yaml
┌──[[email protected]]-[~/ansible/resources]
└─$kubectl apply -f pod-demo-momory.yaml
pod/pod-demo created
┌──[[email protected]]-[~/ansible/resources]
└─$kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-demo 1/1 Running 0 12s 10.244.70.55 vms83.liruilongs.github.io <none> <none>
┌──[[email protected]]-[~/ansible/resources]
└─$
┌──[[email protected]]-[~/ansible]
└─$kubectl cp ./bigmem-7.0-1.r29766.x86_64.rpm pod-demo:/root/
┌──[[email protected]]-[~/ansible]
└─$kubectl exec -it pod-demo -- bin/bash
[root@pod-demo /]# cd /root/
[root@pod-demo ~]# rpm -ivh bigmem-7.0-1.r29766.x86_64.rpm
Preparing... ################################# [100%]
Updating / installing...
1:bigmem-7.0-1.r29766 ################################# [100%]
[root@pod-demo ~]# bi
bigmem bind
[root@pod-demo ~]# free -h
total used free shared buff/cache available
Mem: 4.4G 548M 3.1G 216M 818M 3.4G
Swap: 0B 0B 0B
[root@pod-demo ~]# bigmem 3000M
Attempting to allocate 3000 Mebibytes of resident memory...
Killed
[root@pod-demo ~]# bigmem 2000M
Attempting to allocate 2000 Mebibytes of resident memory...
Press <Enter> to exit^C
[root@pod-demo ~]# bigmem 20000M
Attempting to allocate 20000 Mebibytes of resident memory...
Killed
[root@pod-demo ~]# exit
exit
command terminated with exit code 137

可以发现,我们设置了limits 的值,所以由cgroup实现资源隔离来处理内存不够,可以看到顶层的控制组为kubepods.slice,内存不够的时候通过Cgroup 来kill掉进程,而不是通过宿主机内核OOM Killer 来杀

┌──[[email protected]]-[~]
└─$cat /var/log/messages | grep -i memory
Aug 10 21:08:06 vms83 kernel: [<ffffffff81186c24>] pagefault_out_of_memory+0x14/0x90
Aug 10 21:08:06 vms83 kernel: memory: usage 3072000kB, limit 3072000kB, failcnt 2760
Aug 10 21:08:06 vms83 kernel: memory+swap: usage 3072000kB, limit 9007199254740988kB, failcnt 0
Aug 10 21:08:06 vms83 kernel: Memory cgroup stats for /kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod804e1f6c_d5c0_4f8a_aa27_bcd66393087c.slice: cache:0KB rss:0KB rss_huge:0KB mapped_file:0KB swap:0KB inactive_anon:0KB active_anon:0KB inactive_file:0KB active_file:0KB unevictable:0KB
Aug 10 21:08:06 vms83 kernel: Memory cgroup stats for /kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod804e1f6c_d5c0_4f8a_aa27_bcd66393087c.slice/docker-bf3af784f917c54a50d0cb422d8f2624be3ba65a904e126e89081817d457c4d4.scope: cache:0KB rss:40KB rss_huge:0KB mapped_file:0KB swap:0KB inactive_anon:0KB active_anon:40KB inactive_file:0KB active_file:0KB unevictable:0KB
Aug 10 21:08:06 vms83 kernel: Memory cgroup stats for /kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod804e1f6c_d5c0_4f8a_aa27_bcd66393087c.slice/docker-80f5aff910f2d6e0203fb6fc871cec9bf1d358d7e06ab9d4a381e46bac311465.scope: cache:0KB rss:3071960KB rss_huge:0KB mapped_file:0KB swap:0KB inactive_anon:0KB active_anon:3071912KB inactive_file:0KB active_file:0KB unevictable:0KB
Aug 10 21:08:06 vms83 kernel: Memory cgroup out of memory: Kill process 47482 (bigmem) score 1561 or sacrifice child
Aug 10 21:09:11 vms83 kernel: [<ffffffff81186c24>] pagefault_out_of_memory+0x14/0x90
Aug 10 21:09:11 vms83 kernel: memory: usage 3072000kB, limit 3072000kB, failcnt 2770
Aug 10 21:09:11 vms83 kernel: memory+swap: usage 3072000kB, limit 9007199254740988kB, failcnt 0
Aug 10 21:09:11 vms83 kernel: Memory cgroup stats for /kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod804e1f6c_d5c0_4f8a_aa27_bcd66393087c.slice: cache:0KB rss:0KB rss_huge:0KB mapped_file:0KB swap:0KB inactive_anon:0KB active_anon:0KB inactive_file:0KB active_file:0KB unevictable:0KB
Aug 10 21:09:11 vms83 kernel: Memory cgroup stats for /kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod804e1f6c_d5c0_4f8a_aa27_bcd66393087c.slice/docker-bf3af784f917c54a50d0cb422d8f2624be3ba65a904e126e89081817d457c4d4.scope: cache:0KB rss:40KB rss_huge:0KB mapped_file:0KB swap:0KB inactive_anon:0KB active_anon:40KB inactive_file:0KB active_file:0KB unevictable:0KB
Aug 10 21:09:11 vms83 kernel: Memory cgroup stats for /kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod804e1f6c_d5c0_4f8a_aa27_bcd66393087c.slice/docker-80f5aff910f2d6e0203fb6fc871cec9bf1d358d7e06ab9d4a381e46bac311465.scope: cache:0KB rss:3071960KB rss_huge:0KB mapped_file:0KB swap:0KB inactive_anon:0KB active_anon:3071948KB inactive_file:0KB active_file:0KB unevictable:0KB
Aug 10 21:09:11 vms83 kernel: Memory cgroup out of memory: Kill process 48483 (bigmem) score 1561 or sacrifice child

如果不设置CPU或Memory的Limit值,会怎样呢?(不考虑上面的问题)

在这种情况下,该Pod的资源使用量有一个弹性范围,我们不用绞尽脑汁去思考这两个Limit的合理值,但问题也来了,考虑下面的例子:

Pod A的Memory Request被设置为1GB,NodeA当时空闲的Memory为1.2GB,符合PodA的需求,因此PodA被调度到NodeA上。运行3天后,PodA的访问请求大增,内存需要增加到1.5GB,此时NodeA的剩余内存只有200MB,由于PodA新增的内存已经超出系统资源,所以在这种情况下,PodA就会被Kubernetes杀掉。

没有设置Limit的Pod,或者只设置了CPULimit或者Memory Limit两者之一的Pod,表面看都是很有弹性的,但实际上,相对于4个参数都被设置的Pod,是处于一种相对不稳定的状态的。

CPU和内存这两种计算资源的特点进行说明。

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

  2. Memory 内存的Requests和Limits计量单位是字节数。使用整数或者定点整数加上国际单位制(International System of Units)来表示内存值。国际单位制包括十进制的E、P、T、G、M、K、m,或二进制的Ei、Pi、Ti、Gi、Mi、Ki。KiB与MiB是以二进制表示的字节单位,常见的KB与MB则是以十进制表示的字节单位,Kubernetes的计算资源单位是大小写敏感的

官方文档的一些描述

如果你没有指定内存限制

如果你没有为一个容器指定内存限制,则自动遵循以下情况之一:

  • 容器可无限制地使用内存。容器可以使用其所在节点所有的可用内存, 进而可能导致该节点调用 OOM Killer。 此外,如果发生 OOM Kill,没有资源限制的容器将被杀掉的可行性更大。

  • 运行的容器所在命名空间有默认的内存限制,那么该容器会被自动分配默认限制。 集群管理员可用使用 LimitRange 来指定默认的内存限制。

内存请求和限制的目的

通过为集群中运行的容器配置内存请求和限制,你可以有效利用集群节点上可用的内存资源。 通过将 Pod 的内存请求保持在较低水平,你可以更好地安排 Pod 调度。 通过让内存限制大于内存请求,你可以完成两件事:

  • Pod 可以进行一些突发活动,从而更好的利用可用内存。
  • Pod 在突发活动期间,可使用的内存被限制为合理的数量。

Recommend

  • 3
    • luckymrwang.github.io 2 years ago
    • Cache

    Kubernetes 内存资源限制实战

    Kubernetes 内存资源限制实战 Kubernetes 对内存资源的限制实际上是通过 cgroup 来控制的,cgroup 是容器的一组用来控制内核如何运行进程的相关属性集合。针对内存、CPU 和各种设备都有对应的 cgroup。cgr...

  • 9

    通过本文,我们将学习如何从头开始重新创建 Kubernetes RBAC 授权模型,并了解Roles、ClusterRoles、ServiceA...

  • 12

    1.什么是资源限制? 1.1在kubernetes集群中,为了使得系统能够稳定的运行,通常会对Pod的资源使用量进行限制。在kubernetes集群中,如果有一个程序出现异常,并且占用大量的系统资源,如果没有对该Pod进行资源限制的话,可能会影响其...

  • 6

    关于K8s中资源服务质量管理Resource Qos的一些笔记整理 精神的寓所是我们的,不是阴曹地府,不是天上星辰,这两者都是活在我们之中的精神所制作的。 —-《作为意志和表象的事件》 分享一些 K8s中资源服务质量管理

  • 4
    • liruilongs.github.io 2 years ago
    • Cache

    关于 Linux 中 firewalld 的一些笔记整理

    关于 Linux 中 firewalld 的一些笔记整理 傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。——–王小波...

  • 8
    • liruilongs.github.io 2 years ago
    • Cache

    关于Linux 网络抓包的一些笔记整理

    关于Linux 网络抓包的一些笔记整理 这世界的存在完全只是就它对一个其他事物的,一个进行 “表象者” 的关系来说的,这个进行 “表象者” 就是人自己 —–《作为意志和表象的世界》(第一篇 世界作为表象初论) 遇到一个...

  • 5

    关于Linux下HAProxy自动化部署的一些笔记整理 傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。——–王小波

  • 7
    • liruilongs.github.io 2 years ago
    • Cache

    关于Git分支高级合并的一些笔记整理

    关于Git分支高级合并的一些笔记整理 傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。——–王小波

  • 10
    • liruilongs.github.io 2 years ago
    • Cache

    关于 K8s 中 Open Kruise 的一些笔记整理

    关于 K8s 中 Open Kruise 的一些笔记整理 对每个人而言,真正的职责只有一个:找到自我。然后在心中坚守其一生,全心全意,永不停息。所有其它的路都是不完整的,是人的逃避方式,是对大众理想的懦弱回归,是随波逐流,是对内心的恐惧 ——赫尔曼·黑...

  • 12

    Ceph:关于Linux Ceph 存储架构的一些笔记整理 对每个人而言,真正的职责只有一个:找到自我。然后在心中坚守其一生,全心全意,永不停息。所有其它的路都是不完整的,是人的逃避方式,是对大众理想的懦弱回归,是随波逐流,是对内心的恐惧 ——赫尔...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK