k8s中的资源管理和调度

k8s中的Resource,目前支持类型:
  • cpu,单位为Core(此处1 Core实际指一个Hyperthread),1 millicore=0.001Core
  • memory,单位Byte
  • storage
  • ephemeral-storage:容器日志、emptyDir、可写入的容器镜像层
  • hugepages-<size>:目前属于Pod级别的资源
  • 自定义资源(如GPU):配置时,指定的数量必须为整数。
目前资源配置主要分成request(需要的数量)和limit(资源的界限)两种类型。
调度Pod时,调度器只会使用request进行调度(同时会考虑kubelet的--max-pods参数,默认110)
临时存储功能(默认不启动)启动后Pod挂载的emptyDir不能超过sizeLimit、Container对本地临时存储的使用量不能超过其Limit、Pod对本地临时存储的使用量不能超过所有Container的Limit之和,否则会被驱逐
巨页的request必须等于limit,多尺寸的巨页默认不支持。
自定义资源的request必须等于limit。
 
Pod服务质量(Qos)配置
根据CPU、内存资源的需求,对Pod的服务质量进行分类:
  • Guaranteed:Pod中每个容器都有CPU、内存的request以及limit声明,且request=limit
  • Burstable:CPU、内存的request≠limit,或者只填写了其中一种资源
  • BestEffort:没有任何request和limit
当节点上配额资源不足,kubelet会把一些低优先级的,或者说服务质量要求不高的Pod驱逐掉(先BestEffort再Burstable)。
 
CPU是按request来划分权重的,服务质量要求不高的Pod,request可以填很小的数字或者不填,Pod的权重就会非常低。
kubelet的参数cpu-manager-policy=static时,如果Guaranteed Qos的Pod的CPU的request是整数,会进行绑核;CPU的request不是整数的Guaranteed/Burstable/BestEffort,它们要用的CPU会组成一个CPU share pool,根据不同的权重划分时间片。
 
memory上也会按照不同的Qos划分OOMScore。物理机出现OOM时会优先kill掉OOMScore得分高的Pod。
    Guaranteed:会配置默认的-998的OOMScore;
    Burstable:会根据内存设计的大小和节点的关系(申请资源越多得分越低)来分配 2~999的OOMScore;
    BestEffort:会固定分配1000的OOMScore
 
调度配置
(1)Pod进行Node选择
在Pod的sepc中指定:
  nodeSelector: <object>
(2)workload进行Node选择
在workload的spec中通过matchLabels来筛选出一批Pod;通过matchExpressions来决定这批Pod的调度。
  selector:  
    matchLabels: <object>
    matchExpressions: <object>
(3)Node禁止调度
在Node的sepc中指定:
  unschedulable: true
(3)Pod的拓扑调度
在Pod的spec中描述这一组Pod在某个topologyKey上的分布
如果定义了多个,则是并列关系。比如说可以在一个zone级别上,也可以在一个Node级别上。
  topologySpreadConstraints:
    - maxSkew: <integer>
      topologyKey: <string>
      whenUnsatisfiable: <string>
      labelSelector: <object>
topologyKey为zone时,Pod将在zone间均匀分布。没有key为zone的Node将被忽略(位于这些Node上的Pod不会被计算,新Pod也不会启动到这些Node上)
maxSkew是最大允许不均衡的数量。如果设置为1,那么Pod将在所有zone间完全均匀分布。
举例:
假设集群中有三个zone,某个部署的Pod在zone1和zone2中都分配了一个Pod。
计算不均衡数量公式为:Skew = count[topo] - min(count[topo]),由此可以算出三个zone的Skew分别是1、1、0。
如果新Pod分配到zone1/zone2,zone1/zone2的skew将变为2,大于设置的maxSkew=1;如果分配到zone3的话,zone1-zone3的Skew均为0。因此新Pod只能分配到zone3
假设maxSkew为2,如果新Pod分配到zone1/zone2,skew 的值为2 <=maxSkew。因此zone1-zone3都是允许的。
在不均衡的情况下可以设置whenUnsatisfiable:在过滤阶段一般设置为DoNotSchedule(不允许被调度),也可以设置为ScheduleAnyway(随便调度)
 
在kube-scheduler配置文件的profile中可以设置默认的PodTopologySpread:
apiVersion: kubescheduler.config.k8s.io/v1beta1
kind: KubeSchedulerConfiguration
profiles:
  pluginConfig:
    - name: PodTopologySpread
      args:
        defaultConstraints:
          - maxSkew: 1
            topologyKey: topology.kubernetes.io/zone
            whenUnsatisfiable: ScheduleAnyway
Pod没有配置PodTopologySpread时会自动使用此配置。
配置中没有labelSelector,会根据service、rs等自动计算。因此Pod必须属于某个资源对象。
开启此默认配置时,最好禁用scheduler framework中的SelectorSpread插件。
此时scheduler framework中的PodTopologySpread会使用如下默认配置:
  defaultConstraints:
    - maxSkew: 3
      topologyKey: "kubernetes.io/hostname"
      whenUnsatisfiable: ScheduleAnyway
    - maxSkew: 5
      topologyKey: "topology.kubernetes.io/zone"
      whenUnsatisfiable: ScheduleAnyway
(4)Pod亲和调度和反亲和调度
Exists范围比In更大。当Operator填了Exists,就不需要再填写values,会直接禁止调度到带该key标签的Pod的节点。即,不管 values是什么值,只要带了k1这个key标签的Pod所在节点,都不能调度过去。
 
优先调度和优先反调度时,preferred里面可以是一个list选择填上多个条件,每对key: kalue有不同的权重。调度器会优先把Pod分配到权重分更高的调度条件节点上去。
 
(5)Node亲和调度
NodeSelector其实是一个map结构,在pod的spec.nodeSelector里面直接写上对node标签key:value的要求即可。
NodeAffinity的Operator上提供了比 PodAffinity的Operator更丰富的内容。增加了Gt和Lt(数值比较,values只能填数字)。
 
(6)Node标记/容忍
例如上图绿色部分,给demo-node打了taint后,效果是:新建的Pod没有专门容忍这个taint,那就没法调度到这个节点上。
除非如上图蓝色部分,在Pod上打一个key、value、effect完全相同的Pod Tolerations。
 
该特性目前已变为taints:使用cordon命令将节点标记为不可调度,使用drain命令将已经在节点上运行的pod驱逐到其他节点;uncordon命令解锁节点,使其重新变得可调度
 
(7)优先级抢占调度
比如有一个Node的CPU已经被一个Pod占用了。另一个高优先级Pod来的时候,低优先级的Pod应该把CPU让给高优先级的Pod使用。低优先级的Pod需要回到等待队列,或者是业务重新提交。
Kubernetes v1.14后,优先级(PodPriority)和抢占(Preemption)的特点变成了stable。并且默认开启。
原文地址:https://www.cnblogs.com/yangyuliufeng/p/14257886.html