Pod 生命周期与终止流程
概述
Pod 的生命周期从 Pending 开始,经过 Running,最终到达 Succeeded 或 Failed。理解 Pod 生命周期对于正确管理应用至关重要。
Pod 生命周期阶段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
type PodPhase string
const ( PodPending PodPhase = "Pending"
PodRunning PodPhase = "Running"
PodSucceeded PodPhase = "Succeeded"
PodFailed PodPhase = "Failed"
PodUnknown PodPhase = "Unknown" )
|
生命周期流程图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ Pod 创建请求 │ │ kube-apiserver -> etcd │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ Pending 阶段 │ │ │ │ 1. Pod 已被 API Server 接受 │ │ 2. 等待调度器绑定到节点 │ │ 3. 拉取镜像 │ │ 4. 创建 Pod Sandbox │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ Init Container 阶段 │ │ │ │ 按顺序执行 Init Container (如果有) │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ 1. init-container-1 执行 -> 完成 │ │ │ │ 2. init-container-2 执行 -> 完成 │ │ │ │ 3. ... 所有 Init Container 完成 │ │ │ └─────────────────────────────────────────────────────────────────────────┘ │ │ │ │ 注意: 任一 Init Container 失败 -> Pod 失败 │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ Running 阶段 │ │ │ │ 1. 启动主容器 (Main Container) │ │ 2. 执行 PostStart Hook (如果有) │ │ 3. 容器运行中 │ │ 4. 定期执行 Liveness/Readiness Probe │ └──────────────────────────────────────────────────────────────────────────────┘ │ ┌───────────────┴───────────────┐ │ │ ▼ ▼ ┌──────────────────────────────┐ ┌──────────────────────────────┐ │ Succeeded 阶段 │ │ Failed 阶段 │ │ │ │ │ │ 所有容器成功退出 │ │ 至少一个容器失败退出 │ │ restartPolicy: Never/OnFailure │ 或被系统终止 │ └──────────────────────────────┘ └──────────────────────────────┘
|
容器重启策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
type RestartPolicy string
const ( RestartPolicyAlways RestartPolicy = "Always"
RestartPolicyOnFailure RestartPolicy = "OnFailure"
RestartPolicyNever RestartPolicy = "Never" )
|
重启策略行为
| 重启策略 |
容器成功退出 |
容器失败退出 |
适用场景 |
| Always |
重启 |
重启 |
长期运行的服务 |
| OnFailure |
不重启 |
重启 |
批处理任务 |
| Never |
不重启 |
不重启 |
一次性任务 |
kubelet 中的 Pod 管理
Pod Worker 流程
- 文件:
pkg/kubelet/pod_workers.go
- 函数:
podWorkers.managePodLoop()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ Pod 更新事件 │ │ UpdatePod(update.PodWorkType) │ │ │ │ WorkType: │ │ ├── SyncPod: 正常同步 │ │ ├── TerminatingPod: 正在终止 │ │ └── TerminatedPod: 已终止 │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ managePodLoop │ │ pkg/kubelet/pod_workers.go:1200 │ │ │ │ switch { │ │ case update.WorkType == TerminatedPod: │ │ err = p.podSyncer.SyncTerminatedPod(ctx, pod, status) │ │ │ │ case update.WorkType == TerminatingPod: │ │ err = p.podSyncer.SyncTerminatingPod(ctx, pod, status, gracePeriod) │ │ │ │ default: │ │ isTerminal, err = p.podSyncer.SyncPod(ctx, updateType, pod, status) │ │ } │ └──────────────────────────────────────────────────────────────────────────────┘
|
SyncPod 主流程
- 文件:
pkg/kubelet/kubelet.go
- 函数:
Kubelet.syncPod()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ syncPod │ │ pkg/kubelet/kubelet.go:1800 │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 1. 预检查 │ │ │ │ - 检查 Pod 是否已被删除 │ │ - 检查 Pod 是否可以运行 │ │ - 检查资源是否充足 │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 2. 创建 Pod 数据目录 │ │ │ │ - 创建 Pod 目录: /var/lib/kubelet/pods/<uid> │ │ - 创建 Volume 目录 │ │ - 创建 Plugin 目录 │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 3. 等待 Volume 挂载 │ │ │ │ - 等待所有 PVC 绑定 │ │ - 挂载卷到 Pod 目录 │ │ - 设置 SELinux 上下文 │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 4. 获取 Image Pull Secrets │ │ │ │ - 从 Pod.Spec.ImagePullSecrets 获取 │ │ - 解析 Secret 数据 │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 5. 执行 SyncPod │ │ pkg/kubelet/kuberuntime/kuberuntime_manager.go │ │ │ │ a) 计算 Sandbox 和容器变更 │ │ b) 终止需要删除的容器 │ │ c) 创建/更新 Pod Sandbox │ │ d) 启动 Init Container (按顺序) │ │ e) 启动主容器 (并行) │ └──────────────────────────────────────────────────────────────────────────────┘
|
Init Container 流程
执行顺序
- 文件:
pkg/kubelet/kuberuntime/kuberuntime_manager.go
- 函数:
computePodActions()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ Init Container 执行 │ │ │ │ Pod.Spec.InitContainers: [init-1, init-2, init-3] │ │ │ │ 步骤 1: 执行 init-1 │ │ ├── 创建容器 │ │ ├── 执行 PostStart Hook │ │ ├── 等待容器退出 │ │ └── 检查退出码 (0 = 成功) │ │ │ │ 步骤 2: 执行 init-2 │ │ ├── 创建容器 │ │ └── 等待容器退出 │ │ │ │ 步骤 3: 执行 init-3 │ │ ├── 创建容器 │ │ └── 等待容器退出 │ │ │ │ 所有 Init Container 成功 -> 启动主容器 │ │ 任一 Init Container 失败 -> 根据重启策略处理 │ └──────────────────────────────────────────────────────────────────────────────┘
|
Init Container 特点
1 2 3 4 5 6 7 8 9 10
| spec: initContainers: - name: init-db image: busybox command: ['sh', '-c', 'until nslookup db-service; do sleep 1; done']
|
容器 Probe
Probe 类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
type Probe struct { ProbeHandler InitialDelaySeconds int32 TimeoutSeconds int32 PeriodSeconds int32 SuccessThreshold int32 FailureThreshold int32 TerminationGracePeriodSeconds *int64 }
type ProbeHandler struct { Exec *ExecAction HTTPGet *HTTPGetAction TCPSocket *TCPSocketAction GRPC *GRPCAction }
|
Liveness Probe (存活探测)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ Liveness Probe │ │ │ │ 作用: 检测容器是否存活 │ │ 失败: 重启容器 │ │ │ │ 示例: │ │ livenessProbe: │ │ httpGet: │ │ path: /healthz │ │ port: 8080 │ │ initialDelaySeconds: 30 │ │ periodSeconds: 10 │ │ failureThreshold: 3 │ │ │ │ 流程: │ │ 启动后 30s 开始 -> 每 10s 探测一次 -> 连续 3 次失败 -> 重启容器 │ └──────────────────────────────────────────────────────────────────────────────┘
|
Readiness Probe (就绪探测)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ Readiness Probe │ │ │ │ 作用: 检测容器是否准备好接收流量 │ │ 失败: 从 Service Endpoints 移除 │ │ │ │ 示例: │ │ readinessProbe: │ │ httpGet: │ │ path: /ready │ │ port: 8080 │ │ initialDelaySeconds: 5 │ │ periodSeconds: 5 │ │ failureThreshold: 3 │ │ │ │ 流程: │ │ 启动后 5s 开始 -> 每 5s 探测一次 -> 失败时从 Service 移除 │ └──────────────────────────────────────────────────────────────────────────────┘
|
Pod 终止流程
优雅终止流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| ┌──────────────────────────────────────────────────────────────────────────────┐ │ Pod 删除请求 │ │ kubectl delete pod <name> │ │ 或 DeletionTimestamp 被设置 │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 1. API Server 处理删除 │ │ │ │ - 设置 Pod.DeletionTimestamp │ │ - 设置 Pod.DeletionGracePeriodSeconds (默认 30s) │ │ - 更新 etcd │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 2. kubelet 接收更新 │ │ │ │ - 监听到 Pod 更新 │ │ - 检测到 DeletionTimestamp │ │ - 标记 Pod 为 Terminating │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 3. 执行 PreStop Hook │ │ │ │ 如果定义了 lifecycle.preStop: │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ lifecycle: │ │ │ │ preStop: │ │ │ │ exec: │ │ │ │ command: ["/bin/sh", "-c", "sleep 15; nginx -s quit"] │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ - PreStop 在容器内执行 │ │ - 与 SIGTERM 信号并行 │ │ - 超时时间为 terminationGracePeriodSeconds │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 4. 发送 SIGTERM 信号 │ │ │ │ - 向所有容器发送 SIGTERM │ │ - 容器开始优雅关闭 │ │ - 应用应该: │ │ ├── 停止接收新请求 │ │ ├── 完成处理中的请求 │ │ ├── 关闭数据库连接 │ │ └── 保存状态 │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 5. 从 Service 移除 │ │ │ │ - EndpointController 更新 Endpoints │ │ - 从 Service Endpoints 移除 Pod │ │ - 不再转发新流量到该 Pod │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 6. 等待容器退出 │ │ │ │ 等待 terminationGracePeriodSeconds (默认 30s) │ │ │ │ 如果容器在宽限期内退出: │ │ ├── 进入下一步清理 │ │ │ │ │ 如果宽限期到期容器仍未退出: │ │ └── 发送 SIGKILL 信号强制终止 │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 7. 清理资源 │ │ │ │ - 卸载卷 │ │ - 释放网络资源 │ │ - 清理 Pod 目录 │ │ - 从 CRI 删除容器 │ └──────────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 8. 更新 API Server │ │ │ │ - 设置 Pod.Status.Phase = Failed/Succeeded │ │ - 设置 Pod 容器终止状态 │ │ - 移除 Pod (如果非孤儿) │ └──────────────────────────────────────────────────────────────────────────────┘
|
终止代码
- 文件:
pkg/kubelet/kuberuntime/kuberuntime_container.go
- 函数:
killContainer()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| func (m *kubeGenericRuntimeManager) killContainer( pod *v1.Pod, containerID containerID, containerName string, gracePeriodOverride *int64, reason string, message string, ) error { if container.Lifecycle != nil && container.Lifecycle.PreStop != nil { m.runner.Run(containerID, container.Lifecycle.PreStop) }
m.runtimeService.StopContainer(containerID, gracePeriod)
}
|
强制删除 (Force Delete)
1 2 3 4 5 6 7 8
| kubectl delete pod <name> --force --grace-period=0
|
Pod 状态条件
条件类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
type PodConditionType string
const ( PodScheduled PodConditionType = "PodScheduled"
PodReady PodConditionType = "PodReady"
PodInitialized PodConditionType = "PodInitialized"
Unschedulable PodConditionType = "Unschedulable"
ContainersReady PodConditionType = "ContainersReady" )
|
条件状态
1 2 3 4 5 6 7
| type ConditionStatus string
const ( ConditionTrue ConditionStatus = "True" ConditionFalse ConditionStatus = "False" ConditionUnknown ConditionStatus = "Unknown" )
|
Phase 计算逻辑
- 文件:
pkg/kubelet/status/status_manager.go
- 函数:
generatePodPhase()
1 2 3 4 5 6 7 8 9 10 11
| func generatePodPhase(pod *v1.Pod, podStatus *kubecontainer.PodStatus) v1.PodPhase { }
|
关键代码路径
| 文件 |
说明 |
pkg/kubelet/kubelet.go |
kubelet 主逻辑,syncPod |
pkg/kubelet/pod_workers.go |
Pod Worker 管理 |
pkg/kubelet/status/status_manager.go |
Pod 状态管理 |
pkg/kubelet/kuberuntime/kuberuntime_manager.go |
容器运行时管理 |
pkg/kubelet/kuberuntime/kuberuntime_container.go |
容器操作 |
staging/src/k8s.io/api/core/v1/types.go |
Pod API 类型 |
常见问题排查
1. Pod 卡在 Pending
1 2 3 4 5 6 7 8
| kubectl describe pod <name>
|
2. Pod 卡在 Terminating
1 2 3 4 5 6 7 8
| kubectl describe pod <name>
journalctl -u kubelet | grep <pod-name>
kubectl delete pod <name> --force --grace-period=0
|
3. Init Container 失败
1 2 3 4 5
| kubectl logs <pod-name> -c <init-container-name>
kubectl get pod <name> -o jsonpath='{.status.initContainerStatuses}'
|
4. 健康检查失败
1 2 3 4 5
| kubectl describe pod <name>
kubectl exec <pod-name> -- curl -v http://localhost:8080/healthz
|
最佳实践
1. 合理设置资源
1 2 3 4 5 6 7
| resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 512Mi
|
2. 配置健康检查
1 2 3 4 5 6 7 8 9 10 11 12 13
| livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 30 periodSeconds: 10
readinessProbe: httpGet: path: /ready port: 8080 initialDelaySeconds: 5 periodSeconds: 5
|
3. 优雅终止
1 2 3 4 5 6
| lifecycle: preStop: exec: command: ["/bin/sh", "-c", "sleep 15; nginx -s quit"]
terminationGracePeriodSeconds: 60
|
4. Init Container 使用
1 2 3 4
| initContainers: - name: wait-for-db image: busybox command: ['sh', '-c', 'until nc -z db-service 5432; do sleep 1; done']
|
面试题
基础题
1. Pod 有哪些生命周期阶段?
参考答案:
| 阶段 |
说明 |
| Pending |
Pod 已被接受,但容器尚未启动(调度中、拉取镜像) |
| Running |
Pod 已绑定节点,所有容器已创建,至少一个正在运行 |
| Succeeded |
所有容器成功终止(exit code 0),不会重启 |
| Failed |
所有容器终止,至少一个失败(exit code 非 0) |
| Unknown |
无法获取状态(通常是通信问题) |
2. Pod 的重启策略有哪些?
参考答案:
| 策略 |
容器成功退出 |
容器失败退出 |
| Always |
重启 |
重启 |
| OnFailure |
不重启 |
重启 |
| Never |
不重启 |
不重启 |
默认值:Deployment/ReplicaSet 为 Always,Job 为 OnFailure
3. Init Container 和普通 Container 有什么区别?
参考答案:
| 特性 |
Init Container |
主 Container |
| 执行顺序 |
先执行,按顺序 |
后执行,并行 |
| 必须成功 |
是 |
否(取决于重启策略) |
| 健康检查 |
不支持 |
支持 |
| 资源计算 |
取最大值 |
独立计算 |
| 用途 |
初始化、等待依赖 |
运行应用 |
中级题
4. Init Container 的执行流程是怎样的?
参考答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Pod 创建 │ ▼ Init Container 1 执行 │ ├── 成功 -> Init Container 2 执行 │ │ │ ├── 成功 -> Init Container 3 ... │ │ │ └── 失败 -> 根据重启策略处理 │ └── 失败 -> 根据重启策略处理
所有 Init Container 成功 │ ▼ 主 Container 并行启动
|
代码位置:pkg/kubelet/kuberuntime/kuberuntime_manager.go:890 - findNextInitContainerToRun()
5. Liveness Probe 和 Readiness Probe 有什么区别?
参考答案:
| 特性 |
Liveness |
Readiness |
| 目的 |
检测容器是否存活 |
检测是否可接收流量 |
| 失败后果 |
重启容器 |
从 Service 移除 |
| 影响范围 |
容器本身 |
Service Endpoints |
| 启动时 |
等待 initialDelaySeconds |
等待 initialDelaySeconds |
配置示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 30 periodSeconds: 10 failureThreshold: 3
readinessProbe: httpGet: path: /ready port: 8080 initialDelaySeconds: 5 periodSeconds: 5 failureThreshold: 3
|
6. Startup Probe 的作用是什么?
参考答案:
Startup Probe 用于慢启动应用,在应用完全启动前禁用 Liveness Probe。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| startupProbe: httpGet: path: /healthz port: 8080 failureThreshold: 30 periodSeconds: 10
livenessProbe: httpGet: path: /healthz port: 8080 periodSeconds: 10
|
好处:
- 避免慢启动应用被误杀
- 无需设置过长的 livenessProbe.initialDelaySeconds
7. Pod 的优雅终止流程是怎样的?
参考答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 1. 删除请求 -> API Server 设置 deletionTimestamp │ ▼ 2. kubelet 检测到 deletionTimestamp │ ▼ 3. 从 Service Endpoints 移除 Pod │ ▼ 4. 执行 PreStop Hook(如果有) │ ▼ 5. 发送 SIGTERM 信号给所有容器 │ ▼ 6. 等待 terminationGracePeriodSeconds(默认 30s) │ ├── 容器退出 -> 进入清理 │ └── 超时 -> 发送 SIGKILL 强制终止 │ ▼ 7. 清理资源(卸载卷、释放网络) │ ▼ 8. 从 API Server 删除 Pod
|
高级题
8. PreStop Hook 的执行时机和注意事项?
参考答案:
执行时机:
- 在发送 SIGTERM 之前执行
- 与 SIGTERM 信号处理并行(不是阻塞)
- 在容器内执行
注意事项:
1 2 3 4 5 6 7
| lifecycle: preStop: exec: command: ["/bin/sh", "-c", "sleep 15; nginx -s quit"]
|
关键点:
- PreStop 超时包含在 terminationGracePeriodSeconds 内
- PreStop 失败不影响 Pod 终止
- 容器已崩溃时 PreStop 不会执行
9. 如何实现零停机部署?
参考答案:
1. 正确配置 Readiness Probe:
1 2 3 4 5 6
| readinessProbe: httpGet: path: /ready port: 8080 initialDelaySeconds: 5 periodSeconds: 5
|
2. 使用 PreStop Hook:
1 2 3 4
| lifecycle: preStop: exec: command: ["/bin/sh", "-c", "sleep 15"]
|
3. 设置合适的 grace period:
1
| terminationGracePeriodSeconds: 60
|
4. 配置 PDB:
1 2 3 4
| apiVersion: policy/v1 kind: PodDisruptionBudget spec: minAvailable: 1
|
5. 使用滚动更新策略:
1 2 3 4 5 6
| spec: strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0
|
10. Pod Phase 的计算逻辑是怎样的?
参考答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
func generatePodPhase(pod *v1.Pod, podStatus *kubecontainer.PodStatus) v1.PodPhase { allRunning := true allSucceeded := true anyFailed := false
for _, container := range podStatus.ContainerStatuses { switch container.State { case Running: allSucceeded = false case Exited: if container.ExitCode == 0 { allRunning = false } else { allSucceeded = false anyFailed = true } } }
if allRunning && len(podStatus.ContainerStatuses) > 0 { return v1.PodRunning } if allSucceeded { if pod.Spec.RestartPolicy == v1.RestartPolicyNever { return v1.PodSucceeded } return v1.PodRunning } if anyFailed { if pod.Spec.RestartPolicy == v1.RestartPolicyNever { return v1.PodFailed } return v1.PodRunning } return v1.PodPending }
|
11. 容器重启的退避策略是怎样的?
参考答案:
Kubernetes 使用指数退避策略重启容器:
1 2 3 4 5 6 7 8 9
| 重启间隔 = min(backoff * 2^(restartCount-1), maxBackoff)
示例(默认 maxBackoff = 5m): 第 1 次重启:10s 后 第 2 次重启:20s 后 第 3 次重启:40s 后 第 4 次重启:80s 后 ... 第 N 次重启:5m 后(最大值)
|
相关参数:
1 2
| kubelet --container-max-backoff=5m kubelet --container-min-backoff=10s
|
重置条件:
- 容器运行超过 10 分钟,restartCount 重置为 0
12. Sidecar 容器的终止顺序是怎样的?
参考答案:
Kubernetes 1.28+ 支持 Sidecar 容器,有明确的终止顺序:
1 2 3 4 5
| containers: - name: main - name: sidecar restartPolicy: Always
|
终止顺序:
1 2 3 4 5
| 1. 发送 SIGTERM 给主容器 2. 等待主容器退出 3. 发送 SIGTERM 给 Sidecar 容器(按启动逆序) 4. 等待 Sidecar 退出 5. 清理资源
|
实现:pkg/kubelet/kuberuntime/kuberuntime_termination_order.go
好处:
- Sidecar 可以收集主容器的日志/指标直到主容器完全退出
- 保证依赖关系正确处理
场景题
13. Pod 卡在 Terminating 状态如何处理?
参考答案:
1. 诊断步骤:
1 2 3 4 5 6 7 8
| kubectl describe pod <pod-name>
journalctl -u kubelet | grep <pod-name>
kubectl get pod <pod-name> -o jsonpath='{.metadata.finalizers}'
|
2. 常见原因:
- Finalizer 未移除:如 PV 保护
- kubelet 无响应:节点问题
- 容器无法停止:进程僵死
- 网络问题:无法与 API Server 通信
3. 解决方法:
1 2 3 4 5 6 7 8
| kubectl patch pod <pod-name> -p '{"metadata":{"finalizers":[]}}'
kubectl delete pod <pod-name> --force --grace-period=0
systemctl restart kubelet
|
14. 如何排查容器频繁重启的问题?
参考答案:
1. 查看重启历史:
1 2 3 4
| kubectl describe pod <pod-name>
kubectl get pod <pod-name> -o jsonpath='{.status.containerStatuses[0].restartCount}'
|
2. 查看退出日志:
1
| kubectl logs <pod-name> --previous
|
3. 常见原因和解决:
| 原因 |
诊断方法 |
解决 |
| OOM |
查看 exit code 137 |
增加内存限制 |
| Liveness 失败 |
检查 probe 配置 |
调整阈值或增加超时 |
| 应用崩溃 |
查看日志 |
修复应用 bug |
| 资源不足 |
检查节点资源 |
扩容或优化 |
| 依赖不可用 |
检查网络/服务 |
增加重试逻辑 |
15. 如何设计一个优雅关闭的应用?
参考答案:
1. 信号处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| func main() { sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT)
server := startServer()
<-sigChan log.Println("收到终止信号,开始优雅关闭...")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel()
server.StopAcceptingNewConnections()
server.WaitForExistingRequests(ctx)
db.Close()
cleanup()
log.Println("优雅关闭完成") }
|
2. Kubernetes 配置:
1 2 3 4 5 6 7 8 9 10 11 12
| spec: terminationGracePeriodSeconds: 60 containers: - name: app lifecycle: preStop: exec: command: ["/bin/sh", "-c", "sleep 10"] readinessProbe: httpGet: path: /ready port: 8080
|
3. 健康检查端点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
var ready atomic.Bool
func readyHandler(w http.ResponseWriter, r *http.Request) { if ready.Load() { w.WriteHeader(200) } else { w.WriteHeader(503) } }
func shutdown() { ready.Store(false) }
|
16. 如何处理长时间运行的任务不被中断?
参考答案:
1. 使用 Job 而非 Deployment:
1 2 3 4 5 6 7 8 9 10 11 12 13
| apiVersion: batch/v1 kind: Job metadata: name: long-task spec: backoffLimit: 0 activeDeadlineSeconds: 86400 template: spec: containers: - name: worker image: worker:v1 restartPolicy: Never
|
2. 增加 terminationGracePeriodSeconds:
1 2
| spec: terminationGracePeriodSeconds: 3600
|
3. 使用 PreStop Hook 保存状态:
1 2 3 4
| lifecycle: preStop: exec: command: ["/bin/sh", "-c", "save-progress.sh"]
|
4. 检查点机制:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| func runTask() { for { doWork() saveCheckpoint()
if isShuttingDown() { saveCheckpoint() return } } }
func resume() { checkpoint := loadCheckpoint() continueFrom(checkpoint) }
|