K8s调度之污点与容忍

前言

前面介绍了节点亲和性调度,它可以使得我们的Pod调度到指定的Node节点上,而污点(Taints)与之相反,它可以让Node拒绝Pod的运行,甚至驱逐已经在该Node上运行的Pod

污点是Node上设置的一个属性,通常设置污点表示该节点有问题,比如磁盘要满了,资源不足,或者该Node正在升级暂时不能提供使用等情况,这时不希望再有新的Pod进来,这个时候就可以给该节点设置一个污点。

但是有的时候其实Node节点并没有故障,只是不想让一些Pod调度进来,比如这台节点磁盘空间比较大,希望是像Elasticsearch、Minio这样需要较大磁盘空间的Pod才调度进来,那么就可以给节点设置一个污点,给Pod设置容忍(Tolerations)对应污点,如果再配合节点亲和性功能还可以达到独占节点的效果

一般时候 Taints 总是与 Tolerations配合使用

污点(Taints)

我们已经知道了设置污点后,一般Pod将不会调度到该节点上来,大家看过我先前的文章会发现,我的K8s集群有三个节点,分别是master、node01、node02,但是每次Pod都不会调度到master节点,那是因为搭建K8s集群的时候,K8s给master自带了一个污点。

查看污点

查看master上是否有污点,通过describe命令可以看到节点上的所有污点

[root@master ~]# kubectl describe node master
...
Taints:             node-role.kubernetes.io/master:NoSchedule
...

还可以通过如下命令查看

[root@master ~]# kubectl get nodes master -o go-template={{.spec.taints}}
[map[effect:NoSchedule key:node-role.kubernetes.io/master]]

发现master上自带了一个没有value的污点 node-role.kubernetes.io/master ,effect 为 NoSchedule,由于我们的Pod都没有容忍这个污点,所以一直都不会调度到master

污点类别

上面我们看到了污点有一个effect 属性为NoSchedule,其实还有其它两种类别分别是 PreferNoSchedule与 NoExecute

  • NoSchedule: 如果没有容忍该污点就不能调度进来。
  • PreferNoSchedule: 相当于NoExecute的一个软限制,如果没有容忍该污点,尽量不要把Pod调度进来,但也不是强制的。
  • NoExecute: 如果没有设置容忍该污点,新的Pod肯定不会调度进来, 并且已经在运行的Pod没有容忍该污点也会被驱逐
设置污点

污点分别由key、value(可以为空)、effect 组成,设置命令如下

# 设置污点并不允许Pod调度到该节点
$ kubectl taint node node01 key=value:NoSchedule
# 设置污点尽量不要让Pod调度到该节点
$ kubectl taint node node01 key=value:PreferNoSchedule
# 设置污点,不允许Pod调度到该节点,并且且将该节点上没有容忍该污点的Pod将进行驱逐
$ kubectl taint node node01 key=value:NoExecute
删除污点
# 删除该key的所有污点
$ kubectl taint node node01 key-
# 删除该key的某一个污点
$ kubectl taint node node01 key=value:NoSchedule-
# 删除该key的某一个污点可以不写value
$ kubectl taint node node01 key:NoSchedule-
污点测试

给node01节点设置一个污点,表示只有前台web应用才能调度,后端app应用不能调度

[root@master ~]# kubectl taint node node01 web=true:NoSchedule
node/node01 tainted

编写 web-taint.yaml 内容如下,有三个Pod均没有容忍该污点

apiVersion: v1
kind: Pod
metadata:
  name: web-taint1
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent # 本地有不拉取镜像
---
apiVersion: v1
kind: Pod
metadata:
  name: web-taint2
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent # 本地有不拉取镜像
---
apiVersion: v1
kind: Pod
metadata:
  name: web-taint3
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent # 本地有不拉取镜像

启动Pod,观察Pod是否都被调度到node02节点

# 启动三个Pod
[root@master taint]# kubectl create -f web-taint.yaml 
pod/web-taint1 created
pod/web-taint2 created
pod/web-taint3 created

# 查看pod详情发现均被调度到node02节点
[root@master taint]# kubectl get pod -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
web-taint1   1/1     Running   0          13s   10.244.2.35   node02   <none>           <none>
web-taint2   1/1     Running   0          13s   10.244.2.34   node02   <none>           <none>
web-taint3   1/1     Running   0          13s   10.244.2.36   node02   <none>           <none>

给node02节点天津污点 app=true:NoExecute,表示只有后端服务才能调度进来,并且已经在node02节点上运行的不是后端服务的节点将被驱逐

# 设置污点
[root@master taint]# kubectl taint node node02 app=true:NoExecute
node/node02 tainted
# 查看Pod详情,发现三个Pod已经被驱逐
[root@master taint]# kubectl get pod -o wide
No resources found in default namespace.

从上面可以知道我们虽然设置了污点,但是我们的节点其实很正常,既然是正常节点,那么就可以有服务运行,这就需要用到容忍机制来运行这些Pod

容忍(Toletations)

如果需要Pod忽略Node上的污点,就需要给Pod设置容忍,并且是需要容忍该Pod上的所有污点。

通过 kubectl explain pod.spec.tolerations 可以查看容忍的配置项

配置项
tolerations: # 数组类型,可以设置多个容忍
- key: # 污点key
  operator: # 操作符,有两个选项 Exists and Equal 默认是Equal
  value: # 污点value,如果使用Equal需要设置,如果是Exists就不需要设置
  effect: # 可以设置为NoSchedule、PreferNoSchedule、NoExecute,如果为空表示匹配该key下所有污点,
  tolerationSeconds: # 如果污点类型为NoExecute,还可以设置一个时间,表示这一个时间段内Pod不会被驱逐,过了这个时间段会立刻驱逐,0或者负数会被立刻驱逐
设置容忍

给Pod设置容忍node01节点的污点web=true:NoSchedule

编写 web-tolerations.yaml 内容如下,容忍污点web=true:NoSchedule

apiVersion: v1
kind: Pod
metadata:
  name: web-tolerations
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent # 本地有不拉取镜像
  tolerations:
  - key: web
    operator: Equal
    value: "true"
    effect: NoSchedule

启动web-tolerations,观察Pod是否正常运行

# 启动web-tolerations
[root@master taint]# kubectl create -f web-tolerations.yaml  
pod/web-tolerations created

# Pod正常运行,且运行在node01节点
[root@master taint]# kubectl get pod -o wide
NAME              READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
web-tolerations   1/1     Running   0          8s    10.244.1.92   node01   <none>           <none>

查看该Pod上的容忍

[root@master taint]# kubectl describe pod web-tolerations

Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
                             web=true:NoSchedule

可以看到我们设置的Tolerations在里边,除了我们自己的,K8s还会给每个Pod设置两个默认Tolerations,并且Tolerations时间为五分钟,表示某些节点发生一些临时性问题,Pod能够继续在该节点上运行五分钟等待节点恢复,并不是立刻被驱逐,从而避免系统的异常波动


编写 app-tolerations.yaml 内容如下,容忍污点app=true:NoExecute,并且只容忍60s

apiVersion: v1
kind: Pod
metadata:
  name: app-tolerations
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  tolerations:
  - key: app
    operator: Exists
    effect: NoExecute
    tolerationSeconds: 60

启动app-tolerations,查看Pod是否能够正常运行,且运行在node02节点,等待60秒,查看Pod是否已被驱逐

# 启动app-tolerations
[root@master taint]# kubectl create -f app-tolerations.yaml 
pod/app-tolerations created

# 查看详情,已经运行成功并且调度到了node02节点,此时运行59秒
[root@master taint]# kubectl get pod -o wide
NAME              READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
app-tolerations   1/1     Running   0          59s   10.244.2.37   node02   <none>           <none>

# 运行60秒查看,状态已经变为Terminating
[root@master taint]# kubectl get pod -o wide
NAME              READY   STATUS        RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
app-tolerations   1/1     Terminating   0          60s   10.244.2.37   node02   <none>           <none>

# 立刻再次查看,已经被驱逐
[root@master taint]# kubectl get pod -o wide
No resources found in default namespace.

如果一个节点没有任何污点,另一个节点有污点,并且Pod容忍了该污点,那么最终会调度到哪个节点呢?

删除node02节点的污点app=true:NoExecute,保留node01节点的web=true:NoSchedule,再次启动之前的web-tolerations.yaml 观察Pod所在节点

# 删除node02上的污点
[root@master taint]# kubectl taint node node02 app:NoExecute- 
node/node02 untainted

# 启动Pod web-tolerations
[root@master taint]# kubectl create -f web-tolerations.yaml 
pod/web-tolerations created

# Pod正常运行,并且运行在node02节点
[root@master taint]# kubectl get pod -o wide                 
NAME              READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
web-tolerations   1/1     Running   0          2s    10.244.2.38   node02   <none>           <none>

上面表明,即使是容忍了该污点,如果有其它节点不需要容忍就可以调度的话,那还是会优先选择没有污点的机器,但是生产上往往设置污点就是为了给你这个Pod使用的,不能调度到其它节点,这个时候需要配合节点亲和性调度一起使用。

Equal 与 Exists

Exists 表示key是否存在所以无需设置value,Equal 则必须设置value需要完全匹配,默认为Equal

空的key配合Exists 可以匹配所有的key-value,也就是容忍所有的污点,生产上非常不建议使用

节点故障后Pod的驱逐行为

上面也提到了,K8s为每个Pod设置了两个容忍,如果是一些临时性故障,可以容忍五分钟不被驱逐

在K8s 1.6之后还引入了Taint的两个新特性,TaintNodesByCondition与TaintBasedEvictions用来改善出现异常时对Pod的调度与驱逐问题

TaintNodesByCondition的特性如下(为节点添加NoSchedule的污点)

  • Node节点会不断的检查Node的状态,并且设置对应的Condition
  • 不断地根据Condition的变更设置对应的Taint
  • 不断地根据Taint驱逐Node上的Pod

主要污点如下

node.kubernetes.io/not-ready 节点未就绪,节点Ready为False

node.kubernetes.io/unreachable 节点不可触达

node.kubernetes.io/out-of-disk 磁盘空间已满

node.kubernetes.io/network-unavailable 网络不可用

node.kubernetes.io/unschedulable 节点不可调度

node.cloudprovider.kubernetes.io/uninitialized 如果 kubelet 从 外部 云服务商启动的,该污点用来标识某个节点当前为不可用状态,当云控制器 cloud-controller-manager 初始化这个节点后,kubelet 会将此污点移除

**TaintBasedEvictions **特性添加的是NoExecute的污点,例如内存与磁盘有压力时,如果Pod没有设置容忍这些污点,则会被驱逐,以保证Node不会崩溃

主要污点如下

node.kubernetes.io/memory-pressure 内存不足

node.kubernetes.io/disk-pressure 磁盘不足

1.13版本之后TaintNodesByCondition 与 TaintBasedEvictions 都是默认开启


污点与容忍就介绍到这里,后面将会介绍Pod的控制器。

欢迎关注,学习不迷路!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容