0

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

然后我直接重启了节点,然后启动docker,同样参数启动kubelet。

那些豆荚会发生什么?

  1. 它们是否使用从 kubelet 本地保存的元数据重新创建?或者使用从 api-server 检索到的信息?还是从 OCI 运行时恢复并表现得好像什么都没发生?
  2. 是不是只有无状态的pod(no--local-data)才能正常恢复?如果它们中的任何一个具有本地 PV/目录,它们会正常连接回来吗?
  3. 长时间不重启节点怎么办?api-server 会分配其他节点来创建这些 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-server 收到 PodSpec 时,它像远程服务一样调用 CRI,步骤如下:

  1. 创建 PodSandbox(又名“暂停”图像,始终“停止”)
  2. 创建容器
  3. 运行容器

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

请帮我确认。

先谢谢啦~

4

3 回答 3

3

好问题。先说几件事;Pod 未固定到某个节点。这些节点主要被视为 Kubernetes 可以用来运行其工作负载的“服务器场”。例如,你给 Kubernetes 一组节点,你也给一组 eg Deployment- 这是应该在你的服务器上运行的应用程序的期望状态。Kubernetes 负责调度这些 Pod,并在集群中的某些内容发生更改时保持它们运行。

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

您想要的状态;a Deploymentwith egreplicas: 4保存在Kubernetes 控制平面内的etcd数据库中。

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

Kubelet接收调度到节点的PodSpecs,然后通过定期健康检查保持这些 Pod 处于活动状态。

是不是只有无状态的pod(no--local-data)才能正常恢复?

Pod 应该被视为临时的 - 例如可以消失 - 但由管理它们的控制器恢复 - 除非作为独立 Pod 部署。所以不要在 pod 中存储本地数据。

还有StatefulSet一些 Pod,它们用于有状态的工作负载——但分布式的有状态工作负载,通常例如 3 个 Pod,它们使用Raft来复制数据。etcd 数据库是使用 Raft 的分布式数据库示例。

于 2020-09-23T14:44:02.183 回答
1

正确答案:视情况而定。

想象一下,您有 3 个节点集群,您在其中创建了一个具有 3 个副本和 3-5 个独立 pod 的部署。Pod 被创建并调度到节点。
一切都已启动并正在运行。

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

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

  1. 节点重新启动,例如。使用sudo reboot
  2. systemd重启后,节点按照dependencies指定的顺序启动所有OS进程
  3. 什么时候dockerd启动它什么都不做。此时所有先前的容器都有Exited状态。
  4. 启动时kubelet,它会向集群请求apiserver节点属性等于其节点名称的 Pod 列表。
  5. 从 获得回复后apiserver,使用 Docker CRI 为回复中kubelet描述的所有 pod 启动容器。apiserver
  6. pause容器为列表中的每个 Pod 启动时,它会获取由 CNI 二进制文件配置的新 IP 地址,由 Network addon Daemonset 的 Pod 部署。
  7. kube-proxy节点上启动 Pod 后,它会更新 iptables 规则以实现 Kubernetes 服务所需的配置,同时考虑到新 Pod 的 IP 地址。

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

根据apiserver和配置kube-controller-managerkubelet他们对节点没有延迟响应的事实做出反应。

如果节点重新启动足够快,kube-controller-manager则不会驱逐 Pod,并且它们都保持在同一个节点上调度,RESTARTS在它们的新容器变为Ready.

示例 1。

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

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

如果 node 长时间停止,node 上的 pods 保持Running状态,但连接尝试明显超时。

如果节点保持停止状态,大约 5 分钟后,该节点上安排的 Pod 被驱逐kube-controller-manager并终止。如果我在驱逐之前启动节点,则所有 pod 都保留在节点上。

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

在使用 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 Node OSContainer-Optimized OS (cos)

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

如果节点停止,则在短时间内(T1 大约等于 30-60 秒)后,节点上的所有 pod 的状态都会更改为正在终止。几分钟后,它们从 Pod 列表中消失了。由 Deployment 管理的 Pod 会重新调度到具有新名称和 IP 地址的其他节点上。

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


示例表明,不同集群的worker节点重启后的情况不同,最好在特定集群上进行实验,看看是否能得到预期的结果。

如何配置这些超时:

于 2020-10-01T20:45:15.853 回答
-1

当节点重新启动并在其上安排了由Deploymentor管理的 pod 时ReplicaSet,这些控制器将负责在另一个健康的节点上安排所需数量的副本。因此,如果您有 2 个副本在重新启动的节点上运行,它们将被终止并安排在其他节点上。

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

无状态 Pod 不会在任何其他节点上重新调度,它们将被终止。

于 2020-09-23T14:52:10.330 回答