如果我在一些pod运行的情况下重新启动一个节点,会发生什么



假设有一些来自Deployments/StatefulSet/DemonSet等的pod在Kubernetes节点上运行。

然后我直接重新启动节点,然后启动docker,用相同的参数启动kubelet。

那些吊舱会发生什么?

  1. 它们是用kubelet本地保存的元数据重新创建的吗?或者使用从api服务器检索的信息?或者从OCI运行时恢复,表现得像什么都没发生
  2. 是不是只有无状态pod(无本地数据)才能正常恢复?如果其中任何一个具有本地PV/dir,它们会正常连接吗
  3. 如果我长时间没有重新启动节点怎么办?api服务器会分配其他节点来创建这些pod吗?默认超时值是多少?如何配置

据我所知:

apiserver
^
|(sync)
V
kubelet
^
|(sync)
V
-------------
| CRI plugin |(like api)
| containerd |(like api-server)
|    runc    |(low-level binary which manages container)
| c' runtime |(container runtime where containers run)
-------------

当kubelet从kube-api服务器接收到PodSpec时,它像远程服务一样调用CRI,步骤如下:

  1. 创建PodSandbox(也称为"暂停"图像,总是"停止")
  2. 创建容器
  3. 运行容器

所以我猜测随着节点和docker的重新启动,步骤1和2已经完成,容器处于"停止"状态;然后,当kubelet重新启动时,它从kube-api服务器获取最新信息,发现容器没有处于"运行"状态,因此它调用CRI来运行容器,然后一切恢复正常。

请帮我确认一下。

提前感谢~

好问题。先做几件事;Pod没有固定到某个节点。节点大多被看作是"节点";服务器场";Kubernetes可以用来运行其工作负载。例如,您给Kubernetes一组节点,还给了一组例如Deployment,这是应该在服务器上运行的应用程序的期望状态。Kubernetes负责调度这些Pod,并在集群中的某些内容发生变化时保持它们的运行。

独立的Pod不受任何管理,因此如果Pod崩溃,它将无法恢复。您通常希望将无状态应用程序部署为Deployments,然后启动ReplicaSets来管理应用程序的一组Pod(例如4个Pod)实例。

你想要的状态;具有例如CCD_ 5的CCD_ 4被保存在Kubernetes控制平面内的etcd数据库中。

然后,DeploymentReplicaSet的一组控制器负责保持应用程序的4个副本处于活动状态。例如,如果一个节点变得不负责任(或死亡),则如果其他节点由ReplicaSet的控制器管理,则会在这些节点上创建新的pod。

Kubelet接收调度到节点的PodSpec,然后通过定期的健康检查来保持这些pods的活力。

是不是只有无状态pod(无本地数据)才能正常恢复?

除非部署为独立Pod,否则Pod应被视为emphemeral(例如,可以消失),但由管理它们的控制器恢复。因此,不要将本地数据存储在pod中。

还有StatefulSetpod,用于有状态工作负载,但分布式有状态工作负载,通常为3个pod,使用Raft复制数据。etcd数据库是使用Raft的分布式数据库的一个示例。

正确答案:取决于情况

想象一下,您有3个节点集群,在其中创建了一个具有3个副本和3-5个独立pod的Deployment。吊舱已创建并计划到节点
一切正常。

假设工作节点node1具有1个部署副本和1个或多个独立pod。

节点重启过程的一般顺序如下:

  1. 节点重新启动,例如使用sudo reboot
  2. 重新启动后,节点按systemd依赖项指定的顺序启动所有操作系统进程
  3. dockerd启动时,它什么也不做。此时,所有先前的容器都具有Exited状态
  4. kubelet启动时,它向集群apiserver请求节点属性等于其节点名称的Pod列表
  5. apiserver获得回复后,kubelet使用Docker CRI启动apiserver回复中描述的所有pod的容器
  6. pause容器为列表中的每个Pod启动时,它将获得由网络插件Daemoset的Pod部署的CNI二进制文件配置的新IP地址
  7. kube-proxyPod在节点上启动后,它会更新iptables规则,以实现Kubernetes Services所需的配置,同时考虑到新Pod的IP地址

现在事情变得有点复杂了。

根据apiserverkube-controller-managerkubelet的配置,它们会对节点没有响应这一事实做出一定延迟的反应。

如果节点重新启动得足够快,则kube-controller-manager不会驱逐Pod,并且它们都保持在同一节点上,在它们的新容器变为Ready后增加它们的RESTARTS编号。

示例1.

集群是在GCP中创建的Ubuntu 18.04VM上使用Kubeadm和Flannel网络插件创建的
Kubernetes版本为v1.18.8
Docker版本为19.03.12

节点重新启动后,所有Pod的容器都会在具有新IP地址的节点上启动。播客保留他们的名字和位置。

如果节点长时间停止,节点上的pod将保持在Running状态,但连接尝试显然超时。

如果节点仍然处于停止状态,则在大约5分钟后,kube-controller-manager将逐出并终止在该节点上调度的pod。如果我在驱逐之前启动node,那么所有pod都保留在该节点上。

在驱逐的情况下,独立的Pod会永远消失,Deployments和类似的控制器会创建必要数量的Pod来替换被驱逐的Pod,kube-scheduler会将它们放在适当的节点上。如果新Pod无法在另一个节点上进行调度,例如,由于缺少所需的卷,它将保持"挂起"状态,直到满足调度要求。

在使用Ubuntu 18.04 Vagrant box和Virtualbox hypervisor创建的集群上,带有专门用于Kubernetes网络的主机专用适配器,停止节点上的pod仍然处于Running状态,但即使在两个小时后仍处于Readiness: false状态,并且从未被逐出。在2小时内启动节点后,所有容器都成功重新启动
从Kubernetesv1.7到最新的v1.19.2,此配置的行为始终相同。

示例2.

集群是在谷歌云(GKE)中创建的,具有默认的kubenet网络插件:
Kubernetes版本为1.15.12-gke.20节点操作系统为Deployment0

节点重新启动后(大约需要15-20秒),所有pod都会在具有新IP地址的节点上启动。播客保留他们的名字和位置。(与实施例1相同)

如果节点停止,则在短时间段(T1等于大约30-60秒)后,节点上的所有pod的状态都将更改为Terminating。几分钟后,他们从播客列表中消失了。由Deployment管理的Pod会在具有新名称和ip地址的其他节点上重新安排。

如果节点池是用Ubuntu节点创建的,apiserver稍后会终止Pods,T1大约等于2-3分钟。


示例表明,不同集群的工作节点重新启动后的情况不同,最好在特定集群上运行实验,以检查是否能获得预期结果。

如何配置这些超时:

  • 如何减少在Kubernetes上检测节点故障的时间
  • 如果节点离线超时,Kubernetes将重新创建pod

当节点重新启动,并且节点上有由DeploymentReplicaSet管理的pod时,这些控制器将负责在另一个正常节点上调度所需数量的副本。所以,如果您有两个副本在重新启动的节点上运行,它们将被终止并安排在其他节点上。

在重新启动节点之前,您应该使用kubectl cordon将节点标记为不可调度,并给kubernetes重新调度pod的时间。

无状态pod不会在任何其他节点上重新安排,它们将被终止。

最新更新