上一篇笔记的结尾处我们简单提了一下标签,并通过标签将pod指定给了某个node,因为当时写的时候比较晚了,所以并没有一次性写完,这篇我们接着看标签
在我们使用命令kubectl get nodes查看节点的时候,你会发现有一栏是ROLES,只有master是有的,其他节点都是none
[root@master k8s]# kubectl get nodes NAME STATUS ROLES AGE VERSION master Ready control-plane 2d1h v1.26.0 node1 Ready <none> 2d1h v1.26.0 node2 Ready <none> 2d1h v1.26.0
他默认就是这样显示的,当然,如果你使用的k8s集群版本是1.21或者1.22之前的版本,那么他先是的就是master,而不是control-plane,这个无关竟要,版本问题
现在node1和node2这一栏显示的空的,我们可以修改他吗?当然是可以的,没有任何的问题,修改他其实就是修改标签
# 我们先查看master节点,他既然有这个值,那么他肯定是有一些node节点没有的标签的 [root@master k8s]# kubectl get nodes/master --show-labels NAME STATUS ROLES AGE VERSION LABELS master Ready control-plane 2d1h v1.26.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
我们在标签栏位里面可以找到 node-role.kubernetes.io/control-plane=
你可以查看一下node节点的,是没有的,而且他这个好像是没有value的,只有key,那他好像就是读取的control-plane这个内容,那我么如果加上一个前缀跟他一样的,但是最后这里我们将他修改成其他值,我们来看看效果
# 我们同样不给他value [root@master k8s]# kubectl label nodes master node-role.kubernetes.io/master= node/master labeled # 现在我们再来查看一下这个节点的角色 [root@master k8s]# kubectl get nodes/master NAME STATUS ROLES AGE VERSION master Ready control-plane,master 2d1h v1.26.0
我们会发现他确实是把master加上去了,其实这个标签是很特殊的,它并不需要value,如果你想要给他value也是可以的,不会报错,但是他并不会使用你给的value来当他的角色
# 我们已经知道他的规则了,那我们想要修改就非常的容易了 [root@master k8s]# kubectl label nodes node1 node-role.kubernetes.io/node1= [root@master k8s]# kubectl label nodes node2 node-role.kubernetes.io/node2=
我们来验证一下
[root@master k8s]# kubectl get nodes NAME STATUS ROLES AGE VERSION master Ready control-plane,master 2d1h v1.26.0 node1 Ready node1 2d1h v1.26.0 node2 Ready node2 2d1h v1.26.0
没有任何的问题
我们之前是可以通过一些方法,将pod指定到节点上去创建,那么为什么要这么干呢,为什么不让他自己调度呢
我们可以这样设想一下,如果你用的是服务器搞的集群,并且服务器的配置还不太一样,比如有一台服务器他的CPU很强,算力很高,但是硬盘的读写速度不太行
另外一台服务器CPU没有那么好,但是硬盘用的NVMe的,读写速度那是相当的快,你现在需要创建一个pod,这个pod是跑数据库,只需要他读写速度快就好了,并不需要CPU有很强的算力,那我们能让他自己调度吗?显然是不太行的,所以我们需要指定他调度到那一台硬盘好的服务器上,那我们就可以给这两台服务器都打上标签,一台是高算力,一台是快IO对吧
那我们在以后去调度pod的时候是不是直接通过标签去选择就可以了呢,对吧
这个的意思就是,只要节点被打上这个标记了,那么他就不会参与到调度算法里面了,我们可以来看看,记住,他是不参与到调度算法里,如果这个节点已经存在pod,是没有影响的
# 我们先查看一下node的状态 [root@master k8s]# kubectl get nodes NAME STATUS ROLES AGE VERSION master Ready control-plane,master 2d2h v1.26.0 node1 Ready node1 2d2h v1.26.0 node2 Ready node2 2d2h v1.26.0
一切都是正常的,现在我们来给node1加一个cordon,然后再查看
[root@master k8s]# kubectl cordon node1 node/node1 cordoned [root@master k8s]# kubectl get nodes NAME STATUS ROLES AGE VERSION master Ready control-plane,master 2d2h v1.26.0 node1 Ready,SchedulingDisabled node1 2d2h v1.26.0 node2 Ready node2 2d2h v1.26.0
现在我们可以看见,node1的状态是Ready,但是后面还有一个参数,是不能被调度,那我们现在来创建pod,看看是否真的真的不会在node1上创建出来
[root@master k8s]# kubectl run pod01 --image=nginx --image-pull-policy=IfNotPresent pod/pod01 created [root@master k8s]# kubectl run pod02 --image=nginx --image-pull-policy=IfNotPresent pod/pod02 created [root@master k8s]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod01 1/1 Running 0 15s 10.244.104.59 node2 <none> <none> pod02 1/1 Running 0 10s 10.244.104.60 node2 <none> <none>
我们创建了2个pod,他确实都是在node2上起的,你还可以继续创建更多pod他也只会在node2上
好的,我们现在知道了他不会在node1上创建了,那我们如果在node2上也加一个cordon呢,那pod是在哪呢?master上吗?
[root@master k8s]# kubectl cordon node2 node/node2 cordoned [root@master k8s]# kubectl run pod03 --image=nginx --image-pull-policy=IfNotPresent pod/pod03 created [root@master k8s]# kubectl get pods NAME READY STATUS RESTARTS AGE pod01 1/1 Running 0 95s pod02 1/1 Running 0 90s pod03 0/1 Pending 0 4s
我们可以看到,他现在的状态是pending,他既没有创建到node1,也没到node2上,那master上没有做cordon,他为什么没有在master上创建呢?这个问题留着,等会就知道了
我们取消cordon
[root@master k8s]# kubectl uncordon node1 node/node1 uncordoned [root@master k8s]# kubectl uncordon node2 node/node2 uncordoned
他跟Cordon的共同点是,只要加上了这个操作,那么他们都是不可被调度的,不同点是Drain他会比Dordon多一个动作,Dordon对于已经存在的pod是不会驱逐的,但是Drain对于已经存在的pod是会进行驱逐的
我们来做个实验看看
# 我们先跑2个pod,让他自己调度,不出意外应该是一个在node1,一个在node2 [root@master k8s]# kubectl run pod01 --image=nginx --image-pull-policy=IfNotPresent pod/pod01 created [root@master k8s]# kubectl run pod02 --image=nginx --image-pull-policy=IfNotPresent pod/pod02 created [root@master k8s]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod01 1/1 Running 0 10s 10.244.104.61 node2 <none> <none> pod02 1/1 Running 0 6s 10.244.166.166 node1 <none> <none>
现在每个节点上都被调度了一个pod,那我们现在给node1加上Cordon,给node2加上Drain,来看看他们的区别
[root@master k8s]# kubectl cordon node1 node/node1 cordoned [root@master k8s]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod01 1/1 Running 0 2m1s 10.244.104.61 node2 <none> <none> pod02 1/1 Running 0 117s 10.244.166.166 node1 <none> <none>
在node1上加上cordon之后pod是没有任何的变化的
# 现在我们给node2加上Drain # 注意,一定加加上--ignore-daemonsets 和--force [root@master k8s]# kubectl drain node2 --ignore-daemonsets=true --force node/node2 cordoned Warning: ignoring DaemonSet-managed Pods: calico-system/calico-node-9f7ck, calico-system/csi-node-driver-hzj2r, kube-system/kube-proxy-xmxpj; deleting Pods that declare no controller: default/pod01 evicting pod tigera-operator/tigera-operator-cfc98749c-nzvs8 evicting pod default/pod01 pod/tigera-operator-cfc98749c-nzvs8 evicted pod/pod01 evicted node/node2 drained
现在我们再来查看一下pod
[root@master k8s]# kubectl get pods NAME READY STATUS RESTARTS AGE pod02 1/1 Running 0 32m [root@master k8s]#
现在我们发现pod01已经没有了,想要取消的话直接使用取消Cordon的命令,原因是Drain的过程是先给节点打上Cordon,然后开始驱逐,所以它也是有Cordon这一步动作的,所以是可以直接用Cordon命令取消的
刚刚使用pod他是直接将pod给删掉了,并没有在其他的地方把这个pod搞起来,驱逐难道不是应该给他换个地方吗?这其实是因为pod的原因,我们可以使用deployment控制器来实现这个效果,控制器现在只需要了解一下就行了,后面会说到,大概就是你给这个控制器一个你想要的规模数量,比如我想要5个pod,那么他会保持你的pod在5个,多了删,少了补
# 生产yaml文件 [root@master k8s]# kubectl create deployment web01 --image=nginx --dry-run=client -o yaml > depolyment.yaml
metadata: creationTimestamp: null labels: app: web01 name: web01 spec: replicas: 5 selector: matchLabels: app: web01 strategy: {} template: metadata: creationTimestamp: null labels: app: web01 spec: containers: - image: nginx name: nginx imagePullPolicy: IfNotPresent resources: {} status: {}
# 我们使用这个文件来创建控制器,然后在给node2加上Drain [root@master k8s]# kubectl get pods -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES web01-854bdfcbd8-6j958 1/1 Running 0 29s 10.244.104.12 node2 <none> <none> web01-854bdfcbd8-dlx6r 1/1 Running 0 29s 10.244.104.10 node2 <none> <none> web01-854bdfcbd8-mcc9q 1/1 Running 0 29s 10.244.166.170 node1 <none> <none> web01-854bdfcbd8-rd8sv 1/1 Running 0 29s 10.244.104.11 node2 <none> <none> web01-854bdfcbd8-v2tfn 1/1 Running 0 29s 10.244.166.169 node1 <none> <none> # 加上Drain [root@master k8s]# kubectl drain node2 --ignore-daemonsets --force [root@master k8s]# kubectl get pods -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES web01-854bdfcbd8-6mmcx 1/1 Running 0 15s 10.244.166.173 node1 <none> <none> web01-854bdfcbd8-cdkmw 1/1 Running 0 15s 10.244.166.172 node1 <none> <none> web01-854bdfcbd8-j82mv 1/1 Running 0 15s 10.244.166.171 node1 <none> <none> web01-854bdfcbd8-mcc9q 1/1 Running 0 102s 10.244.166.170 node1 <none> <none> web01-854bdfcbd8-v2tfn 1/1 Running 0 102s 10.244.166.169 node1 <none> <none>
现在我们可以看到之前在node2上的pod现在全部都被干掉了,然后又重新被调度到了node1上,这个就是驱逐
pod为什么不会宁愿是pending他都不会调度到master上呢?因为master上默认就是有污点的,我们来看看
[root@master k8s]# kubectl describe node master |grep Taint Taints: node-role.kubernetes.io/control-plane:NoSchedule
我们现在可以看到,他这个有显示Taints里面有个NoSchedule,就是不被调度,这样一切就都解释的通了,这也就是为什么master上默认不会运行业务pod
我们再来看看node1上有没有这个
[root@master k8s]# kubectl describe node master |grep Taint Taints: node-role.kubernetes.io/control-plane:NoSchedule
注意了,你如果查到的node1是这样的,说明你之前做的Cordon没有取消,一定要取消掉,还原他的默认调度策略
# 取消完之后他就应该是这样的,污点显示none,没有任何的污点 [root@master k8s]# kubectl describe node node1 |grep Taint Taints: <none>
我们来给node1也加上一个污点,让他不被调度
# 注意,打污点的时候也是key:value的形式,但是key是什么并不重要,重要的value [root@master k8s]# kubectl taint node node1 wudian:NoSchedule node/node1 tainted
这样污点就被打上了,刚刚说过了,污点的key并不重要,随意是什么都可以的
现在来创建pod,他是一定会在node2上创建pod的,因为master和node1都有污点,我们来看看
[root@master k8s]# kubectl run taint-pod2 --image=nginx --image-pull-policy=IfNotPresent pod/taint-pod2 created [root@master k8s]# kubectl run taint-pod3 --image=nginx --image-pull-policy=IfNotPresent pod/taint-pod3 created [root@master k8s]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES taint-pod 1/1 Running 0 22s 10.244.104.62 node2 <none> <none> taint-pod2 1/1 Running 0 8s 10.244.104.63 node2 <none> <none> taint-pod3 1/1 Running 0 4s 10.244.104.1 node2 <none> <none>
可以看到,确实所有的pod都被调度到了node2上
污点的删除也很简单,只需要在key后面加上-就可以了
[root@master k8s]# kubectl taint node node1 wudian- node/node1 untainted
也是可以把master上的污点给他删除掉的,删除之后后面再创建pod他就会往master上进行调度了
看到这里,也许没有搞清楚污点和Cordon他们的区别在哪,不都是不能被调度吗。为什么要搞这么多一样的功能呢?其实他们是有其别的,你看,污点这个名字,是不是就像你读书的时候学校给你的处分啊,难道说学校给你处分之后,你就不能来学校读书了吗?当然是可以的啊,这个Cordon就像是你在学校搞了很严重的事情,现在老师让你回家反省一周,你能回去一天就来学校吗?肯定不行啊,这个也就是他们的区别
如果节点存在污点,但是我指定了污点容忍,这个节点也会参与到调度中来,那么他依旧是可以被创建出来的,但是你这个节点有Cordon,不管你怎么指定,他都是pending状态的
# 实践是检验真理的唯一标准,上操作,还记得我们之前使用标签指定pod在哪个节点上创建吧。 # 我们给node1指定一个标签,同样给他一个NoSchedule的污点,再通过yaml文件来指定污点容忍,以及节点选择 [root@master k8s]# kubectl label nodes node1 cloud=666 node/node1 labeled [root@master k8s]# kubectl taint node node1 cloud=666:NoSchedule node/node1 tainted
现在我们已经操作好了,他既有标签,也有污点,直接只用yaml文件来创建pod
kind: Pod metadata: creationTimestamp: null labels: run: pod01 name: pod01 spec: containers: - image: nginx imagePullPolicy: IfNotPresent name: pod01 resources: {} dnsPolicy: ClusterFirst restartPolicy: Always # 在这里加上的是节点选择器 nodeSelector: cloud: "666" # 这里加上的污点容忍,key=value:effect 这个要跟之前定义的污点一样 tolerations: - key: "cloud" operator: "Equal" value: "666" effect: "NoSchedule" status: {}
使用这个yaml文件来看看效果
[root@master k8s]# kubectl apply -f label1.yml pod/pod01 created [root@master k8s]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod01 1/1 Running 0 5s 10.244.166.168 node1 <none> <none>
我们可以看到,虽然node1有污点,但是这个pod有污点容忍,他一样可以被调度到node1上