Kubernetes 如何关闭一个 Pod

本文主要求证一个问题:Pod 生命周期中执行 preStop 的时长是否计入 terminationGracePeriodSeconds 中。这个问题在 https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-ter

本文主要求证一个问题:Pod 生命周期中执行 preStop 的时长是否计入 terminationGracePeriodSeconds 中。这个问题在 https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination 中有描述,但是未能清楚地 get 到计时的方式,所以期望从源码中能找到答案。

求证

kubectl delete pod xxxx 开始,kubectl 最终会向 apiserver 发送 DELETE 请求,如下代码所示

SewzwwSewzww

当对 apiserver 的请求经过若干处理后,最终写入 etcd 后,kubelet 监测到该 Pod 状态的变更,最终执行 Pod 的删除操作。此处过滤掉 kublet 冗长的启动后,直接进入 Pod 删除的代码逻辑。

2axxqZ

可以看到先删除容器、再删除 PodSandbox

x2YthL

容器的列表在一个 for 循环中,各开一个协程进行删除操作

vdTgVC

当开始删除容器时,会先计算 gracePeriod 的时长,它的值未必会一定等于 terminationGracePeriodSeconds,有若干条件,简单而言,若由于 reasonLivenessProbe 检测失败的原因导致的容器删除,它的 gracePeriod 会取 LivenessProbe 里面配置的 TerminationGracePeriodSeconds 时长。

// From this point, pod and container must be non-nil.
gracePeriod := int64(minimumGracePeriodInSeconds)
switch {
case pod.DeletionGracePeriodSeconds != nil:
	gracePeriod = *pod.DeletionGracePeriodSeconds
case pod.Spec.TerminationGracePeriodSeconds != nil:
	gracePeriod = *pod.Spec.TerminationGracePeriodSeconds

	switch reason {
	case reasonStartupProbe:
		if containerSpec.StartupProbe != nil && containerSpec.StartupProbe.TerminationGracePeriodSeconds != nil {
			gracePeriod = *containerSpec.StartupProbe.TerminationGracePeriodSeconds
		}
	case reasonLivenessProbe:
		if containerSpec.LivenessProbe != nil && containerSpec.LivenessProbe.TerminationGracePeriodSeconds != nil {
			gracePeriod = *containerSpec.LivenessProbe.TerminationGracePeriodSeconds
		}
	}
}

因此此处假设 gracePeriod 为  terminationGracePeriodSeconds 的情况。

当配有 preStop 时,会从 gracePeriod 中减去执行 preStop 的用时,即执行 preStop 的用时是计算在 gracePeriod 中。preStop 的最大执行时长为 gracePeriod。当执行 preStop 的时长比 gracePeriod 2s 时,会直接将 gracePeriod 置为 2s。重新获得额外的 2s 时间。

接着给容器发送停止信号,此处的超时时长为 gracePeriod,已减去 preStop 执行所用时长。

9jaKz59jaKz5

结论

preStop 的执行时长,会被纳入  terminationGracePeriodSeconds 的倒计时中

Reference

Read more

容器镜像(4):镜像的常用工具箱

容器镜像(4):镜像的常用工具箱

前几篇在讲多架构镜像时已经用过 skopeo 和 crane 做镜像复制,这篇系统整理这两个工具的完整能力,同时介绍几个日常操作镜像时同样好用的工具。 一、skopeo:不依赖 Daemon 的镜像瑞士军刀 skopeo 的核心价值是绕过 Docker daemon,直接与 Registry API 交互。上一篇用它做镜像复制和离线传输,但它的能力远不止于此。 1.1 安装 # Ubuntu / Debian sudo apt install -y skopeo skopeo --version # skopeo version 1.15.1 1.2 inspect:免拉取检查镜像元数据 docker inspect 需要先把镜像拉到本地,skopeo inspect 直接向 Registry

容器镜像(3):多架构镜像构建

容器镜像(3):多架构镜像构建

一、什么是多架构镜像 1.1 OCI Image Index 上一篇介绍了单平台镜像的结构:一个 Manifest 指向 Config 和若干 Layer blob。多架构镜像在此之上多了一层——OCI Image Index(也叫 Manifest List),是一个轻量的索引文件,把多个单平台 Manifest 组织在一起: $ docker manifest inspect golang:1.22-alpine { "schemaVersion": 2, "mediaType": "application/vnd.oci.image.index.v1+json", "manifests&

容器镜像(2):containerd 视角下的镜像

容器镜像(2):containerd 视角下的镜像

一、为什么需要了解 containerd 如果你只用 docker run 跑容器,从来不关心底层,那可以不了解 containerd。但如果你在用 Kubernetes,或者想真正理解"容器运行时"是什么,containerd 是绕不开的。 事实上,当你执行 docker run 的时候,containerd 早就在后台悄悄工作了——Docker 从 1.11 版本开始,就把核心运行时剥离出来交给 containerd 负责。 1.1 Docker 的架构演变 早期的 Docker(1.10 及之前)是一个"大一统"的单体程序:一个 dockerd