官方文档在此
服务质量(Quality of Service,Qos)类,kubernetes会基于每个Pod
中容器的资源请求
和资源限制
为Pod设置Qos类,然后kubernetes会根据Qos类来决定在遇到节点压力(没有足够可用资源)的时候从Node中驱逐哪些Pod;
Qos可选类有Guaranteed、Burstable和BestEffort,当一个Node资源耗尽时,Kubernetes将首先驱逐在该Node上运行的BestEffort
Pod,然后是Burstable
Pod,最后是Guaranteed
Pod;当这种驱逐是由资源压力引起时,只有超出资源请求的Pod才是被驱逐的候选对象;
Guaranteed
:Guaranteed Pod具有最严格资源限制,并且最不可能面临驱逐。也就是 只有在这些Pod超过其自身的限制或者在Node抢占时优先级比别的Pod低,才会被杀死;这些Pod不可以获得超出指定limit的资源,这些Pod也可以使用static CPU管理策略来独占CPU;Burstable
:Burstable Pod有一些基于request的资源下限保证,但不需要特定的limit;如果未指定limit,则默认limit等于Node的容量,这允许Pod在资源可用时灵活地增加其资源。在Node资源压力导致Pod被驱逐时,只有在所有的BestEffort Pod被驱逐后这些Pod才会被驱逐。因为Burstable Pod可以包括没有资源limit或资源rquest的容器,所以Burstable Pod可以尝试使用任意数量的节点资源;BestEffort
:Qos类中的Pod可以使用未专门分配给其他Qos类中的Pod的节点资源。例如一个节点是16核CPU,并且已经将4核分配给了一个Guaranteed Pod,那么BestEffort Qos类中的Pod可以尝试任意使用剩下的12核CPU(如果节点遇到资源压力,kubelet会将BestEffort Pod优先驱逐);硬性要求:
所有容器
必须要有CPU和内存
的limit和request
;limit值和request值要相等
;例如:
下面这个Pod的容器设置了内存请求和内存限制,值都是2Gi,同时也设置了CPU请求和CPU限制,值都是1核(也可以是1000m)
apiVersion: v1
kind: Pod
metadata:
name: "pod-guaranteed"
namespace: default
labels:
app: "pod-guaranteed"
spec:
containers:
- name: pod-guaranteed
image: "nginx:latest"
resources:
limits:
cpu: 1
memory: 2Gi
requests:
cpu: 1
memory: 2Gi
验证:
[root@k8s-master ~# kubectl describe pod/pod-guaranteed
Containers:
pod-guaranteed:
...
Limits:
cpu: 1
memory: 2Gi
Requests:
cpu: 1
memory: 2Gi
...
QoS Class: Guaranteed
说明:
如果某 Container 指定了自己的内存限制,但没有指定内存请求,Kubernetes 会自动为它指定与内存限制相等的内存请求。同样,如果容器指定了自己的 CPU 限制, 但没有指定 CPU 请求,Kubernetes 会自动为它指定与 CPU 限制相等的 CPU 请求。
也就是说,如果创建Pod时只指定了CPU和内存的limit,而不指定request,那么默认情况下request是和limit相等的,所以创建出来的Pod也是属于Guaranteed Pod类;
硬性要求:
例如(1):
下面这个Pod的容器设置了内存限制为最多使用500Mi,内存请求为200Mi
apiVersion: v1
kind: Pod
metadata:
name: "pod-burstable"
namespace: default
labels:
app: "pod-burstable"
spec:
containers:
- name: pod-burstable
image: "nginx:latest"
resources:
limits:
memory: 500Mi
requests:
memory: 200Mi
#或如下配置都是属于Burstable Pod类
#limits:
# cpu: 2
# memory: 2Gi
#requests:
# cpu: 1
# memory: 1Gi
验证:
[root@k8s-master ~]# kubectl describe pod/pod-burstable
Containers:
pod-burstable:
...
Limits:
memory: 500Mi
Requests:
memory: 200Mi
...
QoS Class: Burstable
例如(2):
下面这个Pod的里包含两个容器,一个容器指定内存请求为200MiB,另一个容器没有任何请求或限制
apiVersion: v1
kind: Pod
metadata:
name: "pod-burstable2"
namespace: default
labels:
app: "pod-burstable2"
spec:
containers:
- name: pod-burstable2
image: "nginx:latest"
resources:
requests:
memory: 200Mi
- name: pod-burstable-assist
image: "redis"
验证:
[root@k8s-master ~]# kubectl describe pod/pod-burstable2
Containers:
pod-burstable2:
...
Requests:
memory: 200Mi
...
QoS Class: Burstable
硬性要求:
例如:
下面这个Pod的容器没有设置内存和CPU限制或请求
apiVersion: v1
kind: Pod
metadata:
name: "pod-besteffort"
namespace: default
labels:
app: "pod-besteffort"
spec:
containers:
1. name: pod-besteffort
image: "nginx:latest"
验证:
[root@k8s-master ~]# kubectl get pod/pod-besteffort -o yaml
spec:
containers:
...
resources: {}
...
status:
qosClass: BestEffort
官方文档在此
综上所述,Qos类的优先级由低到高为:
BestEffort < Burstable < Guaranteed
BestEffort 类型的Pods
:当节点有压力时/系统用完了全部内存时,首先考虑的就是资源使用量超过其请求的BestEffort Pods,也就是该类型的Pods会最先被kill掉;Burstable类型的Pods
:当节点有压力时/系统用完了全部内存,且 没有BestEffort Pods可以被kill时,该类Pods会被kill掉;Guaranteed类型的Pods
:当节点有压力时/系统用完了全部内存,且 没有BestEffort Pods和BestEffort Pods 可以被kill时,该类型的Pods才会根据资源使用量以及优先级被kill掉;下面再来解释下为什么Guaranteed类型的Pods是最后才被kill掉的:
Kubernetes通过cgroup给pod设置QoS级别,当资源不足时先kill优先级低的pod,在实际使用过程中,通过OOM分数值来实现,OOM分数值从0-1000(OOM分数值根据OOM_ADJ参数计算得出)。
kubelet 会根据 Pod 的服务质量(QoS)为每个容器设置一个 oom_score_adj 值。
服务质量 | oom_score_adj |
---|---|
Guaranteed | -997 |
BestEffort | 1000 |
Burstable | 2到999 |
简单理解为:oom_score_adj的值越大越容易被kill;
对于kubernetes保留资源,比如kubelet,docker,OOM_ADJ参数设置成了-999,表示不会被OOM kill掉。OOM_ADJ参数设置的越大,通过OOM_ADJ参数计算出来OOM分数越高,表明该pod优先级就越低,当出现资源竞争时会越早被kill掉,对于OOM_ADJ参数是-999的表示kubernetes永远不会因为OOM而被kill掉。
总结
在生产环境中,强烈建议划分业务资源池:
如果公司有钱,资源充足的话,可将QoS pods类型均设置为Guaranteed。用计算资源换业务性能和稳定性,减少排查问题时间和成本。