简述
Kubernetes允许你去影响pod被调度到哪个节点。 起初, 只能通过在pod规范里指定节点选择器来实现,其实还有更高级的机制比如利用污点和亲缘性来实现pod 的调度。
污点和容忍度
首先要介绍的高级调度的两个特性是节点污点, 以及pod对于污点的容忍度,前者配置在节点上后者配置在Pod上。这些特性被用于限制哪些pod可以被调度到某一个节点。 只有当 一个pod 具有容忍某个节点的污点的容忍度, 这个pod才能被调度到该节点否则不能被调度到该节点。
区别
这与使用节点选择器和节点亲缘性有些许不同,污点是在不修改巳有pod信息的前提下,通过在节点上添加污点信息,来拒绝pod在某些节点上的部署。
污点和污点容忍度的使用场景
1、默认情况下,一个集群中的主节点需要设置污点,这样才能保证只有控制面板pod才能部署在主节点上。
2、假设你有一个单独的 Kubernetes 集群,上面同时有生产环境和非生产环境的流量。其中最重要的一点是, 非生产环境的 pod不能运行在生产环境的节点上。可以通过在生产环境的节点上添加污点来满足这个要求。
3、可以将一个集群分成多个部分, 只允许开发团队将pod调度到他们特定的节点上。 当你的部分节点提供了某种特殊硬件, 并且只有部分pod需要使用到这些硬件的时候, 也可以通过设置污点和容忍度的方式来实现。
查看节点上的污点属性和pod 的污点容忍度
节点上的污点属性 kubectl describe node master.k8s ... ... Taints: node-role.kubernetes.io/master:NoSchedule 信息显示格式: 节点包含一个污点,污点包含了 一 个key、value, 以及一个effect, 表现为<key>=<value>:<effect>。上面显示的主节点的污点信息,包含一 个为node-role.kubernet es.io/master的key, 一个空的value, 以及值为NoSchedule的effect。这个污点将阻止pod调度到这个节点上,除非有pod能容忍这个污点,而通常容忍这个污点的pod都是系 统级别pod pod 的污点容忍度 kubectl describe po kube-proxy-80asd -n kube-system ... ... Tolerations: node-role.kubernetes.io/master=:NoSchedule node.alpha.kubernetes.io/notReady=:Exists:NoExecute node.alpha.kubernetes.io/unreachable=:Exists:NoExecute ... ... 第一个污点容忍度匹配了某个节点的污点,表示允许这个 pod被调度到具有该污点的节点上。 kubectl get po kube-proxy-80asd -o yaml -n kube-system ... ... 注意: 尽管在pod的污点容忍度中显示了等号,但是在节点的污点信息中却没有。当污点或者污点容忍度中的value为null时,kubectl故意将污点和污点容忍度进行不同形式的显示。
污点的效果
如上所示另外两个在kube-proxy pod 上的污点定义了当节点状态是没有ready 或者是 unreachable 时,该 pod 允许运行在该节点多长时间(时间用秒来表示,这里没有显示但是在podYAML 中可以看到)。 这两个污点容忍度使用的效果是 NoExecute 而不是 NoSchedule。
每一个污点都可以关联一个效果, 效果包含了以下三种:
• NoSchedule 表示如果 pod 没有容忍这些污点, pod 则不能被调度到包含这些污点的节点上。
• PreferNoSchedule 是NoSchedule 的一个宽松的版本, 表示尽量阻止pod 被调度到这个节点上,但是如果没有其他节点可以调度,pod依然会被调度到这个节点上。
• NoExecute 不同于 NoSchedule 以及 PreferNoSchedule, 后两者只在调度期间起作用, 而 NoExecute 也会影响正在节点上运行着的 pod。 如果在一个节点上添加了
NoExecute 污点, 那些在该节点上运行着的 pod, 如果没有容忍这个 NoExecute 污点, 将会从这个节点去除。
在节点上添加自定义污点AND在pod上添加污点容忍度
在节点上添加自定义污点 假设你有一个单独的 Kubernetes 集群, 上面同时有生产环境和非生产环境的流量。 其中最重要的一点是, 非生产环境的 pod 不能运行在生产环境的节点上。 可以通过在生产环境的节点上添加污点来满足这个要求 $ kubect1 taint node nodel.k8s node-type=production:NoSchedule 这个命令添加了一个 taint,其中key为node-type, value为 production,效果为NoSchedule。 在pod上添加污点容忍度 apiVersion: extensions/vlbetal kind: Deployment metadata: name: prod spec: replicas: 5 template: spec: ... ... tolerations: - key: node-type operator: Equal value: production effect: NoSchedule
另外
1、节点可以拥有多个污点信息,而pod也可以有多个污点容忍度。正如你所见,污点可以只有一个key和 一 个效果,而不必设置value。污点容忍度可以通过设置Equal操作符来指定匹配的value (默认情况下的操作符),或者也可以通过设置Exists操作符来匹配污点的key。
2、配置节点失效之后的 pod 重新调度最长等待时间你也可以配置一个容忍度, 用于当某个pod运行所在的节点变成unready或者unreachable状态时,Kubemetes可以等待该pod被调度到其他节点的最长等待时间。
如果查看其中一个pod的容忍度信息, 你将看到两条容忍度信息,如下所示:
$ kubect1 get po prod-350605-lphSh -o yaml ... tolerations: - effect: NoExecute key: node.alpha.kubernetes.io/notReady operator: Exists tolerationSeconds: 300 - effect: NoExecute key: node.alpha.kubernetes.io/unreachable operator: Exists tolerationSeconds: 300 这两个容忍度表示, 该pod将容忍所在节点处于notReady或者unreachable状态维持300秒。 当Kubemetes控制器检测到有节 点处于notReady或者unreachable状态时,将会 等待300秒, 如果状态持续的话, 之后将把该pod重新调度到其他节点上。当没有定义这两个容忍度时, 他们会自动添加到pod上。 如果你觉得对于你的pod来说,5分钟 太长的话,可以在pod描述中显式地将这两个容忍度设置得更短一些。
notice:
当前这是一个 alpha阶段的特性,在未来的Kubemetes版本中可能会有所改变。基于污点信息的pod剔除也不是默认启用的, 如果要启用这个特性, 需要在运行控制器管理器时使用--feature-gates=TaintBasedEvictions=true 选项
亲缘性及与非亲缘性
节点亲缘性与非亲缘性都是根据节点的标签来进行选择, 这点跟节点选择器是一致的。与节点选择器类似, 每个 pod 可以定义自己的节点亲缘性规则。 这些规则可以允许你指定硬性限制或者偏好。 如果指定一种偏好的话, 你将告知 Kubemetes 对于某个特定的 pod, 它更倾向于调度到某些节点上, 之后 Kubemetes 将尽量把这个pod调度到这些节点上面。 如果没法实现的话, pod将被调度到其他某个节点上。
使用节点亲缘性将pod调度到特定节点上
污点可以用来让 pod 远离特定的几点。 现在, 你将学习一种更新的机制, 叫作节点亲缘性 (node affinity), 这种机制允许你通知 Kubemetes将 pod 只调度到某个节点子集上面。
默认的节点标签
$ kubectl describe node gke-kubia-default-pool-db274c5a-mjnf Name: gke-kubia-default-pool-db2 74c5a-mjnf Role: Labels: beta.kubernetes.io/arch=amd64 beta.kubernetes.io/fluentd beta.kubernetes.io/instance-type=fl-micro beta.kubernetes.io/os=linux cloud.google.com/gke-nodepool=default-pool failure-domain.beta.kubernetes.io/region=europe-westl failure-domain.beta.kubernetes.io/zone=europe-westl-d kubernetes.io/hostname=gke-kubia-default-pool-db274c5a-msd 这个节点有很多标签,但涉及节点亲缘性和 pod 亲缘性时,最后3个标签是最重要的。这3个标签的含义如下: failure domain beta.kubernetes /region 表示该节点所在的地理地域 failure domain beta kubernetes.io/zone 表示该节点所在的可用性区域( availibility zone ) kubernetes.io hostname 很显然是该节点的主机名
指定强制性节点亲缘性规则
apiVersion : ki nd: Pod metadata: name: kubia-gpu spec: affinity : nodeAffinity: requiredDuringSchedulingignoredDuringExecution: nodeSelectorTerms : - matchExpressions: - key: gpu operator: In values: - ”true” 解释: requiredDuringScheduling ... 表明了该宇段下定义的规则,为了让pod能调度到该节点上,明确指出了该节点必须包含的标签,也就是强制性的要求必须调度到规则匹配的标签的节点 ...IgnoredDuringExecution 表明了该字段下定义的规则, 不会影响己经在节点上运行着的 pod nodeSelectorTerrns 和 matchExpressions 字段,这两个宇段定义了节点的标签必须满足哪一种表达式,才能满足 pod 调度的条件。样例中的单个表达式比较容易理解,节点必须包含一个叫作 gpu 的标签,并且这个标签的值必须是 true
调度 pod 时优先考虑某些节点
当调度某 pod 时,指定调度器可以优先考虑哪些节点,这个功能是通过 preferredDuringSchedulingignoredDuringExecution 字段来实现的
给节点加上标签 $ kubectl label node nodel.k8s availability-zone=zonel $ kubectl label node nodel.k8s share-type=dedicated $ kubectl label node node2.k8s availability-zone=zone2 $ kubectl label node node2.k8s share-type=shared $ kubectl get node -L availability-zone -L share-type NAME STATUS AGE VERSION AVAILABILITY-ZONE SHARE-TYPE master.k8s Ready 4d vl.6.4 <none> <none> nodel.k8s Ready 4d vl.6.4 zonel dedicated node2.k8s Ready 4d vl.6.4 zone2 shared 指定优先级节点亲缘性规则 当这些节点的标签设置好,现在可以创建一个Deployment, 其中优先选择zonel中的dedicated节点。 apiVersion: extensions/vlbetal kind: Deployment metadata: name: pref spec: template: spec: affinity: nodeAffinity: preferredDuringSchedulingignoredDuringExecution: - weight: 80 preference: matchExpressions: - key: availability-zone operator: In values: - zonel - weight: 20 preference: matchExpressions: - key: share-type operator: in values: - dedicated 上面配置定义了一个节点亲缘性优先级,而不是强制要求。你想要pod被调度到包含标签availability-zone =zonel以及weight设置为80,而第二个优先级规则 就不那么重要(weight设置为20)。
了解节点优先级是如何工作的
如果你的集群包含多个节点, 当调度上面的代码清单中的Deployment pod时, 节点将会分成4个组, 如图所示。 那些包含Availability-zone以及share-type 标签, 并且匹配pod亲缘性的节点, 将排在最前面。 然后, 由于pod的节点亲缘性规则配置的权重, 接下来是zonel的shared节点, 然后是其他区域的dedicated节点, 优先级最低的是剩下的其他节点。