当前位置: 首页 > article >正文

Kubernetes 中导致 pod 重启的原因

原因

在 Kubernetes(K8s)中,导致 Pod 重启的原因主要有以下几种:

1. 应用程序异常

  • 应用进程崩溃:Pod 内部的应用程序由于未处理的异常、内存溢出(OOM)、访问非法地址等原因崩溃,导致容器退出并被 K8s 重新拉起。
  • 主动退出(exit 非 0):如果容器的主进程(PID 1)主动退出并返回非零状态码,K8s 会认为容器异常终止,并可能触发重启。

2. OOM(Out Of Memory)杀死

  • 内存不足(OOMKilled):当容器内存超出 requestslimits 限制,K8s 可能会触发 OOM 终止容器。
  • Node 级别 OOM:如果 Node 本身内存不足,K8s 可能会触发 OOM 终止某些 Pod(优先终止低优先级的 Pod)。

3. Liveness Probe 检测失败

  • 存活探针(Liveness Probe)失败:如果 Pod 配置了 livenessProbe,但探测失败(例如健康检查接口未响应或返回错误),K8s 会认为该容器不健康并重启它。

4. Readiness Probe 失败

  • 就绪探针(Readiness Probe)失败:虽然 Readiness Probe 失败不会直接导致重启,但如果 Pod 一直无法进入就绪状态,可能会被调度器驱逐或被运维人员删除并重新创建。

5. CPU/内存资源限制

  • CPU 资源不足:如果容器 CPU 使用超过 limits,K8s 不会直接杀死容器,但可能会限制 CPU 资源,从而导致应用性能下降。
  • Eviction(驱逐):如果 Node 资源紧张,K8s 可能会根据 PriorityClass 选择性地驱逐 Pod。

6. 节点问题

  • Node 故障:如果运行 Pod 的 Node 发生故障(如宕机、网络异常等),K8s 会将该 Node 标记为 NotReady,并可能在其他 Node 上重新调度 Pod。
  • Node 重启:如果 Node 由于系统更新、管理员操作等原因重启,Pod 也会随之重启。

7. 滚动更新(RollingUpdate)

  • 在 Deployment、StatefulSet 等资源对象执行滚动更新时,旧的 Pod 会被终止,新 Pod 被创建。
  • 如果配置 maxUnavailable,K8s 可能会先终止一些 Pod,然后再创建新的。

8. 手动操作

  • 运维人员或自动化脚本
    • kubectl delete pod <pod_name>:手动删除 Pod 后,ReplicaSet/Deployment 会重新创建 Pod。
    • kubectl rollout restart deployment <deployment_name>:触发 Deployment 重新启动所有 Pod。
    • 重新应用 YAML 文件:如果 YAML 配置发生变更,K8s 可能会自动替换 Pod。

9. 磁盘或存储问题

  • PersistentVolume(PV)异常:Pod 依赖的持久化存储(如 NFS、Ceph、EBS)不可用或挂载失败,可能导致 Pod 进入 CrashLoopBackOff 状态。
  • 临时目录写满:如果容器写入 /tmp 或其他非持久存储目录,可能导致磁盘写满,进而触发 OOM 或应用崩溃。

10. 网络问题

  • DNS 解析失败:如果 Pod 依赖的服务无法解析 DNS 记录,可能导致 Pod 退出并重启。
  • 网络断开:Pod 依赖的 API Server、存储服务或数据库断开连接,应用异常退出。

如何排查 Pod 重启原因?

可以使用以下命令查看 Pod 的状态和重启原因:

kubectl get pod <pod_name> -o wide
kubectl describe pod <pod_name>
kubectl logs <pod_name> --previous  # 查看上次退出的日志
kubectl get events --sort-by=.metadata.creationTimestamp  # 查看最近的事件

如果 Pod 处于 CrashLoopBackOff 状态,可以进一步检查:

kubectl get pod <pod_name> -o yaml | grep reason

如果怀疑是 OOMKilled:

kubectl describe pod <pod_name> | grep -i oom

总结

导致 Pod 重启的主要原因包括:

  • 应用程序崩溃(未处理异常、exit 非 0)
  • OOMKilled(内存超限)
  • Liveness Probe 失败
  • CPU/内存不足或被驱逐
  • Node 故障或重启
  • 滚动更新
  • 手动删除
  • 磁盘或存储问题
  • 网络异常

综合 kubectl describe podkubectl logskubectl get events 进行排查,可以更精准地定位 Pod 重启的具体原因。

内存限制

如果 Pod 的堆内存(Heap Memory)超过了 Pod 限定的内存(Container Memory Limit),可能会导致 Pod 被 OOMKilled(Out of Memory Killed),从而触发 Pod 重启

具体分析

Kubernetes 中,容器的内存限制是通过 resources.limits.memory 设置的。如果进程(如 JVM 应用)使用的堆内存超过了这个限制,Kubernetes 可能会触发 OOM 终止(OOMKilled),导致容器崩溃并重启。

1. JVM 与 Kubernetes 内存管理

如果 Pod 运行的是 Java 应用,JVM 的堆内存(Heap)和 Kubernetes 分配的内存可能存在不匹配的问题:

  • JVM 默认会基于物理内存计算 -Xmx(最大堆内存),但 K8s 容器中的可用内存是受 limits.memory 限制的。
  • 如果 JVM 误以为它可以使用整个节点的内存,而不是容器的限制,可能导致 堆内存(Heap)+ 其他非堆内存(Metaspace、Stack)总和超出 K8s 限制,最终触发 OOMKilled。

2. OOMKilled 触发机制

当容器进程的内存占用超过 limits.memory,Linux 内核的 OOM 机制会直接 终止该进程,K8s 会检测到容器退出并尝试重新启动它。

可以通过以下方式检查是否是 OOMKilled:

kubectl describe pod <pod_name> | grep -i oom
kubectl get pod <pod_name> -o yaml | grep reason

如果输出包含 OOMKilled,说明是由于内存超限导致 Pod 被杀死并重启。

如何避免 OOMKilled?

方法 1:合理设置 JVM 堆内存

手动指定 最大堆内存-Xmx),确保它不会超出 Kubernetes 的 limits.memory

示例(Java)

如果 Pod 限制内存为 1GiB

resources:
  requests:
    memory: "512Mi"
  limits:
    memory: "1Gi"

可以在 JAVA_OPTS 中设置:

-XX:MaxRAMPercentage=75.0  # 让 JVM 最大堆占用 75% 的限制内存

或者直接指定 -Xmx

java -Xmx750m -jar app.jar

确保 JVM 的 最大堆大小(Heap)+ Metaspace + Stack + Off-heap 总和不会超过 1GiB。

方法 2:使用 requests.memorylimits.memory

  • requests.memory:表示Pod 启动时的最小预留内存,用于调度时分配。
  • limits.memory:表示Pod 最大可使用的内存,超出后会触发 OOMKilled。

示例:

resources:
  requests:
    memory: "512Mi"   # 申请 512MB
  limits:
    memory: "1Gi"     # 限制最大 1GB

避免 limits.memory 过低,否则 JVM 可能会因 GC 频繁触发 OOM。

方法 3:使用 memoryOvercommit 机制

如果业务允许,可以不设置 limits.memory,仅使用 requests.memory,这样 Kubernetes 不会强行杀死超限的进程,而是让 JVM 进行 GC 以尝试释放内存。

方法 4:监控和优化内存使用

  1. 监控 JVM 内存占用
    • 使用 Prometheus + Grafana 监控 Pod 内存使用情况
    • 结合 JVM Metrics(Micrometer、JMX Exporter) 监控 Heap、GC 频率
  2. 优化代码
    • 通过 调优 GC(G1GC、ZGC)减少堆外内存泄露
    • 避免大量对象滞留,减少 OutOfMemoryError: Metaspace

结论

  • 如果堆内存(Heap)超过了 Pod 的 limits.memory,会触发 OOMKilled 并导致 Pod 重启。
  • 建议手动限制 JVM 的 -Xmx,并合理配置 requests.memorylimits.memory,避免 OOMKilled 发生。
  • 通过 Prometheus 监控 Pod 的实际内存使用情况,并优化代码减少不必要的内存占用。

http://www.kler.cn/a/613654.html

相关文章:

  • PrimeTime生成.lib竟暗藏PG添加Bug
  • Skynet 中 snlua 服务启动整体流程分析
  • 工作后考研
  • 【STM32】GPIO输入(按键)
  • 交换机与路由器的区别:深入解析
  • 新手村:逻辑回归-理解04:熵是什么?
  • # 线性代数:660习题总结660# 宋浩讲解视频
  • 安装docker版jira8.0.2
  • Go 语言标准库中reflect模块详细功能介绍与示例
  • 如何使用 GPT-4o API 实现视觉、文本、图像等功能 附赠gpt升级和4o额度购买
  • OPPO Pad 4 Pro图赏,轻薄大屏,多面出色
  • QT四 资源文件;绘图;绘图设备;qpixmap 和 qimage 转换;QPixmap、QBitmap、QImage和 QPicture的区别
  • Golang中间件的原理与实现
  • 使用 Selenium 构建简单高效的网页爬虫
  • Docker Compose 基础知识
  • rnn的ho的维度 (num_layers * num_directions, batchsize, hidden_size)
  • 付账问题 | 第9届蓝桥杯省赛C++A组
  • Kafka 偏移量
  • 安卓车载app面经
  • 嵌入式单片机程序的映像文件解读