前言
环境:k8s-v1.22.17 docker-20.10.9 centos-7.9
目录
- 前言
- 什么是可计算资源
- CPU、Memory计量单位
- pod资源请求、限额方式
- pod定义requests、limits
- 查看节点资源情况
- pod使用request、limits示例
- LimitRange限制命名空间下的pod的资源配额
- Qos服务质量等级
- 资源配额管理 Resource Quotas
- 总结
什么是可计算资源
CPU、GPU、Memory等都是计算资源,所谓计算资源,就是可计量的、能被申请的、能被分配使用的资源。
CPU在容器技术中属于可压缩资源,因此,pod对CPU的使用超过其cpu.limit限制一般不会导致容器被系统"杀死",而Memory属于不可压缩资源,当容器使用的memory超过其memory.limit限制时,系统将可能会"杀掉"容器,这就是常见的OOM(out of memory)异常,如果该容器的重启策略是always,则kubelet将会重启该容器,因此评估好pod的memory.limit是一个重要的事情。
CPU、Memory计量单位
CPU:CPU的request和limits是通过cpu核数(cpus)来度量的,单位是m(milliunit),数量可以为整数或小数,如0.1m、50m,CPU的资源是绝对值而不是相对值,比如0.1CPU在单核或多核上是一样的,都严格等于0.1 CPU core。m,milliunit代表“千分之一核心”,譬如50m的含义是指50/1000核心,即5%
Memory:内存的计量单位是字节Byte,Byte是由8个位组成的一个单元,也就是1 Byte = 8 bit。pod的内存requests或limits都是使用整数加上国际单位制来表示内存值,国际单位制可以是
十进制的E、P、T、G、M、K、m或二进制的Ei、Pi、Gi、Mi、Ki。
常见的KiB和MiB是以二进制表示的字节单位,KB和MB是以十进制表示的字节单位。
十进制:1 KB = 1000 Byte = 8000 bit
二进制:1 KiB = 2的10次方 Byte = 1024 Byte = 8192 bit
Mi:1Mi = 1024乘1024,而平时使用的单为M是1M = 1000乘1000
memory:内存大小,可以使用Gi、Mi、G、M等单位
cpu的单位m:
注意:Gi和G,Mi和M优点区别,官网解释:Mi表示(1Mi=1024×1024),M表示(1M=1000×1000)(其它单位类推, 如Ki/K Gi/G)
pod资源请求、限额方式
在k8s中,全面限制一个应用及其中的pod所能占用的资源配额,具体可以使用下面三种方式:
1、定义每个pod的资源配额相关参数,如CPU/memory的request、limits;
2、自动为每个没有定义资源配额的pod添加资源配额模板(LimitRange);
3、从总量上限制一个租户(namespace)应用所能使用的资源配额(ResourceQuota)
pod的request、limits是指pod中所有容器的request、limits的总和,对于没有设置request、limits的容器,该值为0或者按照集群配置的默认值计算;
LimiteRang正是用于解决了没有设置配额参数的pod的默认资源配额问题;
REsourceQuota则约束租户的资源总量配额问题。
pod定义requests、limits
pod可以定义资源配额的相关参数:
spec.container[].resources.requests.cpu:容器初始要求的CPU数量
spec.container[].resources.limits.cpu:容器所能使用的最大CPU数量
spec.container[].resources.requests.memory:容器初始要求的内存数量
spec.container[].resources.limits.memory:容器所能使用的最大内存数量
默认情况下,pod中只写requests(cpu和memory写其中一个或两个都写)不写limits,则默认没有最大资源限制;
pod中只写limits.cpu、limits.memory,不写requests.cpu、requests.memory,默认的requests的cpu、memory其值等于对应的limits的cpu、memory值;
pod中只写limits的cpu或memory其中的一个,则requests对应的也等价于limits的对应的一个值。如只写limits.cpu,则requests.cpu值=limits.cpu值,limits.memory没写则requests.memory也没有值。
requests和limits背后的机制
如果容器运行时是docker,那么pod的requests和limits归根结底还是要转换为docker run启动容器的参数,对应如下:
spec.container[].resources.requests.cpu docker run --cpu-shares
spec.container[].resources.limits.cpu docker run --cpu-period
spec.container[].resources.requests.memory 无,请求内存只会作为调度器的参考,不会作为如何参数传递给docker run
spec.container[].resources.limits.memory docker run --memory
查看节点资源情况
kubectl describe node master01 :可以查看节点的计算资源总量和已分配量
pod使用request、limits示例
kubectl create ns nginx #创建命名空间
vim nginx-test.yaml #创建pod,pod包含2个容器
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-test
namespace: nginx-test
spec:
........
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: nginx-test-1
resources: #定义资源请求、资源限制
requests: #资源请求
memory: "20Mi" #内存请求
cpu: "30m" #CPU请求
limits: #资源限制
memory: "50Mi" #内存限制
cpu: "50m" #CPU限制
ports:
- containerPort: 80
name: nginx
- image: tomcat
imagePullPolicy: IfNotPresent
name: tomcat-test-2
resources: #定义资源请求、资源限制
requests: #资源请求
memory: "10Mi" #内存请求
cpu: "20m" #CPU请求
limits: #资源限制
memory: "40Mi" #内存限制
cpu: "40m" #CPU限制
ports:
- containerPort: 8080
name: tomcat
#查看pod占用的资源情况
[root@master ~]# kubectl describe node node2 | grep -C10 nginx-test-7d448999cb-mxq6s
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age
--------- ---- ------------ ---------- --------------- ------------- ----
nginx-test nginx-test-7d448999cb-mxq6s 50m (1%) 90m (2%) 30Mi (1%) 90Mi (4%) 6m31s
可以看到,我们创建的pod一共请求50m的CPU,30Mi的内存,最大CPU限制为90m,最大内存限制为90Mi
LimitRange限制命名空间下的pod的资源配额
前面我们讨论了pod中可以手动定义requests.cpu、requests.memory、limits.cpu、limits.memory参数实现pod的资源请求和资源限制,但是当集群很大,存在很多pod中,对每个pod定义资源请求和资源限制显得很繁琐,所以出现了LimitRange机制。
一个 LimitRange(限制范围) 对象提供的限制能够做到:
1、在一个命名空间中实施对每个 Pod 或 Container 最小和最大的资源使用量的限制。
2、在一个命名空间中实施对每个 PersistentVolumeClaim 能申请的最小和最大的存储空间大小的限制。
3、在一个命名空间中实施对一种资源的申请值和限制值的比值的控制。
4、设置一个命名空间中对计算资源的默认申请/限制值,并且自动的在运行时注入到多个 Container 中。
limitrange属于命名空间,当在一个命名空间中创建了一个limitrange对象,将会在该命名空间中实施 LimitRange 限制。
LimitRange机制的原理:在某个命名空间下,创建一个limitrang资源对象,表示对该命名空间下创建的pod和容器的requests和limits配置进行限制,比如pod和容器的最大、最小、默认requests和limits值。
下面进行演示:
#创建一个命名空间
kubectl create ns limitrang-nginx #创建命名空间
#为命名空间创建一个limitrange
vim my-limits.yaml
apiVersion: v1
kind: LimitRange
metadata:
name: my-limits
namespace: limitrang-nginx
spec:
limits: #定义了容器的request和limit的最大最小值,以及默认request、limit值
- type: Pod #类型是pod,表示下面这段整对整个pod而言
max: #pod的最大值
cpu: "4" #pod的最大cpu
memory: 2Gi #pod的最大内存
min: #pod的最小值
cpu: "200m" #pod的最小cpu
memory: 6Mi #pod的最小内存
maxLimitRequestRatio: #这个好像是pod的limits和requests的最大比例
cpu: 3
memory: 2
- type: Container #类型是容器,表示下面这段整对pod里面的每一个容器而言
default: #容器的默认限制值,注意这是默认limits值,当容器没有给定limits时将启动该值(下面说的default limit就是这个参数)
cpu: 300m #容器的默认limits.cpu
memory: 200Mi #容器的默认limits.memory
defaultRequest: #容器的默认请求值,当容器没有设置request时使用
cpu: 100m #容器的默认requests.cpu
memory: 100Mi #容器的默认requests.memory
max: #容器的最大值
cpu: 2 #容器的最大cpu,即limits.cpu
memory: 1Gi #容器的最大memory,即limits.memory
min: #容器的最小值
cpu: 100m #容器的最小cpu,即requests.cpu
memory: 3Mi #容器的最小memory,即requests.memory
maxLimitRequestRatio: #这个好像是容器的limits和requests的最大比例
cpu: 5
memory: 4
参数说明:
在limitrange中,pod和container都可以设置CPU或内存的min、max、maxLimitRequestRatio参数,container还可以定义default request和
default limit参数,而pod不能设置default request和default limit参数。
对container参数解读如下:
container的min表示pod中所有容器的requests最小值;
container的max表示pod中所有容器的requests最大值;
container的defaultRequest是pod中所有未指定requests值的容器的的默认request值;
container的default是pod中所有未指定limits值的容器的默认limits值。(注意看了,default对应的是容器默认limits,不要被它的单词迷糊了)
maxLimitRequestRatio这个参数好像是容器的最大超卖比例。
四个参数关系:min<=defaultRequest<=default<=max
对pod的参数解读如下:
pod的min表示pod中全部容器的requests总和最小值;
pod的max表示pod中全部容器的limits总和最大值;
maxLimitRequestRatio这个参数好像是pod的最大超卖比例。
当一个pod没有定义requests或limits时,且该pod所属命名空间中存在limitrange,则系统将根据limitrange给pod默认设置对应的requests和
limits值;
当即没有limitrange时,参考上面小节《 pod定义requests、limits》讲的那样;
当有limitrange时,但是只给定了limits,没有给定requests值时,经验证,pod还是默认requests值与limits值相等,而不是设置为limitrange设定的defaultRequest值。
Qos服务质量等级
(暂时先忽略limitrange吧,因为Qos服务质量等级涉及pod中容器requests和limits)
在系统资源不足时,k8s会选择"杀掉"部分容器来释放资源,选择哪些pod进行杀掉呢,那么如何衡量一个pod的重要程度时,使用Qos服务质量等级衡量,k8s将容器划分为3个QoS等级,如下:
Guaranteed:完全可靠的,是指pod的所有容器都定义了requests和limits,并且每一个容器的requests和limits值都对应相等且不为0,我们指定,如果定义了limits没有定义requests,那么requests值就等于limits,这种pod的QoS等级就是Guaranteed。
Burstable:弹性波动,较可靠的,当pod的QoS等级既不是Guaranteed又不是BestEffect,那就是Burstable;
这分为2种情况:pod中一部分容器定义了requests和limits且requests值小于limits值;pod中一部分容器都未定义requests和limits。注意:这里说的是没有定义requests和limits,但是不代表这里limitrange不会默认设置,这里可以先暂时忽略limitrange吧。
BestEffect:尽力而为,不太可靠的,是指pod中所有容器都没有定义requests和limits,那么这种pod的QoS等级就是BestEffect。注意:这里说的是没有定义requests和limits,但是不代表这里limitrange不会默认设置,这里可以先暂时忽略limitrange吧。
Guaranteed > Burstable > BestEffect
资源配额管理 Resource Quotas
一个k8s集群可能被多个租户使用,如何分配不同租户可以使用的资源呢? Resource Quotas就是来解决这个问题的。
一般的,一个租户占用一个命名空间,则可以在该命名空间下创建 Resource Quotas来进行资源使用限制;
Resource Quotas可以限制命名空间中某种资源类型对象的总数上限,也可以限制命名空间中pod可使用的可计算资源(可计算资源:cpu、memory)的总上限;资源配额还支持作用域,对符合特定范围的对象加以限制。官网:https://kubernetes.io/zh-cn/docs/concepts/policy/resource-quotas/
一个命名空间可以设定多个resourcequotas,resourcequotas在k8s中可以简写为quota。
#资源配额,对指定命名空间某种资源对象总数进行限制
[root@master ~]# vim resource-count.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: resource-count
namespace: limitrang-nginx #quota在哪个命名空间就表示对该命名空间进行限制
spec:
hard: #目前支持对下面这些资源对象进行总数量限制
configmaps: "50" #在该命名空间中允许存在的 ConfigMap 总数上限
persistentvolumeclaims: "50" #在该命名空间中允许存在的 PVC 的总数上限
pods: "4" #在该命名空间中允许存在的非终止状态的 Pod 总数上限
replicationcontrollers: "35" #在该命名空间中允许存在的 ReplicationController 总数上限
resourcequotas: "34" #在该命名空间中允许存在的 ResourceQuota 总数上限
services: "68" #在该命名空间中允许存在的 Service 总数上限
services.loadbalancers: "465" #在该命名空间中允许存在的 LoadBalancer 类型的 Service 总数上限
services.nodeports: "65" #在该命名空间中允许存在的 NodePort 类型的 Service 总数上限
secrets: "6" #在该命名空间中允许存在的 Secret 总数上限
#测试,在limitrang-nginx命名空间中扩容副本数,单由于quota限制了pod副本数最大只能是4个,所以deployment扩容并不会成功
#扩容到10个副本
[root@master ~]# kubectl scale deployment -n limitrang-nginx nginx --replicas=10
[root@master ~]# kubectl describe deployments.apps nginx --namespace=limitrang-nginx | grep Replicas
Replicas: 10 desired | 4 updated | 4 total | 4 available | 6 unavailable
#通过查看deployment对应的rs,我们看到rs的报错信息,正是由于quota限制命名空间pod副本数最大只能是4个才导致报错扩容不成功
[root@master ~]# kubectl -n limitrang-nginx describe rs nginx-6799fc88d8 | tail -n 1
Warning FailedCreate 14m replicaset-controller Error creating: pods "nginx-6799fc88d8-tmjpt"
is forbidden: exceeded quota: resource-count, requested: pods=1, used: pods=4, limited: pods=4
[root@master ~]#
#资源配额,对指定命名空间可计算资源资源总数进行限制
[root@master ~]# vim compute-resources.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
spec:
hard:
requests.cpu: "100" #所有非终止状态的 Pod,其 CPU 需求总量不能超过该值
requests.memory: 100Gi #所有非终止状态的 Pod,其内存需求总量不能超过该值
limits.cpu: "200" #所有非终止状态的 Pod,其 CPU 限额总量不能超过该值
limits.memory: 200Gi #所有非终止状态的 Pod,其内存限额总量不能超过该值
requests.nvidia.com/gpu: 4 #所有非终止状态的 Pod,GPU需求总量不能超过该值
# hugepages-<size>: xx #对于所有非终止状态的 Pod,针对指定尺寸的巨页请求总数不能超过此值
EOF
#例子不举了
还可以对存储资源配额:
requests.storage: 所有PVC存储资源的需求总量不能超过该值
persistentvolumeclaims: 该命名空间中允许的PVC总数量
<storage-class-name>.storageclass.storage.k8s.io/requests.storage: 在所有与 <storage-class-name> 相关的持久卷申领中,存储请求的总和不能超过该值
<storage-class-name>.storageclass.storage.k8s.io/persistentvolumeclaims: 在与 storage-class-name 相关的所有持久卷申领中,命名空间中可以存在的持久卷申领总数
配额作用域
资源配额可以指定作用域,对符合特定范围的对象加以限制;
更详细可以看官网:https://kubernetes.io/zh-cn/docs/concepts/policy/resource-quotas/#quota-scopes
apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-low
spec:
hard:
cpu: "5"
memory: 10Gi
pods: "10"
scopeSelector: #指定了作用域选择器
matchExpressions:
- operator: In
scopeName: PriorityClass
values: ["low"]
总结
1、可计算资源
cpu、memory是k8s中最常见的可计算资源,cpu是可压缩资源,cpu可被超量使用,memory是不可压缩资源,超出内存最大值将发生OOM异常;
2、cpu的单位
cpu的是通过cpu核数(cpus)来度量的,单位是m(milliunit),数量可以为整数或小数,如0.1m、50m;单位m,因为含义是milliunit,代表"千分
之一核心",譬如50m的含义是指50/1000核心,即5%。
3、memory的单位
Memory:内存的计量单位是字节Byte,Byte是由8个位组成的一个单元,也就是1 Byte = 8 bit。pod的内存requests或limits都是使用整数加上国际
单位制来表示内存值,国际单位制可以是
十进制的E、P、T、G、M、K、m或二进制的Ei、Pi、Gi、Mi、Ki。
常见的KiB和MiB是以二进制表示的字节单位,KB和MB是以十进制表示的字节单位。
十进制:1 KB = 1000 Byte = 8000 bit
二进制:1 KiB = 2的10次方 Byte = 1024 Byte = 8192 bit
Mi:1Mi = 1024乘1024,而平时使用的单为M是1M = 1000乘1000
memory:内存大小,可以使用Gi、Mi、G、M等单位
cpu的单位m:
注意:Gi和G,Mi和M优点区别,官网解释:Mi表示(1Mi=1024×1024),M表示(1M=1000×1000)(其它单位类推, 如Ki/K Gi/G)
4、pod定义requests、limits来进行容器的cpu、memory资源请求和限制
pod的request等于pod中所有容器的request相加之和。
pod的limit等于pod中所有容器的limits相加之和。
pod可以定义资源配额的相关参数:
spec.container[].resources.requests.cpu:容器初始要求的CPU数量
spec.container[].resources.limits.cpu:容器所能使用的最大CPU数量
spec.container[].resources.requests.memory:容器初始要求的内存数量
spec.container[].resources.limits.memory:容器所能使用的最大内存数量
默认情况下,pod中只写requests(cpu和memory写其中一个或两个都写)不写limits,则默认没有最大资源限制;
pod中只写limits.cpu、limits.memory,不写requests.cpu、requests.memory,默认的requests的cpu、memory其值等于对应的limits的cpu、
memory值;
pod中只写limits的cpu或memory其中的一个,则requests对应的也等价于limits的对应的一个值。如只写limits.cpu,则requests.cpu值
=limits.cpu值,limits.memory没写则requests.memory也没有值。
5、LimitRange限制命名空间下的pod的资源配额
limitrange属于命名空间,当在一个命名空间中创建了一个limitrange对象,将会在该命名空间中实施 LimitRange 限制。
LimitRange机制的原理:在某个命名空间下,创建一个limitrang资源对象,表示对该命名空间下创建的pod和容器的requests和limits配置进行限
制,比如pod和容器的最大、最小、默认requests和limits值。
spec:
limits: #定义了容器的request和limit的最大最小值,以及默认request、limit值
- type: Pod #类型是pod,表示下面这段整对整个pod而言
max: #pod的最大值
cpu: "4" #pod的最大cpu
memory: 2Gi #pod的最大内存
min: #pod的最小值
cpu: "200m" #pod的最小cpu
memory: 6Mi #pod的最小内存
maxLimitRequestRatio: #这个好像是pod的limits和requests的最大比例
cpu: 3
memory: 2
- type: Container #类型是容器,表示下面这段整对pod里面的每一个容器而言
default: #容器的默认限制值,注意这是默认limits值,当容器没有给定limits时将启动该值(下面说的default limit就是这个参数)
cpu: 300m #容器的默认limits.cpu
memory: 200Mi #容器的默认limits.memory
defaultRequest: #容器的默认请求值,当容器没有设置request时使用
cpu: 100m #容器的默认requests.cpu
memory: 100Mi #容器的默认requests.memory
max: #容器的最大值
cpu: 2 #容器的最大cpu,即limits.cpu
memory: 1Gi #容器的最大memory,即limits.memory
min: #容器的最小值
cpu: 100m #容器的最小cpu,即requests.cpu
memory: 3Mi #容器的最小memory,即requests.memory
maxLimitRequestRatio: #这个好像是容器的limits和requests的最大比例
cpu: 5
memory: 4
6、pod的Qos服务质量等级
在k8s系统中,使用Qos服务质量等级来衡量一个pod的重要程度,当k8s集群资源不足时,如内存不足,那么Qos服务质量等级低的pod将会被优先"杀
掉"以是否系统资源压力, k8s将pod划分为3个QoS等级,如下:
Guaranteed:完全可靠的,是指pod的所有容器都定义了requests和limits,并且每一个容器的requests和limits值都对应相等且不为0,我们指定,
如果定义了limits没有定义requests,那么requests值就等于limits,这种pod的QoS等级就是Guaranteed。
Burstable:弹性波动,较可靠的,当pod的QoS等级既不是Guaranteed又不是BestEffect,那就是Burstable;
这分为2种情况:pod中一部分容器定义了requests和limits且requests值小于limits值;pod中一部分容器都未定义requests和limits。注意:这里
说的是没有定义requests和limits,但是不代表这里limitrange不会默认设置,这里可以先暂时忽略limitrange吧。
BestEffect:尽力而为,不太可靠的,是指pod中所有容器都没有定义requests和limits,那么这种pod的QoS等级就是BestEffect。注意:这里说的
是没有定义requests和limits,但是不代表这里limitrange不会默认设置,这里可以先暂时忽略limitrange吧。
Guaranteed > Burstable > BestEffect
7、资源配额管理 Resource Quotas文章来源:https://uudwc.com/A/wkg6
k8s集群是一个多租户的系统,可能有多个命名空间,一般的每个租户占用一个命名空间进行自己的应用部署,那么如何分配不同租户可以使用的资源呢? Resource Quotas就是来解决这个问题的。
一般的,一个租户占用一个命名空间,则可以在该命名空间下创建 Resource Quotas来进行资源使用限制;
Resource Quotas可以限制命名空间中某种资源类型对象的总数上限,也可以限制命名空间中pod可使用的可计算资源(可计算资源:cpu、memory)的总上限;资源配额还支持作用域,对符合特定范围的对象加以限制。
8、limitrange和resourcequotas的区别文章来源地址https://uudwc.com/A/wkg6
limitrange主要是对一个命名空间下创建的pod和容器的requests和limits配置进行限制,比如pod和容器的最大、最小、默认requests和limits值等,换句话说,limitrange针对的是单个pod的可计算资源;
resourcequotas是对命名空间中某种资源对象总数进行限制,如A命名空间能创建多少个pod,能创建多少个configmap等;
resourcequotas还可以对指定命名空间的可计算资源总数进行限制,如限制A命名空间中全部非终止状态的pod的CPU和memory不能超过多少;
resourcequotas还可以对指定命名空间的存储资源总数进行限制,如限制A命名空间中的pvc数量不能超过100个等。