创建一个pod时,可以指定容器对CPU和内存的资源请求量(即requests),以及资源限制量(即limits)。它们并不在pod里定义,而是针对每个容器单独指定。pod对资源的请求量和限制量是它所包含的所有容器的请求量和限制量之和。
一、容器申请资源
1、如何申请
apiVersion: v1
kind: Pod
metadata:
name: pod-example
spec:
containers:
- image: docker.io/library/busybox:latest
name: example
imagePullPolicy: IfNotPresent
command:
- top
resources:
requests: // 容器运行至少需要预留的量,实际运行可以比它少,但是要预留出来,也可以比它多
cpu: 200m // 毫核,1000m为1核,200毫核为1/5核
memory: 10Mi // 消耗10MB RAM
2、requests对调度的影响
调度器在调度时并不关注各类资源在当前时刻的实际使用量,而只关心节点上部署的所有pod的资源申请量之和
调度器会对可调度节点打分,并选出最优节点分配给pod,打分方式有:LeastRequestedPriority 和MostRequestedPriority。前者优先将 pod调度到请求量少的节点上(也就是拥有更多未分配资源的节点),而后者相反(把pod集中到某node上)
查看node的资源量:
kubectl describe node xxx
-------
Capacity: //容量
cpu: 6
ephemeral-storage: 97283Mi
hugepages-2Mi: 0
memory: 12283244Ki
pods: 110
Allocatable: // 剩余可分配量
cpu: 6
ephemeral-storage: 97283Mi
hugepages-2Mi: 0
memory: 12283244Ki
pods: 110
--------
当指定一个容器需要7核cpu时,调度不成功,因为没有node满足这个资源,pod状态一直都是pending
3、CPU requests如何影响CPU时间分配
两个pod的cpu请求量为1:5时,都跑满,则按照比例分配剩下的cpu
A跑满,B空闲,剩余cpu都给A,但当B需要时,A让位
二、限制容器的可用资源
CPU是一种可压缩资源,意味着我们可以在不对容器内运行的进程产生不利影响的同时,对其使用量进行限制。而内存明显不同 —— 是一种不可压缩资源。一旦系统为进程分配了一块内存,这块内存在进程主动释放之前将无法被回收。这就是我们为什么需要限制容器的最大内存分配量的根本原因。
如果不对内存进行限制,工作节点上的容器(或者pod)可能会吃掉所有可用内存,会对该节点上所有其他pod和任何新调度上来的pod(记住新调度的pod是基于内存的申请量而不是实际使用量的)造成影响。单个故障pod或恶意pod几乎可以导致整个节点不可用
1、如何限制
resources:
limits:
cpu: 1
memory: 20Mi
当只写了limits没写requests时,requests=limit
2、超过limits
分配节点时,只要requests在范围内就可以了,不会因为limits的限制而影响节点的分配,换句话说,一个节点不一定能提供所有pod所指定的资源limits之和那么多的资源
那运行时真的超过了limits怎么办呢?
CPU是可压缩资源,想用较多CPU时,控制分不到比限额多的CPU就可以了,requests也在pod绑定节点的时候预留出来了,所以CPU没有问题
内存是不可压缩资源,当进程尝试申请分配比限额更多的内存时会被杀掉(因为没有足够的内存了,也不能调整其他进程的内存,OOM Out Of Memory),如果pod的重启策略为Always 或 OnFailure,进程将会立即重启,因此用户可能根本察觉不到它被杀掉,但是如果它继续超限并被杀死,Kubernetes会再次尝试重启,并开始增加下次重启的间隔时间(10、20、40、80、160 、300秒,后每隔5分钟无限重启)。这种情况下用户会看到pod处于 CrashLoopBackOff状态。
三、QoS等级
内存资源不够时,需要杀掉一个进程,但杀掉哪个进程呢?
k8s将pod分为三个等级,按等级优先级顺序删除
1、BestEffort
pod中的所有容器都没有设置任何cpu、内存的requests和limits,这个pod的QoS等级就是BestEffort
2、Burstable
pod中任意容器的cpu或内存的requests<limits,这个pod的QoS等级就是Burstable
3、Guaranteed
pod中所有容器的cpu和内存的requests=limits,这个pod的QoS等级就是Guaranteed
仅设置limits时,requests会被自动设置为limits,也满足Guaranteed
pod.status.qosClass可以查看pod的QoS等级
4、优先级
内存不够时,先杀掉BestEffort,再杀Burstable,当系统进程需要资源时,才会杀掉Guaranteed
同一种等级下,优先删除 实际使用量占requests百分比多的
总的来说,因为bestEffort没有指定需要分配多少内存,本来也没预留多少内存给它,占用的内存还不明确,所以先杀;Burstable需要的内存在一定范围内,但也不明确,先删快要OOM的,以免它OOM时还要删;Guaranteed因为预留的和限定一样,确定了需要的内存,就可以优先运行这些pod
四、LimitRange资源
LimitRange可以给每个没有设置requests和limits的容器或pod,设置默认值,也可以约束资源的范围。LimitRange准入插件控制
1、创建LimitRange
如果创建的pod超限了,会直接报错
在LimitRange创建前,已经创建的pod,不受限制,所以,想要更新LimitRange,也只对更新后创建的pod生效
五、ResourceQuota
LimitRange只能应用于pod或容器,resourceQuota可以应用于整个ns,同样也是准入插件控制的,只对创建resourceQuota后创建的资源生效
1、创建
apiVersion: v1
kind: ResourceQuota
metadata:
name: cpu-and-mem
spec:
hard:
requests.cpu: 400m
requests.memory: 200Mi
limits.cpu: 600m
limits.memory: 500Mi
注意:
创建ResourceQuota一般都还要创建LimitRange,或者明确pod的requests和limits,因为资源被限额了,必须要明确每个pod需要的资源
2、为持久化存储指定配额
PVC总量被限制为500GiB
3、限制可创建对象的个数
4、为特定状态或者QoS等级的pod指定配额
不限定范围就是对ns下所有后创建的pod有效
但也可以限定对部分pod有效,需要根据pod状态或QoS等级限制
加个scopes字段,限定有哪种状态或是哪种QoS等级的pod
只有四种作用范围:BestEffort、NotBestEffort、Termination和NotTerminating
pod.spec.activeDeadlineSeconds表示一个pod从开始尝试停止的时间到其被标记为Failed然后真正停止之前,允许其在节点上继续运行的秒数,Termination和NotTerminating就是针对设置了activeDeadlineSeconds的pod
六、对pod的资源使用量监控
给pod预留和限制的资源,多了也不好,少了也不好,可以通过资源监控,查看pod实际需要使用多少cpu内存,再调整pod资源
1、收集、获取实际资源使用情况
Kubelet自身就包含了一个名为cAdvisor的agent,它会收集整个节点和节点上运行的所有单独容器的资源消耗情况。集中统计整个集群的监控信息需要运行一个叫作Heapster的附加组件
在这之前,需要先启用heapster,每种集群部署方式,启动heapster方式不一样,例如minikube:
minikube addons enable heapster
启用之后,就可以使用kubectl top命令查看节点、pod和容器的资源使用量
kubectl top node
kubectl top pod
kubectl top pod --container
2、保存并分析历史资源的使用统计信息
cAdvisor和Heapster获得的都是查询时的临时资源使用量,要想形成图表,分析历史资源的使用情况,需要使用InfiuxDB+Grafana
InfiuxDB是一个用于存储应用指标,以及其他监控数据的开源的时序数据库。Grafana是一个拥有着华丽的web控制台的数据分析和可视化套件,同样也是开源的,它允许用户对InfiuxDB中存储的数据进行可视化,同时发现应用程序的资源使用行为是如何随时间变化的