Kubernetes in Action笔记 - (18) 高级调度:污点、容忍度和亲缘性

分享到:

文章目录

污点是在不修改已有pod信息的前提下,通过在节点上添加污点信息,来拒绝pod在某些节点上的部署。

只有当一个pod容忍某个节点的污点, 这个pod才能被调度到该节点。

可以通过kubectl describe node查看节点的污点信息,在返回结果的Taints字段值中;可以通过kubectl describe po查看pod的污点容忍度,在返回结果的Tolerations字段值中。

每一个污点都可以关联一个效果, 效果包含了以下三种:

  • NoSchedule:表示如果pod没有容忍这些污点, pod则不能被调度到包含这些污点的节点上。
  • PreferNoSchedule:它是NoSchedule的一个宽松的版本,表示尽量阻止pod被调度到这个节点上,但是如果没有其他节点可以调度, pod依然会被调度到这个节点上。
  • NoExecute:不同于NoSchedule以及PreferNoSchedule,后两者只在调度期间起作用, 而NoExecute也会影响正在节点上运行着的pod。如果在一个节点上添加了NoExecute污点,那些在该节点上运行着的pod,如果没有容忍这个NoExecute污点,将会从这个节点去除。

假设有一个单独的 Kubernetes 集群,上面同时有生产环境和非生产环境的流量。其中最重要的一点是,非生产环境的pod不能运行在生产环境的节点上。可以通过在生产环境的节点上添加污点来满足这个要求:

1# 这个命令添加了一个taint,其中key为node-type,value为production,效果为NoSchedule
2kubectl taint node nodel.k8s node-type=production:NoSchedule
bash
 1apiVersion: extensions/vlbetal
 2kind: Deployment
 3metadata:
 4  name: prod
 5spec:
 6  replicas: 5
 7  template:
 8    spec:
 9      tolerations:
10      # 此处的污点容忍度允许pod被调度到生产环境节点上
11      - key: node-type
12        operator: Equal
13        value: production
14        effect: NoSchedule
...
yaml

节点可以拥有多个污点信息,而pod也可以有多个污点容忍度。

污点可以只有一个key和一个效果,而不必设置value。污点容忍度可以通过设置Equal操作符Equal操作符来指定匹配的value(默认情况下的操作符),或者也可以通过设置Exists操作符来匹配污点的key。

污点可以用来组织新pod的调度(使用 NoSchedule效果),或者定义非优先调度的节点(使用PreferNoSchedule效果), 甚至是将已有的pod从当前节点剔除。

可以用任何觉得合适的方式去设置污点和容忍度。例如,可以将一个集群分成多个部分,只允许开发团队将pod调度到他们特定的节点上。 当部分节点提供了某种特殊硬件, 并且只有部分pod需要使用到这些硬件的时候, 也可以通过设置污点和容忍度的方式来实现。

也可以配置一个容忍度, 用于当某个pod运行所在的节点变成unready或者unreachable状态时,k8s可以等待该pod被调度到其他节点的最长等待时间

 1$ kubectl get po prod-350605-lphSh -o yaml
 2...
 3  tolerations:
 4  - effect: NoExecute
 5    key: node.alpha.kubernetes.io/notReady
 6    operator: Exists
 7    tolerationSeconds: 300
 8  - effect: NoExecute
 9    key: node.alpha.kubernetes.io/unreachable
10    operator: Exists
11    tolerationSeconds: 300
...
bash

这两个容忍度表示, 该pod将容忍所在节点处于notReady或者unreachable状态维持300秒。当k8s控制器检测到有节点处于notReady或者unreachable状态时, 将会等待300秒, 如果状态持续的话, 之后将把该pod重新调度到其他节点上。当没有定义这两个容忍度时, 他们会自动添加到pod上。如果觉得5分钟太长的话,可以在pod描述中显式地将这两个容忍度设置得更短一些。

注意:在作者写书的时候,这是一个alpha阶段的特性,在未来的k8s版本中可能会有所改变。基于污点信息的pod剔除也不是默认启的, 如果要启用这个特性, 需要在运行控制器管理器时使用--feature-gates=TaintBasedEvictions=true选项。

可以定义pod的节点亲缘性规则,指定硬性限制或者偏好。

如果指定一种偏好的话,k8s将尽量把这个pod 调度到某些特定的节点上面;如果没法实现的话, pod 将被调度到其他节点。

使用了节点选择器使得需要GPU的pod只被调度到有GPU的节点上。

1apiVersion: vl
2kind : Pod
3metadata:
4  name: kubia-gpu
5spec:
6  nodeSelector:
7    gpu: "true"
8...
yaml

将节点选择器替换为节点亲缘性规则

 1apiVersion: v1
 2kind: Pod
 3metadata:
 4  name: kubia-gpu
 5spec:
 6  affinity:
 7    nodeAffinity:
 8      requiredDuringSchedulingIgnoredDuringExecution:
 9        nodeSelectorTerms:
10        - matchExpressions:
11          - key: gpu
12            operator: In
13            values: "true"
...
yaml
  • requiredDuringScheduling... 表明了该字段下定义的规则,为了让pod能调度到该节点上,明确指出了该节点必须包含的标签。
  • ...IgnoredDuringExecution 表明了该字段下定义的规则, 不会影响已经在节点上运行着的pod

这个功能是通过 preferredDuringSchedulingIgnoredDuringExecution 宇段来实现的

 1nodeAffinity:
 2  preferredDuringSchedulingignoredDuringExecution:
 3  - weight: 80
 4    preference: 
 5      matchExpressions:
 6      - key: availability-zone
 7        operator: In
 8        values:
 9        - zone1
10  - weight: 20
11    preference:
12      matchExpressions:
13      - key: share-type
14        operator: In
15        values:
16        - dedicated
...
yaml

上面主要涉及到pod和节点之间的亲缘性,这里介绍如何指定pod自身之间的亲缘性。

举例来说,想象一下你一个前端pod和一个后端pod, 将这些节点部署得比较靠近,可以降低延时,提高应用的性能。可以使用节点亲缘性规则来确保这两个pod被调度到同一个节点、同一个机架、同一个数据中心。但是,之后还需要指定调度到具体哪个节点、哪个机架或者哪个数据中心。因此,这不是一个最佳的解决方案。更好的做法应该是,让k8s将你的pod部署在任何它觉得合适的地方,同时确保2个pod是靠近的。这种功能可以通过pod亲缘性来实现。

1# 注意不是nodeAffinity
2podAffinity:
3  requiredDuringSchedulingIgnoredDuringExecution:
4  - topologyKey: kubernates.io/hostname
5    labelSelector:
6      matchLabels:
7        app: backend
yaml

注意:除了使用简单的matchLabels字段, 也可以使用表达能力更强的matchExpressions字段。

在同一个可用性区域中协同部署pod,需要将topologyKey属性设置为failure-domain.beta.kubernetes.io/zone

在同一个地域中协同部署pod,需要将topologyKey属性设置为failure-domain.beta.kubernetes.io/region

topologyKey的工作方式很简单,可以任意设置自定义的键,唯一的前置条件就是,在节点上加上对应的标签。

注意:在调度时,默认情况下,标签选择器只有匹配同一命名空间中的pod。但是,可以通过在label Selector同一级添加namespaces字段,实现从其他的命名空间选择pod的功能。

podAffinity与nodeAffinity,都可以指定硬性限制(仅允许调度到特定节点或者pod)或者偏好(如果无法满足,则可以调度到其他地方)。

有时候可能希望pod远离彼此,这种特性叫作pod非亲缘性。

它和pod亲缘性的表示方式一样, 只不过是将podAffinity字段换成podAntiAffinity, 这将导致调度器永远不会选择那些有包含podAntiAffinity匹配标签的pod所在的节点

下面的例子使用非亲缘性分散一个部署中的pod:

1# 一个前端pod必须不能调度到有app=frontend标签的pod运行的节点
2podAntiAffinity:
3  requiredDuringSchedulingIgnoredDuringExecution:
4  - topologyKey: kubernates.io/hostname
5    labelSelector:
6      matchLabels:
7        app: frontend
yaml

图书资料: