一、污点和容忍概述
1、概念
K8S官方关于Taints and Tolerations概述
Taints和Tolerations和搭配使用的,Taints定义在Node节点上,声明污点及标准行为,Tolerations定义在Pod,声明可接受得污点。
在《K8S之节点亲和性》中,我们说到的的NodeAffinity节点亲和性,是在pod上定义的一种属性,使得Pod能够被调度到某些node上运行。Taint刚好相反,它让Node拒绝Pod的运行。
Taint需要与Toleration配合使用,让pod避开那些不合适的node。在node上设置一个或多个Taint后,除非pod明确声明能够容忍这些“污点”,否则无法在这些node上运行。Toleration是pod的属性,让pod能够(注意,只是能够,而非必须)运行在标注了Taint的node上。
污点
更新一个或多个节点上的污点。
污点由键、值和效果组成。作为这里的参数,它表示为 key=value:effect。
密钥必须以字母或数字开头,并且可以包含字母、数字、连字符、点和下划线,最多 253 个字符。
或者,密钥可以以 DNS 子域前缀和单个“/”开头,例如 example.com/my-app。
该值是可选的。如果给出,它必须以字母或数字开头,并且可以包含字母、数字、连字符、点和下划线,最多 63 个字符。
效果必须是 NoSchedule、PreferNoSchedule 或 NoExecute。
目前污点只能应用于节点。
2、基本用法
设置污点:
kubectl taint node [node] key=value[effect]
其中[effect] 可取值: [ NoSchedule | PreferNoSchedule | NoExecute ]
NoSchedule :一定不能被调度。
PreferNoSchedule:尽量不要调度。
NoExecute:不仅不会调度,还会驱逐Node上已有的Pod。
#示例:
kubectl taint node 10.3.1.16 test=16:NoSchedule
去除污点:
#比如设置污点:
kubectl taint node 10.3.1.16 test=16:NoSchedule
kubectl taint node 10.3.1.16 test=16:NoExecute
#去除指定key及其effect:
kubectl taint nodes node_name key:[effect]- #(这里的key不用指定value)
#去除指定key所有的effect:
kubectl taint nodes node_name key-
#示例:
kubectl taint node 10.3.1.16 test:NoSchedule-
kubectl taint node 10.3.1.16 test:NoExecute-
kubectl taint node 10.3.1.16 test-
下面是一个简单的示例:
在node1上加一个Taint,该Taint的键为key,值为value,Taint的效果是NoSchedule。这意味着除非pod明确声明可以容忍这个Taint,否则就不会被调度到node1上:
kubectl taint nodes node1 key=value:NoSchedule
然后需要在pod上声明Toleration。下面的Toleration设置为可以容忍具有该Taint的Node,使得pod能够被调度到node1上:
apiVersion: v1
kind: Pod
metadata:
name: pod-taints
spec:
tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"
containers:
- name: pod-taints
image: busybox:latest
也可以写成如下:
tolerations:
- key: "key"
operator: "Exists"
effect: "NoSchedule"
pod的Toleration声明中的key和effect需要与Taint的设置保持一致,并且满足以下条件之一:
operator的值为Exists,这时无需指定value
operator的值为Equal并且value相等
如果不指定operator,则默认值为Equal。
另外还有如下两个特例:
空的key配合Exists操作符能够匹配所有的键和值
空的effect匹配所有的effect
Update node 'foo' with a taint with key 'dedicated' and value 'special-user' and effect 'NoSchedule' # 如果已经存在具有该键和效果的污点,则按指定替换其值
kubectl taint nodes foo dedicated=special-user:NoSchedule
从节点 'foo' 中删除键为 'dedicated' 的污点,如果存在则影响 'NoSchedule'
kubectl taint nodes foo dedicated:NoSchedule-
从节点 'foo' 中删除所有带有键 'dedicated' 的污点
kubectl taint nodes foo dedicated-
在标签为 mylabel=X 的节点上添加带有键 'dedicated' 的污点
kubectl taint node -l myLabel=X dedicated=foo:PreferNoSchedule
向节点 'foo' 添加一个带有键 'bar' 且没有值的污点
kubectl taint nodes foo bar:NoSchedule
3、effect说明
上面的例子中effect的取值为NoSchedule,下面对effect的值作下简单说明:
NoSchedule: 如果一个pod没有声明容忍这个Taint,则系统不会把该Pod调度到有这个Taint的node上
PreferNoSchedule:NoSchedule的软限制版本,如果一个Pod没有声明容忍这个Taint,则系统会尽量避免把这个pod调度到这一节点上去,但不是强制的。
NoExecute:定义pod的驱逐行为,以应对节点故障。NoExecute这个Taint效果对节点上正在运行的pod有以下影响:
没有设置Toleration的Pod会被立刻驱逐
配置了对应Toleration的pod,如果没有为tolerationSeconds赋值,则会一直留在这一节点中
配置了对应Toleration的pod且指定了tolerationSeconds值,则会在指定时间后驱逐
从kubernetes 1.6版本开始引入了一个alpha版本的功能,即把节点故障标记为Taint(目前只针对node unreachable及node not ready,相应的NodeCondition "Ready"的值为Unknown和False)。激活TaintBasedEvictions功能后(在–feature-gates参数中加入TaintBasedEvictions=true),NodeController会自动为Node设置Taint,而状态为"Ready"的Node上之前设置过的普通驱逐逻辑将会被禁用。注意,在节点故障情况下,为了保持现存的pod驱逐的限速设置,系统将会以限速的模式逐步给node设置Taint,这就能防止在一些特定情况下(比如master暂时失联)造成的大量pod被驱逐的后果。这一功能兼容于tolerationSeconds,允许pod定义节点故障时持续多久才被逐出。
4、配置
多污点与多容忍配置
系统允许在同一个node上设置多个taint,也可以在pod上设置多个Toleration。Kubernetes调度器处理多个Taint和Toleration能够匹配的部分,剩下的没有忽略掉的Taint就是对Pod的效果了。下面是几种特殊情况:
如果剩余的Taint中存在effect=NoSchedule,则调度器不会把该pod调度到这一节点上。
如果剩余的Taint中没有NoSchedule的效果,但是有PreferNoSchedule效果,则调度器会尝试不会pod指派给这个节点
如果剩余Taint的效果有NoExecute的,并且这个pod已经在该节点运行,则会被驱逐;如果没有在该节点运行,也不会再被调度到该节点上。
kubectl taint nodes node1 key1=value1:NoSchedule
kubectl taint nodes node1 key1=value1:NoExecute
kubectl taint nodes node1 key2=value2:NoSchedule
5、示例
诊断报错
NODE_WITH_INTOLERABLE_TAINT/所有满足nodeSelector的节点均存在pod无法容忍的污点
查看pod处于pending状态
查看events事件报错没有合适的node可以调度
kubectl get pod
kubectl get nodes -o=custom-columns=NodeName:.metadata.name,TaintKey:.spec.taints[*].key,TaintValue:.spec.taints[*].value,TaintEffect:.spec.taints[*].effect
kubectl describe po {pod_name}
kubectl get node
kubectl get node {node_name} -o go-template --template='{{.spec.taints}}'
kubectl taint node {node_name} {key}:{effect}-
再次查看pod
二、节点亲和
1、概念
Node Affinity
Affinity 翻译成中文是“亲和性”,它对应的是 Anti-Affinity,我们翻译成“互斥”。这两个词比较形象,可以把 pod 选择 node 的过程类比成磁铁的吸引和互斥,不同的是除了简单的正负极之外,pod 和 node 的吸引和互斥是可以灵活配置的。
Affinity的优点:
匹配有更多的逻辑组合,不只是字符串的完全相等
调度分成软策略(soft)和硬策略(hard),在软策略下,如果没有满足调度条件的节点,pod会忽略这条规则,继续完成调度。
目前主要的node affinity:
requiredDuringSchedulingIgnoredDuringExecution
表示pod必须部署到满足条件的节点上,如果没有满足条件的节点,就不停重试。其中IgnoreDuringExecution表示pod部署之后运行的时候,如果节点标签发生了变化,不再满足pod指定的条件,pod也会继续运行。
requiredDuringSchedulingRequiredDuringExecution
表示pod必须部署到满足条件的节点上,如果没有满足条件的节点,就不停重试。其中RequiredDuringExecution表示pod部署之后运行的时候,如果节点标签发生了变化,不再满足pod指定的条件,则重新选择符合要求的节点。
preferredDuringSchedulingIgnoredDuringExecution
表示优先部署到满足条件的节点上,如果没有满足条件的节点,就忽略这些条件,按照正常逻辑部署。
preferredDuringSchedulingRequiredDuringExecution
表示优先部署到满足条件的节点上,如果没有满足条件的节点,就忽略这些条件,按照正常逻辑部署。其中RequiredDuringExecution表示如果后面节点标签发生了变化,满足了条件,则重新调度到满足条件的节点
软策略和硬策略的区分是有用处的,硬策略适用于 pod 必须运行在某种节点,否则会出现问题的情况,比如集群中节点的架构不同,而运行的服务必须依赖某种架构提供的功能;软策略不同,它适用于满不满足条件都能工作,但是满足条件更好的情况,比如服务最好运行在某个区域,减少网络传输等。这种区分是用户的具体需求决定的,并没有绝对的技术依赖。
2、官网案例
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/e2e-az-name
operator: In
values:
- e2e-az1
- e2e-az2
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value
containers:
- name: with-node-affinity
image: gcr.io/google_containers/pause:2.0
这个 pod 同时定义了 requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution 两种 nodeAffinity。第一个要求 pod 运行在特定 AZ 的节点上,第二个希望节点最好有对应的 another-node-label-key:another-node-label-value 标签。
这里的匹配逻辑是label在某个列表中,可选的操作符有:
In: label的值在某个列表中
NotIn:label的值不在某个列表中
Exists:某个label存在
DoesNotExist:某个label不存在
Gt:label的值大于某个值(字符串比较)
Lt:label的值小于某个值(字符串比较)
如果nodeAffinity中nodeSelector有多个选项,节点满足任何一个条件即可;如果matchExpressions有多个选项,则节点必须同时满足这些选项才能运行pod 。
需要说明的是,node并没有anti-affinity这种东西,因为NotIn和DoesNotExist能提供类似的功能。