K8s环境中Pod频繁重启是运维人员经常碰到的稳定性问题,通常表现为服务间歇性不可用、监控曲线出现周期性断点。造成这种现象的原因大多可以归为两类:一是资源使用超出限制被系统终止,二是健康检查机制配置不当导致控制器误判容器状态。要彻底解决,需要同时从资源管理和探针策略两条线入手排查。

一、资源限制不合理引发的重启
Kubernetes通过requests和limits两个字段控制容器的资源分配。requests是调度依据,表示容器至少需要的资源;limits是上限,超过就会被cgroup限制甚至杀掉进程。很多初学者只设置limits却不管requests,或者把内存limit设得过小,导致Java、Node等应用在启动或流量高峰时触发OOMKilled,Pod随之重启。
举例来说,一个Spring Boot服务默认堆内存可能占到容器可用内存的七成,若limit只给512Mi,而JVM按1g申请,操作系统在内存紧张时就会发送SIGKILL。通过kubectl describe pod能看到Last State显示OOMKilled,重启次数不断累加。因此需要根据应用实际占用画像来定限额,并预留buff给系统组件。
| 字段 | 作用 | 设置建议 |
|---|---|---|
| requests.cpu | 调度保证的最低CPU | 按平均利用率的1.2倍 |
| limits.memory | 内存硬上限 | 峰值加百分之二十余量 |
| requests.memory | 调度依据内存 | 接近常态驻留值 |
二、健康检查配置错误的影响
存活探针(livenessProbe)决定kubelet是否重启容器,就绪探针(readinessProbe)决定流量是否导入。如果存活探针命令执行慢、超时短或失败阈值低,应用还没完成初始化就被判死,从而被重启。这种重启又会拉长启动时间,形成恶性循环。
比如一个后端服务冷启动要四十秒连数据库,但探针配置成httpGet超时两秒、失败三次即重启,那Pod永远活不到就绪。正确做法是初始延迟initialDelaySeconds设到六十秒,periodSeconds调成十秒,并让探针指向轻量接口。就绪探针则可稍宽松,避免瞬时抖动踢掉后端。
常见探针类型对比
- exec:在容器内执行命令,适合检查文件或进程存在性,但命令自身不能重。
- httpGet:请求特定路径,最常用,需注意返回码与超时。
- tcpSocket:仅测端口通断,无法反映业务健康。
三、综合排查与调优步骤
遇到频繁重启,第一步用kubectl get pod看RESTARTS列与状态,第二步kubectl describe查Events里的Failed、Unhealthy、OOMKilled记录。第三步进容器或查日志确认是否真死还是被误杀。把证据链串起来后,再回头改yaml里的resources和probe段。
调优不是一次到位,应在压测环境模拟高峰,观察重启是否消失。若仍重启,可临时去掉limit看是否资源问题,或放宽探针看是否健康误判。稳定后写进Deployment模板,并用Prometheus告警重启次数,防止再次劣化。只有资源与健康检查双轮驱动,Pod才能长久稳定运行。