Kubernetes 节点调度
标签概述
标签是
Kubernetes
极具特色的功能之一,它能够附加于Kubernetes
的任何资源对象之上
简单来说,标签就是“键值”类型的数据,可以在资源创建时直接指定,也可以随时按需添加到活动对象中,而后即可由标签选择器进行匹配度检查从而完成资源挑选,一个对象可拥有不止一个标签,而同一个标签也可以被添加到至多个资源之上
标签操作
下面我们来演示下如何操作标签
准备工作
编辑POD资源清单
我们需要先在我们的服务上面启动一个POD
1 | vi nginx-pod.yml |
1 | apiVersion: v1 |
创建POD
1 | kubectl apply -f nginx-pod.yml |
查看标签
通过该命令可以查看POD的标签
1 | kubectl get pods --show-labels |
过滤标签
我们可以通过过滤标签来查看我们感兴趣的POD
1 | kubectl get pods -l app |
因为我们没有创建
app=tomcat
的标签
查看标签信息
我们可以通过使用以下命令来查看标签的内容
1 | kubectl get pods -L app |
添加标签
有时候我们需要给POD增加一个标签可以通过如下的方式
1 | kubectl label pod nginx env=prod |
这条命令给
nginx
的pod增加了一个env=prod
的标签
多条件过滤
有时候过滤标签可能是多个条件同时满足,我们可以使用逗号进行分割
1 | kubectl get pods -l app,env |
修改标签
修改已有的标签的值,同上面添加标签一样,只是添加–overwrite参数
1 | kubectl label pod nginx env=dev --overwrite |
删除标签
删除标签和添加标签类型,只需要在需要删除的标签名字后面加上
-
号
1 | kubectl label pod nginx env- |
标签选择器
标签选择器用于选择标签的查询条件或选择标准
kubernetes API
目前支持两个选择器:基于等值关系以及基于集合关系,例如,env=production
和env!=qa
是基于等值关系的选择器,而tier in(frontend,backend)
则是基于集合关系的选择器。
选择器逻辑
使用标签选择器时还将遵循以下逻辑:
- 同时指定的多个选择器之间的逻辑关系为“与”操作
- 使用空值的标签选择器意味着每个资源对象都将被选中
- 空的标签选择器将无法选出任何资源。
选择器类型
等值选择器
“=”、“==”和“!=”三种,其中前两个意义相同,都表示等值关系;最后一个表示不等关系
集合选择器
KEY in(VALUE1,VALUE2,…):指定的健名的值存在于给定的列表中即满足条件
KEY notin(VALUE1,VALUE2,…):指定的键名的值不存在与给定的列表中即满足条件
KEY:所有存在此健名标签的资源。
!KEY:所有不存在此健名标签的资源
演示示例
等值关系
查询标签
app
等于nginx
的pod
1 | kubectl get pods -l app=nginx |
查询标签
app
不等于nginx
的pod
1 | kubectl get pods -l app!=nginx |
集合关系示例
查询标签
app
包含nginx的pod
1 | kubectl get pods -l "app in(nginx)" |
查询标签
app
不包含nginx的pod
1 | kubectl get pods -l "app notin(nginx)" |
节点选择器
pod
节点选择器是标签及标签选择器的一种应用,它能够让pod
对象基于集群中工作节点的标签来挑选倾向运行的目标节点。
作用
在定义pod资源清单时,可以通过nodeName来指定pod运行的节点,或者通过nodeSelector来挑选倾向的节点
节点选择器操作
下面我们演示下节点选择器的一般操作
查看节点默认的标签
通过下面命令我们可以查看节点选择器的默认标签有哪些
1 | kubectl get nodes --show-labels |
节点添加标签
我们可以通过如下命令给节点添加标签
1 | kubectl label nodes node01 service=nginx |
节点修改标签
如上面,修改标签只需要在添加的基础上添加–overwrite参数
1 | kubectl label nodes node01 service=tomcat --overwrite |
删除节点标签
删除标签和添加标签类型,只需要在需要删除的标签名字后面加上
-
号
1 | kubectl label nodes node01 service- |
Pod调度器
kube-scheduler 是 kubernetes 的核心组件之一,主要负责整个集群资源的调度功能,根据特定的调度算法和策略,将 Pod 调度到最优的工作节点上面去,从而更加合理、更加充分的利用集群的资源,这也是我们选择使用 kubernetes 一个非常重要的理由。
什么是调度
调度,可以说是Kubernetes最核心的功能之一了
Pod是Kubernetes中最小的调度单元,而Pod又是运行在Node之上的,所谓调度,简单来说就是为一个新创建出来的 Pod,寻找一个最适合它运行的Node
调度流程
默认调度器
kube-scheduler负责分配调度Pod 到集群内的节点上,它监听kube-apiserver,查询还未分配Node的Pod,然后根据调度策略为这些Pod分配节点(更新Pod 的NodeName字段)
默认情况下,kube-scheduler 提供的默认调度器能够满足我们绝大多数的要求,我们前面和大家接触的示例也基本上用的默认的策略,都可以保证我们的 Pod 可以被分配到资源充足的节点上运行,但是在实际的线上项目中,可能我们自己会比 kubernetes 更加了解我们自己的应用,比如我们希望一个 Pod 只能运行在特定的几个节点上,或者这几个节点只能用来运行特定类型的应用,这就需要我们的调度器能够可控。
kube-scheduler 的主要作用就是根据特定的调度算法和调度策略将 Pod 调度到合适的 Node 节点上去,是一个独立的二进制程序,启动之后会一直监听 API Server,获取到 PodSpec.NodeName 为空的 Pod,对每个 Pod 都会创建一个 binding
需要考虑的因素
这个过程在我们看来好像比较简单,但在实际的生产环境中,需要考虑的问题就有很多了:
- 如何保证全部的节点调度的公平性?要知道并不是所有节点资源配置一定都是一样的
- 如何保证每个节点都能被分配资源?
- 集群资源如何能够被高效利用?
- 集群资源如何才能被最大化使用?
- 如何保证 Pod 调度的性能和效率?
- 用户是否可以根据自己的实际需求定制自己的调度策略
调度过程
调度主要分为以下几个部分
- 首先是预选过程,过滤掉不满足条件的节点,这个过程称为
Predicates
(过滤) - 然后是优选过程,对通过的节点按照优先级排序,称之为
Priorities
(打分) - 最后从中选择优先级最高的节点,如果中间任何一步骤有错误,就直接返回错误
Predicates
阶段首先遍历全部节点,过滤掉不满足条件的节点,属于强制性
规则,这一阶段输出的所有满足要求的节点将被记录并作为第二阶段的输入,如果所有的节点都不满足条件,那么 Pod 将会一直处于 Pending 状态,直到有节点满足条件,在这期间调度器会不断的重试。
所以我们在部署应用的时候,如果发现有 Pod 一直处于 Pending 状态,那么就是没有满足调度条件的节点,这个时候可以去检查下节点资源是否可用。
Priorities
阶段即再次对节点进行筛选,如果有多个节点都满足条件的话,那么系统会按照节点的优先级(priorites
)大小对节点进行排序,最后选择优先级最高的节点来部署 Pod 应用。
Pod调度策略
一般而言pod的调度都是通过RC、Deployment等控制器自动完成,但是仍可以通过手动配置的方式进行调度,目的就是让pod的调度符合我们的预期
但是在实际过程中,这并不满足需求,因为很多情况下,我们想控制某些pod到达某些节点上,那么应该怎么做呢?
调度策略分类
这就要求了解k8s对pod的调度规则,k8s提供了四大类调度方式:
- 自动调度:运行在哪个节点上完全由scheduler经过一系列的算法得出
- 定向调度:nodename、nodeselector
- 亲和性调度:nodeaffinity、podaffinity、podantiaffinity
- 污点(容忍)调度:Taints、toleration
调度原理
Kubernetes Scheduler 根据调度算法将 pod 调度到最优的节点上,和 OpenStack 和 Mesos 等非常类似,kube-scheduler 首先过滤不符合要求的节点,然后从符合要求的节点中根据权重选出最优节点,这两个步骤在 K8S 中分别被称为 predicates 和 priorities
predicates 类型
Predicates 主要有以下类型:
- PodFitsResources:节点 CPU,内存资源是否充足。
- 节点是否压力大:节点 CPU,内存,磁盘资源是否存在压力。
- Volume 相关调度:节点是否支持相应的云厂商,卷的数量是否超出上限等。
- MatchNodeSelector:节点亲和性调度,即 node affinity。
- MatchInterPodAffinity:容器之间的亲和性调度,即 pod affinity。
- 其它类型性
定向调度
定向调度,指的是利用在pod上声明nodename或者nodeselector,以此将pod调度到期望的node节点上。注意,这里的调度是强制的,这就意味着即使要调度目标node不存在,也会向上面进行调度,只不过pod运行失败而已
nodename调度
nodename用于强制约束将pod调度到指定的name的pod节点上,这种方式,其实是直接跳过scheduler的调度逻辑,直接写入podlist表
创建资源清单
下面的配置是将一个pod强制调度到node1节点
1 | vi pod-node-dispatch.yml |
1 | apiVersion: apps/v1 |
应用配置
下面我们应用配置文件
1 | kubectl apply -f pod-node-dispatch.yml |
删除pod
删除pod应用,pod控制器会重建pod
1 | kubectl delete pod nginx-deployment-596b9b7fb6-4b55h |
我们发现节点删除后,重新的应用还是落在了node1节点上,说明我们的节点调度生效的
调度不存在的节点
我们尝试将节点调度到一个不存在的节点,配置
nodeName: node03
1 | apiVersion: apps/v1 |
应用配置
1 | kubectl apply -f pod-node-dispatch.yml |
我们发现pod一直处于
Pending
状态,并没有成功创建,并且调度的节点是node03
可以看见虽然被指定在了node3,但是由于node3不存在,pod无法启动
nodeselector
nodeselector用于将pod调度到添加了指定标签的node节点上,它是通过k8s的label-selector机制实现的,也即是说,在pod创建之前,会由,scheduler使用matchnodeselector调度策略进行label匹配,找出目标node,然后将pod调度到目标节点,该匹配规则是强制约束
此时需要首先给指定的node打上标签,并在pod中设置nodeSelector属性以完成pod的指定调度。
创建标签
给node2添加上
disk=ssd
的标签
1 | kubectl label nodes node02 disk=ssd |
创建资源清单
我们创建一个节点调度的资源清单
1 | vi pod-node-selector-dispatch.yml |
1 | apiVersion: apps/v1 |
应用配置
1 | kubectl apply -f pod-node-selector-dispatch.yml |
我们发现两个POD现在都处于Node02的节点上
删除pod
删除pod应用,pod控制器会重建pod,我们通过标签将两个POD都给删除掉
1 | kubectl delete pod -l app=nginx |
我们发现POD重启后还是会被强制调度到node02节点上
亲和性调度
前面我们了解了 kubernetes 调度器的调度流程,我们知道默认的调度器在使用的时候,经过了 predicates 和 priorities 两个阶段,但是在实际的生产环境中,往往我们需要根据自己的一些实际需求来控制 Pod 的调度,这就需要用到 nodeAffinity(节点亲和性)、podAffinity(pod 亲和性) 以及 podAntiAffinity(pod 反亲和性)
亲和策略
亲和性调度可以分成软策略和硬策略两种方式,对于亲和性和反亲和性都有这两种规则可以设置:
preferredDuringSchedulingIgnoredDuringExecution
:软亲和requiredDuringSchedulingIgnoredDuringExecution
:硬亲和
软策略
软策略
就是如果现在没有满足调度要求的节点的话,Pod 就会忽略这条规则,继续完成调度过程,说白了就是满足条件最好了,没有的话也无所谓
硬策略
硬策略
就比较强硬了,如果没有满足条件的节点的话,就不断重试直到满足条件为止,简单说就是你必须满足我的要求,不然就不干了
节点亲和策略
定义节点亲和性规则的关键点有两个,一是为节点配置合乎需求的标签,另一个是为
Pod
对象定义合理的标签选择器,从而能够基于标签选择出符合期望的目标节点。
不过preferredDuringSchedulingIgnoredDuringExecution
和requiredDuringSchedulingIgnoredDuringExecution
名字中的后半段字符串IgnoredDuringExecution
隐含的意义所指,在Pod
资源基于节点亲和性规则调度至某节点之后,节点标签发生了改变而不再符合此节点亲和性规则时,调度器不会将Pod
对象从此节点上移除,因为它仅对新建的Pod
对象生效。
相比nodeSelector节点亲和可以匹配有更多的逻辑组合,不只是字符串的完全相等,支持的操作符有:In、NotIn、Exists、DoesNotExist、Gt、Lt
调度策略
调度分为软策略和硬策略,而不是硬性要求
- 硬(required):必须满足
- 软(preferred):尝试满足,但不保证
标签匹配逻辑
这里的匹配逻辑是 label 标签的值在某个列表中,现在 Kubernetes 提供的操作符有下面的几种:
- In:label 的值在某个列表中 (这里的操作符,我们一般只用到in就足够了;)
- NotIn:label 的值不在某个列表中
- Gt:label 的值大于某个值
- Lt:label 的值小于某个值
- Exists:某个 label 存在
- DoesNotExist:某个 label 不存在
但是需要注意的是如果
nodeSelectorTerms
下面有多个选项的话,满足任何一个条件就可以了;如果matchExpressions
有多个选项的话,则必须同时满足这些条件才能正常调度 Pod。
演示案例
创建资源清单
创建一个资源清单
1 | vi node-affinity.yaml |
1 | apiVersion: apps/v1 |
该资源清单包含两个亲和调度策略
- 节点硬亲和:不能调度到master节点,只能调度到node01,node02节点上
- 节点软亲和:尽量调度到
role=web
的节点上如果找不到则使用默认调度策略
查看节点的信息
我们先看下节点的
kubernetes.io/hostname
标签的信息
1 | kubectl get node -L kubernetes.io/hostname |
查看下节点的
role
标签信息
1 | kubectl get node -L role |
我们发现当前节点没有
role
标签
应用配置
应用配置后并查看节点信息
1 | kubectl apply -f node-affinity.yaml |
我们发现四个节点,并且没有被调度到
master
节点上,说明说明硬亲和策略生效了
添加标签
因为没添加
role=web
的标签,软亲和没有生效,我们给node02
添加上相应的标签
1 | kubectl label nodes node02 role=web |
查看节点分布情况,发现节点没有发生变化,说明节点亲和策略只针对于创建pod生效,已有的pod不会变化
重新应用配置
因为亲和策略只针对于创建有效,我们先删除pod然后在自动创建
1 | kubectl delete pod -l app=nginx |
我们发现重新创建标签后,节点的软亲和策略已经生效了,都已经调度到了
node02
节点上
POD 亲和策略
Pod 亲和性(podAffinity)主要解决 Pod 可以和哪些 Pod 部署在同一个拓扑域中的问题(其中拓扑域用主机标签实现,可以是单个主机,也可以是多个主机组成的 cluster、zone 等等),而 Pod 反亲和性主要是解决 Pod 不能和哪些 Pod 部署在同一个拓扑域中的问题,它们都是处理的 Pod 与 Pod 之间的关系。
比如一个 Pod 在一个节点上了,那么我这个也得在这个节点,或者你这个 Pod 在节点上了,那么我就不想和你待在同一个节点上。
这个是很重要的,线上业务基本要配置这种podAntiAffinity
演示案例
由于我们这里只有一个集群,并没有区域或者机房的概念,所以我们这里直接使用主机名来作为拓扑域,把 Pod 创建在同一个主机上面
创建busybox
因为我们的的调度用到了busybox容器,所以我们先创建一个busybox的POD
1 | vi pod-busybox.yaml |
1 | apiVersion: v1 |
并启动运行
1 | kubectl apply -f pod-busybox.yaml |
创建资源清单
我创建一个POD硬亲和的资源清单
1 | vi pod-affinity.yaml |
这里我们创建的是一个硬亲和,调度到的节点必须要有
app=busybox-pod
标签的pod
1 | apiVersion: apps/v1 |
应用配置
应用配置并查看POD的部署情况
1 | kubectl apply -f pod-affinity.yaml |
我们发现创建的三个POD都处于node02节点上,这个就是pod亲和
删除busybox-pod
我们删除掉busybox-pod在检查看POD的情况
1 | kubectl delete pod -l app=busybox-pod |
我们删除节点后,发现硬亲和的pod并没有收到影响,说明POD亲和调度也是在创建的时候才生效
重建Nginx
我们对nginx节点进行重建,然后看看情况,前提是busybox-pod已经被删除了
1 | kubectl delete pod -l app=nginx |
我们发现节点一直处于Pending状态,说明没有找到busybox-pod,不能进行创建nginx的pod,这个就是硬亲和
查看POD的详细信息
1 | kubectl describe pod pod-affinity-ff5d5f6cc-67lqf |
告诉我们没有可用的节点
拓扑域
我们这个地方使用的是
kubernetes.io/hostname
这个拓扑域,意思就是我们当前调度的 Pod 要和目标的 Pod 处于同一个主机上面,因为要处于同一个拓扑域下面。
为了说明这个问题,我们把拓扑域改成 beta.kubernetes.io/os
,同样的我们当前调度的 Pod 要和目标的 Pod 处于同一个拓扑域中,目标的 Pod 是拥有 beta.kubernetes.io/os=linux
的标签,而我们这里所有节点都有这样的标签,这也就意味着我们所有节点都在同一个拓扑域中,所以我们这里的 Pod 可以被调度到任何一个节点。
查看拓扑域
1 | kubectl get node -L kubernetes.io/hostname |
演示案例
我们重新运行上面的
app=busybox-pod
的 Pod,然后再更新下我们这里的资源对象:
修改资源清单
1 | vi pod-affinity.yaml |
我们修改资源清单,将
1 | apiVersion: apps/v1 |
应用配置
应用修改的配置
1 | kubectl apply -f pod-affinity.yaml |
可以看到现在是分别运行在2个节点下面的,因为他们都属于
beta.kubernetes.io/os
这个拓扑域(而busybox-pod
也刚好在这个域下,因此符合硬策略要求)。
这里需要注意下:通过上面这个实验可以看到,这2个node节点都属于beta.kubernetes.io/os
这个拓扑域,但只有node1上有app=pod-affitity
这个标签的pod,从结果可以看到也是可以调度到node2上的。
POD反亲和策略
Pod 反亲和性(podAntiAffinity)则是反着来的,比如一个节点上运行了某个 Pod,那么我们的模板 Pod 则不希望被调度到这个节点上面去了。
演示案例
运行busybox-pod
1 | kubectl apply -f pod-busybox.yaml |
修改资源清单
我们把上面的
podAffinity
直接改成podAntiAffinity
1 | vi pod-antiaffinity.yaml |
1 | apiVersion: apps/v1 |
这里的意思就是如果一个节点上面有一个 app=busybox-pod 这样的 Pod 的话,那么我们的 Pod 就别调度到这个节点上面来,也就是app=busybox-pod
和app=nginx
在一个节点上不能共存,上面我们把app=busybox-pod
这个 Pod 固定到了 node02 这个节点上面的,所以正常来说我们这里的 Pod 不会出现在该节点上
应用配置
我们创建POD
1 | kubectl apply -f pod-antiaffinity.yaml |
我们发现
app=busybox-pod
和app=nginx
处于两个不同的节点上不能部署在一起,这个就是反亲和
污点与容忍
污点(taints)是定义节点之上的键值型属性数据,用于让节点拒绝将
Pod
调度运行于其上,除非该Pod
对象具有接纳节点污点的容忍度。
而容忍度(tolerations)是定义在Pod
对象上的键值型属性数据,用于配置其可容忍的节点污点,而且调度器仅能将Pod
对象调度至其能够容忍该节点污点的节点之上,如下图所示:
上面的节点选择器(nodeSelector)和节点亲和性(nodeAffinity)两种调度方式都是通过在Pod
对象上添加标签选择器来完成对特定类型节点标签的匹配,它们实现的是由Pod
选择节点的机制。
而污点和容忍度则是通过向节点添加污点信息来控制Pod
对象的调度结果,从而赋予了节点控制何种Pod
对象能够调度于其上的主控权。简单来说,节点亲和性使得Pod
对象被吸引到一类特定的节点,而污点则相反,提供了让节点排斥特定Pod
对象的能量。
Kubernetes
使用PodToleratesNodeTaints
预选策略和TaintTolerationPriority
优选函数来完成此种类型的高级调度机制。
应用场景
- 专用节点:根据业务线将Node分组管理,希望在默认情况下不调度该节点,只有配置了污点容忍才允许分配
- 配备特殊硬件:部分Node配有SSD硬盘、GPU,希望在默认情况下不调度该节点,只有配置了污点容忍才允许分配
- 基于Taint的驱逐
对于 nodeAffinity 无论是硬策略还是软策略方式,都是调度 Pod 到预期节点上。而污点(Taints)恰好与之相反,如果一个节点标记为 Taints ,除非 Pod 也被标识为可以容忍污点节点,否则该 Taints 节点不会被调度 Pod。
比如用户希望把 Master 节点保留给 Kubernetes 系统组件使用,或者把一组具有特殊资源预留给某些 Pod,则污点就很有用了,Pod 不会再被调度到 taint 标记过的节点,我们使用 kubeadm 搭建的集群默认就给 master 节点添加了一个污点标记,所以我们看到我们平时的 Pod 都没有被调度到 master 上去。
容忍度定义
污点定义在节点的
nodeSpec
中,容忍度定义在Pod
的podSpec
中,都是键值型数据,都额外支持(effect)标记,语法格式为”key=value:effect”,其中key
和value
的用法及格式与资源注解信息相似,而effect
则用于定义对Pod
对象的排斥等级,
容忍度类型
容忍度主要包含以下三种类型:
- NoSchedule:不能容忍此污点的新
Pod
对象不可调度至当前节点,属于强制型约束关系,节点上现存的Pod
对象不受影响。 - PreferNoSchedule:
NoSchedule
的柔性约束版本,即不能容忍此污点的新Pod
对象尽量不要调度至当前节点,不过无其它节点可供调度时也允许接受相应的Pod
对象,节点上现存的Pod
对象不受影响。 - NoExecute:不能容忍此污点的新
Pod
对象不可调度至当前节点,属于强制型约束关系,而且节点上现存的Pod
对象因节点污点变动或Pod
容忍度变动而不再满足匹配规则时,Pod
对象将被驱逐。
容忍度操作符
在
Pod
对象上定义容忍度时,支持两种操作符:
等值比较(Equal),表示容忍度与污点必须在
key
、value
和effect
三者之上完全匹配;存在性判断(Exists),表示二者的
key
和effect
必须完全匹配,而容忍度中的value
字段要使用空值。
污点定义
污点:其实是一个label标签,只不过它是一个特殊的label标签。
污点匹配规则
一个节点可以配置使用多个污点,一个
Pod
对象也可以有多个容忍度,不过二者在进行匹配检查时遵循如下逻辑:
- 首先处理每个有着与之匹配的容忍度的污点。
- 不能匹配到的污点上,如果存在了一个使用
NoSchedule
效用标识,则拒绝调度Pod
对象至此节点。 - 不能匹配到的污点上,若没有任何一个使用了
NoSchedule
效用标识,但至少有一个使用了PreferNoScheduler
,则应尽量避免将Pod
对象调度至此节点。 - 如果至少有一个不匹配的污点使用了
NoExecute
效用标识,则节点将立即驱逐Pod
对象,或者不予调度至给定节点;另外,即便容忍度可以匹配到使用了NoExecute
效用标识的污点,若在定义容忍度时还同时使用tolerationSeconds
属性定义了容忍时限,则超出时限后期也将被节点驱逐。
默认污点
使用
kubeadm
部署的Kubernetes
集群,其Master
节点将自动添加污点信息以阻止不能容忍此污点的Pod
对象调度至此节点,因此,用户手动创建的未特意添加容忍此污点容忍度的Pod
对象将不会被调度至此节点:
1 | kubectl describe node master |grep Taints |
污点管理
污点定义规则
任何符合其键值规范要求的字符串均可用于定义污点信息:仅可使用字母、数字、连接符、点号和下划线,且仅能以字母或数字开头,其中键名长度上限为253个字符,值最长为63个字符。
可以用污点用来描述具体的部署规划,键名比如node-type、node-role、node-project或node-geo等,还可以在必要时戴上域名以描述其额外的信息,如node-type.ilinux.io等。
添加污点
需要注意的是,即便是同一个键值数据,若其效用标识不同,则其也分属于不同的污点信息
添加NoSchedule污点
我们给node01添加一个
node-type=production
的污点,并且这个污点属于NoSchedule类型
1 | kubectl taint nodes node01 node-type=production:NoSchedule |
此时,
node01
上已有的Pod
对象不受影响,但新建的Pod
若不能容忍此污点将不能再被调度至此节点
添加NoExecute污点
我们给node01添加一个
node-type=production
的污点,并且这个污点属于NoExecute类型
1 | kubectl taint nodes node01 node-type=production:NoExecute |
此时,
node01
上已有的Pod
将会被驱逐出去
查看污点信息
我们可以通过如下命令来查看污点信息
1 | kubectl get nodes node01 -o go-template={{.spec.taints}} |
删除污点
删除污点,仍通过
kubectl taint
命令进行,但是要使用如下的命令格式,省略效用标识则表示删除使用指定键名的所有污点,否则就只是删除指定健名上对应效用标识的污点:
命令格式
1 | kubectl taint nodes <node-name> <key>[:<effect>]- |
删除单个污点
我们把刚刚创建的污点删除掉
1 | kubectl taint nodes node01 node-type:NoSchedule- |
删除所有污点
若要删除使用指定健名的所有污点,则在删除命令中省略效用标识即能实现
1 | kubectl taint nodes node01 node-type- |
POD容忍度
Pod
对象的容忍度可通过其spec.tolerations
字段进行添加,根据使用的操作符不同,主要有两种可用的形式:
一种是与污点信息完全匹配的等值关系;
另一种是判断污点信息存在性的匹配方式。
使用Equal
操作符的示例如下所示,其中tolerationSeconds
用于定义延迟驱逐当前Pod
对象的时长。
tolerations属性
对于
tolerations
属性的写法,其中的 key、value、effect 与 Node 的 Taint 设置需保持一致, 还有以下几点说明:
- 如果 operator 的值是
Exists
,则 value 属性可省略 - 如果 operator 的值是
Equal
,则表示其 key 与 value 之间的关系是 equal(等于) - 如果不指定 operator 属性,则默认值为
Equal
两个特殊值
- 空的 key 如果再配合
Exists
就能匹配所有的 key 与 value,也就是是能容忍所有节点的所有 Taints - 空的 effect 匹配所有的 effect
NoSchedule容忍度
创建资源清单
1 | vi deploy-taint-deployment.yml |
1 | apiVersion: apps/v1 |
我们创建了一个普通的
Deployment
,然后应用配置
1 | kubectl apply -f deploy-taint-deployment.yml |
创建污点
我们在node01节点上创建一个
NoSchedule
的污点
1 | kubectl taint node node01 node-type=production:NoSchedule |
查看POD部署
我们再来查看下POD的部署情况
1 | kubectl get pod -o wide |
我们发现POD没有任何变化,说明
NoSchedule
不针对已经部署的服务
删除POD
下面我们删除掉POD,然后再查看POD的部署情况
1 | kubectl delete pod -l app=nginx |
我们发现新创建的POD都已经部署到了node02节点,说明
NoSchedule
只针对于新创建的POD
配置容忍度
现在我们改写配置文件,增加POD的容忍度,让POD可以容忍
NoSchedule
1 | apiVersion: apps/v1 |
这里我们配置了POD的容忍度,让POD可以在
node-type=production:NoSchedule
的node上生存
1 | kubectl apply -f deploy-taint-deployment.yml |
我看看到一旦配置容忍度后,我们的pod就被调度到了node1节点上,这个就是pod的容忍度
NoExecute容忍度
查看POD部署
我们现在先看下服务的部署情况
1 | kubectl get pod -o wide |
我们看下当前我们的POD运行在node01和node02节点上
创建污点
我们在node02节点上创建一个
NoExecute
的污点
1 | kubectl taint node node02 node-type=production:NoExecute |
查看POD部署
现在我们在看下POD的部署情况
1 | kubectl get pod -o wide |
我们发现node02上面的POD已经被驱逐出去了,说明
NoExecute
不允许运行没有容忍度的POD
配置容忍度
我们编辑资源清单,并让POD的容忍度支持
NoExecute
1 | vi deploy-taint-deployment.yml |
1 | apiVersion: apps/v1 |
这里我们配置了POD的容忍度,让POD可以在
node-type=production:NoExecute
的node上生存
1 | kubectl apply -f deploy-taint-deployment.yml |
我们设置容忍度后,就会被调度到了node02节点,但是这个容忍度不会被调度到了node01节点上
Exists容忍度
我们可以通过
Exists
进行判断,修改资源配置清单如下,下面这段表示,只要有污点key为node-type
,不论值为什么且是什么类型的污点,都能容忍
编辑资源清单
1 | apiVersion: apps/v1 |
应用配置
因为我们两个节点的污点都配置了
node-type=production
,而我们配置的是Exists
容忍度,则可以将pod部署在node01,node02
1 | kubectl apply -f deploy-taint-deployment.yml |