假设有一些来自Deployments/StatefulSet/DemonSet等的pod在Kubernetes节点上运行。
然后我直接重新启动节点,然后启动docker,用相同的参数启动kubelet。
那些吊舱会发生什么?
- 它们是用kubelet本地保存的元数据重新创建的吗?或者使用从api服务器检索的信息?或者从OCI运行时恢复,表现得像什么都没发生
- 是不是只有无状态pod(无本地数据)才能正常恢复?如果其中任何一个具有本地PV/dir,它们会正常连接吗
- 如果我长时间没有重新启动节点怎么办?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,步骤如下:
- 创建PodSandbox(也称为"暂停"图像,总是"停止")
- 创建容器
- 运行容器
所以我猜测随着节点和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数据库中。
然后,Deployment
和ReplicaSet
的一组控制器负责保持应用程序的4个副本处于活动状态。例如,如果一个节点变得不负责任(或死亡),则如果其他节点由ReplicaSet
的控制器管理,则会在这些节点上创建新的pod。
Kubelet接收调度到节点的PodSpec,然后通过定期的健康检查来保持这些pods的活力。
是不是只有无状态pod(无本地数据)才能正常恢复?
除非部署为独立Pod,否则Pod应被视为emphemeral(例如,可以消失),但由管理它们的控制器恢复。因此,不要将本地数据存储在pod中。
还有StatefulSet
pod,用于有状态工作负载,但分布式有状态工作负载,通常为3个pod,使用Raft复制数据。etcd数据库是使用Raft的分布式数据库的一个示例。
正确答案:取决于情况
想象一下,您有3个节点集群,在其中创建了一个具有3个副本和3-5个独立pod的Deployment。吊舱已创建并计划到节点
一切正常。
假设工作节点node1
具有1个部署副本和1个或多个独立pod。
节点重启过程的一般顺序如下:
- 节点重新启动,例如使用
sudo reboot
- 重新启动后,节点按
systemd
依赖项指定的顺序启动所有操作系统进程 - 当
dockerd
启动时,它什么也不做。此时,所有先前的容器都具有Exited
状态 - 当
kubelet
启动时,它向集群apiserver
请求节点属性等于其节点名称的Pod列表 - 从
apiserver
获得回复后,kubelet
使用Docker CRI启动apiserver
回复中描述的所有pod的容器 - 当
pause
容器为列表中的每个Pod启动时,它将获得由网络插件Daemoset的Pod部署的CNI二进制文件配置的新IP地址 kube-proxy
Pod在节点上启动后,它会更新iptables规则,以实现Kubernetes Services所需的配置,同时考虑到新Pod的IP地址
现在事情变得有点复杂了。
根据apiserver
、kube-controller-manager
和kubelet
的配置,它们会对节点没有响应这一事实做出一定延迟的反应。
如果节点重新启动得足够快,则kube-controller-manager
不会驱逐Pod,并且它们都保持在同一节点上,在它们的新容器变为Ready
后增加它们的RESTARTS
编号。
示例1.
集群是在GCP中创建的Ubuntu 18.04
VM上使用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
节点操作系统为Deployment
0
节点重新启动后(大约需要15-20秒),所有pod都会在具有新IP地址的节点上启动。播客保留他们的名字和位置。(与实施例1相同)
如果节点停止,则在短时间段(T1等于大约30-60秒)后,节点上的所有pod的状态都将更改为Terminating。几分钟后,他们从播客列表中消失了。由Deployment管理的Pod会在具有新名称和ip地址的其他节点上重新安排。
如果节点池是用Ubuntu节点创建的,apiserver稍后会终止Pods,T1大约等于2-3分钟。
示例表明,不同集群的工作节点重新启动后的情况不同,最好在特定集群上运行实验,以检查是否能获得预期结果。
如何配置这些超时:
- 如何减少在Kubernetes上检测节点故障的时间
- 如果节点离线超时,Kubernetes将重新创建pod
当节点重新启动,并且节点上有由Deployment
或ReplicaSet
管理的pod时,这些控制器将负责在另一个正常节点上调度所需数量的副本。所以,如果您有两个副本在重新启动的节点上运行,它们将被终止并安排在其他节点上。
在重新启动节点之前,您应该使用kubectl cordon
将节点标记为不可调度,并给kubernetes重新调度pod的时间。
无状态pod不会在任何其他节点上重新安排,它们将被终止。