摘要
一般情况下我们部署的 POD 是通过集群自动调度选择某个节点的,默认情况下调度器考虑的是资源足够,并且负载尽量平均,但是有的时候我们需要能够更加细粒度的去控制 POD 的调度,比如我们内部的一些服务 gitlab 之类的也是跑在Kubernetes
集群上的,我们就不希望对外的一些服务和内部的服务跑在同一个节点上了,害怕内部服务对外部的服务产生影响;有的时候呢我们两个服务直接交流比较频繁,又希望能够将这两个服务的 POD 调度到同样的节点上。这就需要用到 Kubernetes 里面的一个概念:亲和性,亲和性主要分为两类:nodeAffinity
和podAffinity
。
nodeSelector
我们知道label
是kubernetes
中一个非常重要的概念,用户可以非常灵活的利用 label 来管理集群中的资源,比如最常见的一个就是 service 通过匹配 label 去选择 POD 的。而 POD 的调度也可以根据节点的 label 进行特定的部署。
我们可以通过下面的命令查看我们的 node 的 label:
1 | [root@node1 ~]# kubectl get nodes --show-labels |
1 | [root@node1 ~]# kubectl label nodes node1 source=sy |
我们可以通过上面的--show-labels
参数可以查看上述标签是否生效。当 node 被打上了相关标签后,在调度的时候就可以使用这些标签了,只需要在 POD 的 spec 字段中添加nodeSelector
字段,里面是我们需要被调度的节点的 label。例如,下面是我们之前的一个默认的 busybox POD 的 YAML 文件:
1 | apiVersion: v1 |
然后我需要让上面的 POD 被调度到140的节点上,那么最简单的方法就是去匹配140上面的 label,如下:
1 | apiVersion: v1 |
nodeAffinity
nodeAffinity
就是节点亲和性,相对应的是Anti-Affinity
,就是反亲和性,这种方法比上面的nodeSelector
更加灵活,它可以进行一些简单的逻辑组合了,不只是简单的相等匹配。 调度可以分成软策略和硬策略两种方式,软策略就是如果你没有满足调度要求的节点的话,POD 就会忽略这条规则,继续完成调度过程,说白了就是满足条件最好了,没有的话也无所谓了的策略;而硬策略就比较强硬了,如果没有满足条件的节点的话,就不断重试直到满足条件为止,简单说就是你必须满足我的要求,不然我就不干的策略。 nodeAffinity
就有两上面两种策略:preferredDuringSchedulingIgnoredDuringExecution
和requiredDuringSchedulingIgnoredDuringExecution
,前面的就是软策略,后面的就是硬策略。
如下例子:(test-node-affinity.yaml)
1 | apiVersion: v1 |
上面这个 POD 首先是要求 POD 不能运行在node1这个节点上,如果有个节点满足source=sy
的话就优先调度到这个节点上,同样的我们可以使用descirbe
命令查看具体的调度情况是否满足我们的要求。这里的匹配逻辑是 label 的值在某个列表中,现在Kubernetes
提供的操作符有下面的几种:
- In:label 的值在某个列表中
- NotIn:label 的值不在某个列表中
- Gt:label 的值大于某个值
- Lt:label 的值小于某个值
- Exists:某个 label 存在
- DoesNotExist:某个 label 不存在
如果
nodeSelectorTerms
下面有多个选项的话,满足任何一个条件就可以了;如果matchExpressions
有多个选项的话,则必须同时满足这些条件才能正常调度 POD。
podAffinity
上面两种方式都是让 POD 去选择节点的,有的时候我们也希望能够根据 POD 之间的关系进行调度,Kubernetes
在1.4版本引入的podAffinity
概念就可以实现我们这个需求。
和nodeAffinity
类似,podAffinity
也有requiredDuringSchedulingIgnoredDuringExecution
和 preferredDuringSchedulingIgnoredDuringExecution
两种调度策略,唯一不同的是如果要使用互斥性,我们需要使用podAntiAffinity
字段。 如下例子,我们希望with-pod-affinity
和busybox-pod
能够就近部署,而不希望和node-affinity-pod
部署在同一个拓扑域下面:(test-pod-affinity.yaml)
1 | apiVersion: v1 |
上面这个例子中的 POD 需要调度到某个指定的主机上,至少有一个节点上运行了这样的 POD:这个 POD 有一个app=busybox-pod
的 label。podAntiAffinity
则是希望最好不要调度到这样的节点:这个节点上运行了某个 POD,而这个 POD 有app=node-affinity-pod
的 label。
亲和性/反亲和性调度策略比较如下:
调度策略 | 匹配标签 | 操作符 | 拓扑域支持 | 调度目标 |
---|---|---|---|---|
nodeAffinity | 主机 | In, NotIn, Exists, DoesNotExist, Gt, Lt | 否 | 指定主机 |
podAffinity | POD | In, NotIn, Exists, DoesNotExist | 是 | POD与指定POD同一拓扑域 |
podAnitAffinity | POD | In, NotIn, Exists, DoesNotExist | 是 | POD与指定POD不在同一拓扑域 |
污点(Taints)与容忍(tolerations)
对于nodeAffinity
无论是硬策略还是软策略方式,都是调度 POD 到预期节点上,而Taints
恰好与之相反,如果一个节点标记为 Taints ,除非 POD 也被标识为可以容忍污点节点,否则该 Taints 节点不会被调度pod。
比如用户希望把 Master 节点保留给 Kubernetes 系统组件使用,或者把一组具有特殊资源预留给某些 POD,则污点就很有用了,POD 不会再被调度到 taint 标记过的节点
1 | kubectl taint nodes node1 key=value:NoSchedule |
如果仍然希望某个 POD 调度到 taint 节点上,则必须在 Spec 中做出Toleration
定义,才能调度到该节点,举例如下:
1 | tolerations: |
effect 共有三个可选项,可按实际需求进行设置:
NoSchedule
:POD 不会被调度到标记为 taints 节点。PreferNoSchedule
:NoSchedule 的软策略版本。NoExecute
:该选项意味着一旦 Taint 生效,如该节点内正在运行的 POD 没有对应 Tolerate 设置,会直接被逐出。