10.5 了解Statefulset如何处理节点失效
admin
2023-09-16 06:45:40
0

本文使用

Zhihu On VSCode

创作并发布

10.5 了解Statefulset如何处理节点失效

在10.2.4节中,我们阐述了Kubernetes必须完全保证:一个有状态pod在创建它的代替者之前已经不再运行,当一个节点突然失效,Kubernetes并不知道节点或者它上面的pod的状态。它并不知道这些pod是否还在运行,或者它们是否还存在,甚至是否还能被客户端访问到,或者仅仅是Kubelet停止向主节点上报本节点状态。

因为一个Statefulset要保证不会有两个拥有相同标记和存储的pod同时运行,当一个节点似乎失效时,Statefulset在明确知道一个pod不再运行之前,它不能或者不应该创建一个替换pod。

只有当集群的管理者告诉它这些信息的时候,它才能明确知道。为了做到这一点,管理者需要删除这个pod,或者删除整个节点(这么做会删除所有调度到该节点上的pod)。

作为这一章中的最后一个练习,你会看到当一个集群节点网络断开后,Statefulset和节点上的pod都会发生些什么。

10.5.1 模拟一个节点的网络断开

与第4章中一致,可以通过关闭节点的eth0网络接口来模拟节点的网络断开。因为这个例子需要多个节点,所以不能在Minikube上运行,可以使用谷歌的Kubernetes引擎来运行。

关闭节点的网络适配器

为了关闭一个节点的网络接口,需要通过ssh登录一个节点:

$ gcloud compute ssh gke-kubia-default-pool-32a2csc8-m0g1

然后在节点内部运行如下命令:

$ sudo ifconfig eth0 down

之后你的ssh链接就会中断,所以需要开启一个新的终端来继续执行。

通过Kubernetes管理节点检查节点的状态

当这个节点的网络接口关闭以后,运行在这个节点上的Kubelet服务就无法与Kubernetes API服务器通信,无法汇报本节点和上面的pod都在正常运行。

过了一段时间后,控制台就会标记该节点状态为NotReady。如下面的代码清单所示,当列出节点时可以看到这些。

代码清单10.12 观察到一个失效的节点状态变为NotReady

$ kubectl get node

因为控制台不会再收到该节点发送的状态更新,该节点上面的所有pod状态都会变为Unknown。如下面的代码清单所示,列举pod信息就可以看到。

代码清单10.13 观察到节点变为NotReady后,其上的pod状态就会改变

$ kubectl get po

正如你看到的这样,kubia-0 pod的状态不再已知,这是因为你关闭了这个pod之前运行(也许正在运行)的节点的网络接口。

当一个pod状态为Unknow时会发生什么

若该节点过段时间正常连通,并且重新汇报它上面的pod状态,那这个pod就会重新被标记为Runing。但如果这个pod的未知状态持续几分钟后(这个时间是可以配置的),这个pod就会自动从节点上驱逐。这是由主节点(Kubernetes的控制组件)处理的。它通过删除pod的资源来把它从节点上驱逐。

当Kubelet发现这个pod被标记为删除状态后,它开始终止运行该pod。在上面的示例中,Kubelet已不能与主节点通信(因为你断开了这个节点的网络),这也就意味着这个pod会一直运行着。

让我们解释一下当前的状况。通过kubectl describe命令查看kubia-0 pod的详细信息,如下面的代码清单所示。

代码清单10.14 显示未知状态的pod的详情

$ kubectl describe po kubia-0

可以看到这个pod的状态为Terminating,原因是NodeLost。在信息中说明的是节点不回应导致的不可达。

注意 这里展示的是控制组件看到的信息。实际上这个pod对应的容器并被没有被终止,还在正常运行。

10.5.2 手动删除pod

你已经明确这个节点不会再回来,但是所有处理客户端请求的三个pod都必须是正常运行的。所以需要把kubia-0 pod重新调度到一个健康的节点上。如之前提到的那样,需要手动删除整个节点或者这个pod。

正常删除pod

使用你一直使用的方式删除该pod:

$ kubectl delete po kubia-0

是不是所有的都做完了?删除pod后,Statefulset应该会立刻创建一个替换的pod,这个pod会被调度到剩下可用的节点上。再次列举pod信息来确认:

$ kubectl get po

非常奇怪,你刚刚删除了这个pod,kubectl也返回说它已经被删除。那为什么这个pod还在呢?

注意 列表中的kubia-0 pod不是一个有相同名字的新pod,在从它的AGE列中就可以看出。如果它是一个新pod,它的“年龄”只会是几秒钟。

为什么pod没有被删除

在删除pod之前,这个pod已经被标记为删除。这是因为控制组件已经删除了它(把它从节点驱逐)。

如果再次检查一下代码清单10.14,可以看出这个pod的状态是Terminating。这个pod之前已经被标记为删除,只要它所在节点上的Kubelet通知API服务器说这个pod的容器已经终止,那么它就会被清除掉。但是因为这个节点上的网络断开了,所以上述情况永远不会发生。

强制删除pod

现在你唯一可以做的是告诉API服务器不用等待kubelet来确认这个pod已经不再运行,而是直接删除它。可以按照下面所述执行:

$ kubectl delete po kubia-0 --force --grace-period 0

你需要同时使用--force和--grace-period 0两个选项。然后kubectl会对你做的事情发出警告信息。如果你再次列举pod,就可以看到一个新的kubia-0 pod被创建出来:

$ kubectl get po

警告 除非你确认节点不再运行或者不会再可以访问(永远不会再可以访问),否则不要强制删除有状态的pod。

在继续操作之前,你可能希望把之前断掉连接的节点恢复正常。可以通过GCE web控制台或在一个终端上执行下面的命令来重启该节点:

$ gcloud compute instances reset

相关内容