在Kubernetes环境中排查Pod内脚本卡死问题,需要结合容器监控、日志分析和进程调试工具。以下是具体的排查步骤:
一、快速定位卡死的Pod和脚本
1. 查看Pod状态
kubectl get pods -o wide
kubectl describe pod <pod-name> # 查看Events和Conditions
- 关键点:关注
Ready
状态、RestartCount
和Last Transition Time
。
2. 检查容器日志
kubectl logs <pod-name> # 查看主容器日志
kubectl logs <pod-name> -c <container-name> # 指定容器
kubectl logs <pod-name> --previous # 查看上一次运行的日志
- 异常特征:日志停止更新、频繁重启或报错信息。
3. 监控资源使用
# 安装metrics-server后使用
kubectl top pods
kubectl top pods --containers
# 查看历史资源使用(需Prometheus等监控系统)
二、深入容器内部排查
1. 交互式调试
kubectl exec -it <pod-name> -c <container-name> -- /bin/sh
- 在容器内执行基础命令:
ps auxf # 查看进程树 top -H # 按线程查看CPU使用 netstat -tulpn # 查看网络连接 lsof -n # 查看文件打开情况
2. 使用strace
跟踪卡死进程
# 1. 找到卡死进程的PID
PID=$(kubectl exec <pod-name> -- ps aux | grep "script.sh" | grep -v grep | awk '{print $2}')
# 2. 使用nsenter进入容器命名空间(需要在宿主机执行)
CONTAINER_ID=$(docker ps | grep <pod-name> | awk '{print $1}')
nsenter -t $(docker inspect -f '{{.State.Pid}}' $CONTAINER_ID) -n -m -p -- strace -p $PID -T
- 关键输出:
read()
/write()
长时间无返回 → IO阻塞futex()
/pthread_cond_wait()
→ 线程死锁connect()
/recvfrom()
→ 网络请求超时
3. 使用gdb
获取进程堆栈
# 1. 安装gdb(如果容器内没有)
kubectl exec <pod-name> -- apt-get update && apt-get install gdb -y
# 2. 生成堆栈信息
kubectl exec -it <pod-name> -- gdb -p $PID -ex "thread apply all bt" -ex "quit"
三、Pod生命周期与健康检查
1. 查看探针配置
kubectl get pod <pod-name> -o yaml | grep -A 10 "livenessProbe\|readinessProbe"
- 异常特征:
- 探针频繁失败导致容器重启
- 探针超时设置过短/过长
2. 修改探针增加调试信息
livenessProbe:
exec:
command:
- /bin/sh
- -c
- |
/path/to/script.sh || (echo "Script failed at $(date)" > /var/log/probe.log && exit 1)
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
四、使用Ephemeral Containers调试
# 添加临时调试容器(Kubernetes 1.25+)
kubectl debug <pod-name> --image=busybox --target=<container-name> -it -- /bin/sh
# 在临时容器中执行诊断命令
nsenter -t 1 -n -m -p -- ps aux # 查看主容器进程
五、集群层面排查
1. 节点资源压力
kubectl describe node <node-name> # 查看节点Allocatable资源
kubectl top nodes # 查看节点资源使用
- 异常特征:
- 节点内存/CPU压力大导致OOM
- 磁盘压力导致容器IO阻塞
2. 查看kubelet和容器运行时日志
# 查看kubelet日志
journalctl -u kubelet -n 100
# 查看containerd/runc日志(根据使用的容器运行时)
journalctl -u containerd -n 100
六、自动化监控与告警
1. 集成Prometheus+Grafana
- 监控指标示例:
container_cpu_usage_seconds_total
(CPU使用率)container_memory_usage_bytes
(内存使用)process_start_time_seconds
(进程启动时间)
2. 自定义告警规则
# alert.rules
alert: ScriptStuck
expr: increase(process_start_time_seconds{container="your-container"}[1h]) == 0
for: 5m
labels:
severity: critical
七、卡死脚本的预防措施
1. 脚本健壮性改进
#!/bin/sh
set -euo pipefail # 严格模式:遇错误、未定义变量、管道错误时立即退出
trap 'echo "Script failed at line $LINENO"; exit 1' ERR # 错误捕获
# 添加超时控制
timeout 300s your_command || { echo "Command timed out"; exit 1; }
2. 容器资源限制优化
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "200m"
关键排查工具链
工具 | 用途 | 使用场景 |
---|---|---|
kubectl top | 查看Pod/容器资源使用 | 初步定位资源瓶颈 |
strace | 跟踪系统调用 | 定位IO/网络阻塞点 |
gdb | 获取进程堆栈信息 | 分析死锁或无限循环 |
lsof | 查看文件描述符和网络连接 | 排查资源泄漏 |
netstat /ss | 查看网络状态 | 诊断网络请求卡死 |
通过以上步骤,通常可以定位到卡死的具体脚本及其原因。如果问题仍然难以复现,可以考虑在测试环境中模拟生产负载,使用工具如stress-ng
进行压力测试,观察脚本的稳定性。