【k8s】4.调度器的调度策略:节点选择器,节点亲和性,污点与容忍,pod亲和性

目录

1 节点的调度策略

1.1 节点选择器nodeSelector

1.2 节点亲和性affinity

1.3 污点与容忍

1.3.1 设置污点

1.3.2 设置容忍

1.3.3 污点和亲和性冲突时会怎样

1.4 禁止节点调度,cordon与drain

1.4.1 cordon

1.4.2 drain

1.5 Pod的驱逐

2 Pod的调度策略

2.1 Pod的亲和性与反亲和性


1 节点的调度策略

我们可以在node节点上定义的一些规则,来决定 pod允许或不允许被调度到哪些节点上。

1.1 节点选择器nodeSelector

这是一种较常用也是较简单的方式,将pod调度到指定label的node上,可以满足一般情况下的调度需求。

第一步,为节点打labal:

// 查看节点的label
$ kubectl get nodes --show-labels
NAME      STATUS    ROLES    AGE     VERSION        LABELS
worker0   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker0
worker1   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker1
worker2   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker2

// 为节点打一个label
kubectl label node worker0 disktype=ssd

// 查看
$ kubectl get nodes --show-labels
NAME      STATUS    ROLES    AGE     VERSION        LABELS
worker0   Ready     <none>   1d      v1.13.0        ...,disktype=ssd,kubernetes.io/hostname=worker0
worker1   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker1
worker2   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker2

第二步,创建pod并定义nodeSelector:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
  nodeSelector:
    disktype: ssd

这样pod就会被调度到有对应标签的节点上了。

如果找不到任何一个node有nodeSelector定义的标签,pod是会一直Pending的~

1.2 节点亲和性affinity

是比nodeSelector更灵活但也更复杂的方式, 它可以进行一些简单的逻辑组合,而不只是简单的相等匹配,以应对更加复杂的节点调度需求。

分为软策略、硬策略两种:

  • requiredDuringSchedulingIgnoredDuringExecution:硬策略,如果没有满足条件的节点,就不断重试直至满足条件
  • preferredDuringSchedulingIgnoredDuringExecution:软策略,如果没有满足条件的节点,Pod会忽略这条规则,继续完成调度过程
spec:
  containers:
  - name: nginx
    image: nginx
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname
            operator: NotIn
            values:
            - 192.168.136.131
            - 192.168.136.132
        preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: disktype
                operator: In
                values:
                - ssd
                - sas

上述亲和性配置可以描述为:

  • Pod 不能运行在131和132两个节点上
  • 如果有节点满足 disktype=ssd或sas,优先调度到这类节点上
其中的字段:
  • operator:操作符,有In/NotIn/Gt/Lt/Exist/DoesNotExist
  • nodeSelectorTerms:下面的条件是or关系,满足一个即可
  • matchExpressions:下面的条件是and关系,必须同时满足
  • weight:权重,取值[1,100],会基于此计算评分,也就是当两个节点都满足时,调度器会将weight值添加到节点评分上

1.3 污点与容忍

污点(Taints): node设置了taints后,因为有了污点,不会将pod调度到这个node上了

容忍(Tolerations):pod可以容忍node上的污点,就可以调度到node上

使用场景:

  • 私有云服务中,某业务使用 GPU 进行大规模并行计算。为保证性能,希望确保该业务对服务器的专属性,避免将普通业务调度到部署 GPU 的服务器。
  • 用户希望把 Master 节点保留给 Kubernetes 系统组件使用,或者把一组具有特殊资源预留给某些 Pod,则污点就很有用了,Pod 不会再被调度到 taint 标记过的节点。

1.3.1 设置污点

命令:
kubectl taint node [node_name] key=value:[effect]   

其中 [effect] 取值:

  • NoSchedule:一定不能被调度
  • PreferNoSchedule:尽量不要调度
  • NoExecute:不仅不会调度,还会驱逐Node上已有的Pod
// 设置污点
# kubectl taint node master smoke=true:NoSchedule
node/master tainted

// 查看污点
# kubectl describe node master
Taints:             node.kubernetes.io/disk-pressure:NoSchedule
                    smoke=true:NoSchedule

// 移除污点
# kubectl taint nodes master smoke-
node/master untainted

1.3.2 设置容忍

在pod yaml中定义:
spec:
  containers:
  - name: nginx
    image: nginx
  tolerations:
  - key: smoke
    operator: Equal
    value: true
    effect: NoSchedule
  - key: drunk
    operator: Exists

上述容忍可以描述为:

  • pod可以容忍以下node(满足其中之一即可):
    • taints有smoke=true:NoSchedule
    • 存在key为drunk的taints
其中字段:
  • operator:操作符,不填默认是Equal,当是Exists时value可以省略
  • tolerations:下面的数组是or关系,满足其中之一即可

1.3.3 污点和亲和性冲突时会怎样

考虑如下情况:
  • 设置了master节点的taints为`smoke=true:NoSchedule`
  • 同时设置了pod的nodeSelector为 `smoke:true`
have a try:
# kubectl describe node master
Taints:             smoke=true:NoSchedule

// yaml
spec:
  containers:
  - image: containous/nginx
    name:nginx
  nodeSelector:
    smoke: "true"

查看pod状态:

# kubectl get pod
NAME                      READY   STATUS    RESTARTS   AGE
nginx-855f99dc9d-b54w2    0/1     Pending   0          4m50s

# kubectl describe pod nginx-855f99dc9d-b54w2
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  26s   default-scheduler  0/1 nodes are available: 1 node(s) had taint {smoke: true}, that the pod didn't tolerate.

所以这种情况下,k8s是会阻止pod调度的。也就是说,即使 nodeSelector 匹配了,污点的 NoSchedule 效果会优先阻止调度,导致 pod 处于 Pending 状态。

1.4 禁止节点调度,cordon与drain

1.4.1 cordon

停止节点调度。会将node 标记为 不可调度状态,新的pod不会调度到该node,但 已调度到该node的pod不受影响
// 停止调度
# kubectl cordon master

// 查看
# kubectl describe node master
Taints:             node.kubernetes.io/unschedulable:NoSchedule
                    smoke=true: NoSchedule
Unschedulable:      true

// 恢复调度
# kubectl uncordon master

// 查看
# kubectl describe node master
Taints:             smoke=true:NoSchedule
Unschedulable:      false

cordon本质上也是使用了污点机制,cordon实际上做了以下事情:

  • 为 node 打上 `node.kubernetes.io/unschedulable:NoSchedule` 的taints
  • 将 Unschedulable 置为true

1.4.2 drain

停止节点调度并驱逐pod。会将此节点已有的pod重新调度到其他节点,然后将node标记为 不可调度状态。
// 停止调度并驱逐
$ kubectl drain master --force --ignore-daemonsets --delete-local-data

// 恢复调度
kubectl uncordon master

drain 方式是安全驱逐 pod,会等到 pod 容器应用程序优雅停止后再删除该 pod

驱逐流程:

先在 node 节点删除 pod,然后再在其他 node 节点创建该 pod。所以为了确保 drain 驱逐过程中不中断服务(即做到无感知地平滑驱逐),必须保证要驱逐的 pod 副本数大于1,并且采用"反亲和策略将这些 pod 调度到不同的 node上,也就是说,在"多个pod副本+反亲和策略"的场景下,驱逐过程对容器服务是没有影响的。

1.5 Pod的驱逐

驱逐Eviction:当节点 NotReady或资源不足时,把 pod 驱逐至其它节点。

本质上也是利用污点与容忍实现的。

k8s会从两方面去做检查:

(1) Kube-controller-manager: 周期性检查所有节点状态,当节点处于 NotReady 状态超过一段时间后,驱逐该节点上所有 pod。

节点若失联或异常,k8s会自动为node打上污点,同时为pod添加如下容忍设置:

  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300

其中tolerationSeconds是一个宽限期,即当node异常导致pod要被驱逐时,给node一个5min的宽限时间,等待异常被恢复,避免因网络波动导致pod被立即驱逐。

(2) Kubelet: 周期性检查本节点资源,当资源不足时,按照优先级驱逐部分 pod

2 Pod的调度策略

上面介绍的node的调度策略都是基于node来决定pod如何调度,还可以通过pod上定义的一些规则,决定pod改调度到那个node上。

2.1 Pod的亲和性与反亲和性

基于已经在节点上运行的  Pod  的标签来约束 Pod 可以调度到的节点,而不是基于节点上的标签。
spec:
  containers:
  - name: nginx
    image: nginx
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: topology.kubernetes.io/zone
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security
              operator: In
              values:
              - S2
          topologyKey: topology.kubernetes.io/zone

上述配置可以描述为:

  • 对亲和性:只有节点属于特定的区域(zone),且该区域中的其他 Pod 已打上 security=S1 标签时,才可以 Pod 调度到此节点上。 比如,一个区域由带有 topology.kubernetes.io/zone=V 标签的节点组成,那么只要 Zone V 内已经至少有一个 Pod 打了 security=S1 标签, 就可以将此 Pod 调度到 Zone V 内的任何节点。
  • 对反亲和性: 如果节点属于特定的区域(zone)且该区域中的其他 Pod 已打上 security=S2 标签,那么调度器会尽量避免将 Pod 调度到此节点上。比如,一个区域由带有 topology.kubernetes.io/zone=R 标签的节点组成,那么只要 Zone R 内已经至少有一个 Pod 打了 security=S2 标签, 调度器就会避免将 Pod 分配给 Zone R 内的任何节点。
pod的亲和性与反亲和性较为复杂,且性能不高,所以一般很少使用。
来自官方:Pod 间亲和性和反亲和性都需要相当的计算量,因此会在大规模集群中显著降低调度速度,因此 不建议在包含数百个节点的集群中使用这类设置。
参考:
  • 30
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值