Kubernetes Pod 的生命周期与故障排查
1.Pod的生命周期
在生产环境中,K8s的pod问题往往会层出不穷。Pod的状态不同对应着不同的深层问题,下面是Pod常见的8种Status。
个人认为上面8种状态里,其中Pending、ImagePullBackOff、CrashLoopBackOff、Error、Terminating、unknown这六种问题原因一定要熟知。
说明:
当 Pod 反复启动失败时,某些 kubectl 命令的 Status 字段中可能会出现 CrashLoopBackOff。 同样,当 Pod 被删除时,某些 kubectl 命令的 Status 字段中可能会出现 Terminating。
确保不要将 Status(kubectl 用于用户直觉的显示字段)与 Pod 的 phase 混淆。 Pod 阶段(phase)是 Kubernetes 数据模型和 Pod API 的一个明确的部分。
以下是Pod phase字段的取值。
下面这张Pod生命周期图随处可见,反映了Pod启动过程中所做的事情。由于Pod中可以有多个容器,特殊的Init 容器一般用来安装脚本、配置环境变量等,只有Init 容器准备完成,才能进入应用容器的启动。
应用容器启动和运行过程中,就绪探针和存活探针也会运行,如果探测失败,kubelet会杀死容器。Poststart 、Prestop是两个容器回调程序,用于触发指定代码。它们都在容器生命周期中发挥着重要作用,当Pod 出问题后,排错阶段意味着要理解此部门内容。
2. Pod 异常状态
3. Pod 排障命令
kubectl get pod -o yaml # 查看 Pod 配置是否正确
kubectl describe pod <pod-name> # 查看 Pod 详细事件信息
kubectl logs [-c ] # 查看容器日志
kubectl get events #查看事件,了解具体原因
kubectl logs <pod-name> <container-name> #查看容器日志
kubectl get nodes #查看节点信息
kubectl describe node <node-name> #查看具体节点状态
4. Pod故障问题与排查方法
3.1 Pod 处于 Pending 状态
1.CPU 、内存和GPU资源不足:
检查集群中的节点资源使用情况,查看是否有足够的 CPU 和内存资源来启动新的 Pod。
解决方法:增加节点数量或升级现有节点的资源。
2.节点亲和性/反亲和性规则:
亲和性/反亲和性设置:Pod 的亲和性或反亲和性设置可能阻止它在某些节点上调度。
解决方法:检查并调整 Pod 的亲和性或反亲和性设置,或者修改节点的标签以满足这些要求。
3.污点和容忍度不匹配:
节点被标记为不可调度:节点可能被标记有污点(taints),而 Pod 没有相应的容忍度(toleration)。
解决方法:在 Pod 定义中添加相应的容忍度,或者从节点上移除污点。
4.存储问题:
持久卷(PersistentVolume)和持久卷声明(PersistentVolumeClaim)配置错误:如果 Pod 需要持久存储,配置错误可能导致调度失败。
解决方法:确保所有相关的持久卷和持久卷声明的配置正确,并且有足够的存储资源可用。
3.2 Pod 处于 Waiting 或 ContainerCreating 状态
首先还是通过 kubectl describe pod 命令查看到当前 Pod 的事件。可能的原因包括:
- 镜像拉取失败:比如,镜像地址配置错误、拉取不了国外镜像源(gcr.io)、私有镜像密钥配置错误、镜像太大导致拉取超时,可以适当调整 kubelet 的 –image-pull-progress-deadline 和 –runtime-request-timeout 选项等。
- CNI 网络错误:一般需要检查 CNI 网络插件的配置,比如:无法配置 Pod 网络、无法分配 IP 地址。
- 容器无法启动:需要检查是否打包了正确的镜像或者是否配置了正确的容器参数。
- Failed create pod sandbox,查看kubelet日志,原因可能是磁盘坏道(input/output error)。
3.3 Pod 处于 ImagePullBackOff 状态
基本都是镜像仓库问题:
- 证书过期或验证失败:私有仓库证书过期或节点时间不准确可能导致验证失败。
- 是镜像名称配置错误或者私有镜像的密钥配置错误导致。这种情况可以使用 docker pull 来验证镜像是否可以正常拉取。
如果私有镜像密钥配置错误或者没有配置,按下面检查:
1、查询 docker-registry 类型的 Secret
查看 docker-registry Secret
$ kubectl get secrets first-secret -o yaml | grep 'dockerconfigjson:' | awk '{print $NF}' | base64 -d
2.创建docker-registry类型的Secret
首先创建一个 docker-registry 类型的 Secret
$ kubectl create secret docker-registry first-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL然后在 Deployment 中引用这个 Secret
spec:containers:- name: private-reg-containerimage: <your-private-image>imagePullSecrets:- name: first-secret
镜像加速器未配置:使用阿里云等国内镜像源时,未配置加速器可能导致拉取超时。
镜像标签冲突:公有仓库与私有仓库存在同名镜像标签冲突。
解决建议:
- 检查节点时间同步:确保所有节点时间准确,避免证书验证错误。
- 重试拉取:等待一段时间后重试,Kubernetes会自动按退避算法重试。
- 清理缓存:删除本地损坏的镜像文件后重试。
3.4 Pod 处于 CrashLoopBackOff 状态
CrashLoopBackOff 状态说明容器曾经启动了,但又异常退出,此时可以先查看一下容器的日志。
通过命令 kubectl logs 和 kubectl logs --previous 可以发现一些容器退出的原因,比如:容器进程退出、健康检查失败退出,此时如果还未发现线索,还可以到容器内执行命令来进一步查看退出原因。
kubectl logs 和 kubectl logs --previous
kubectl exec mysql– cat /var/log/mysql/system.log
如果还是没有线索,那就需要 SSH 登录该 Pod 所在的 Node 上,查看 Kubelet 或者 Docker 的日志进一步排查。
3.5 Pod处于Error状态
通常处于 Error 状态说明 Pod 启动过程中发生了错误。
常见的原因包括:
- 依赖的 ConfigMap、Secret 或者 PV 等不存在;
- 请求的资源超过了管理员设置的限制,比如超过了 LimitRange 等;
- 违反集群的安全策略,比如违反了 PodSecurityPolicy 等;
- 容器无权操作集群内的资源,比如开启 RBAC 后,需要为 ServiceAccount 配置角色绑定。
3.6 Pod 处于Terminating状态
1.优雅终止周期(Graceful termination period)
当 pod 被删除时,会进入"Terminating"状态,等待容器优雅关闭。如果容器关闭所需时间超过默认期限(默认 30 秒),则 pod 将保持在"Terminating"状态。
K8S 中的优雅终止周期是在删除 pod 时,容器的优雅关闭时间。在此期间,容器接收 SIGTERM 信号,执行必要的清理工作,例如关闭连接,完成正在进行的任务,并在资源终止之前释放资源,默认为 30 秒。
解决方法:
检查 pod 状态和事件: 通过kubectl检查 pod 的状态和事件以获取相关信息:
$ kubectl describe pod <pod-name> -n <namespace>检查容器日志:
$ kubectl logs <pod-name> -c <container-name> -n <namespace> --previous调整优雅终止周期: 如果容器始终需要更多的时间来清理资源,可以通过在 pod 的 YAML 文件中设置terminationGracePeriodSeconds字段来调整 pod 的终止周期。apiVersion: v1
kind: Pod
metadata:name: my-pod
spec:terminationGracePeriodSeconds: 60containers:- name: my-containerimage: my-image
2.Finalizers:
Finalizer 是一种允许在删除资源之前清理资源的机制。如果 pod 有 Finalizer,并且相关的清理操作被卡住或没有响应,则 pod 将保持在"Terminating"状态。
解决方法:
Finalizer 允许在删除资源之前清理资源,如果 pod 上存在 Finalizer,并且相关的清理操作被卡住或没有响应,则 pod 将保持在"Terminating"状态。例如:apiVersion: v1
kind: Pod
metadata:name: my-finalizer-podfinalizers:- example.com/cleanup
spec:containers:- name: busyboximage: busyboxcommand: ["sh", "-c", "sleep 3600"]检查是否有 finalizer,可以运行以下命令:
$ kubectl get pod <pod-name> -n <namespace> -o json如果确定不需要 finalizer,或者确定可以将其安全删除,可以使用kubectl patch命令。但是,这样做要小心,因为可能会导致意想不到的副作用:
$ kubectl patch pod <pod-name> -n <namespace> -p '{"metadata":{"finalizers":["<finalizer-1>", "<finalizer-2>", ...]}}'
3.无响应容器(Unresponsive containers):
如果 pod 中的容器在终止过程中没有响应 SIGTERM 信号,则可能导致 pod 卡在"Terminating"状态。
当容器消耗过多系统资源时,可能会进入无响应状态。
解决方法:
用kubectl describe命令查看 Pod 状态和事件。
$ kubectl describe pod <pod-name> -n <namespace>检查 Pod/container 日志:
$ kubectl logs <pod-name> -c <container-name> -n <namespace>强制删除 pod: 可以强制删除被卡住的 pod
$ kubectl delete pod <pod-name> -n <namespace> --force --grace-period=0
4.节点问题(Node issues):
如果节点无响应、断开连接或遇到其他问题,pod 可能会进入"Unknown"状态。在这种情况下,Kubernetes 控制平面无法确定 pod 的实际状态。
5.网络问题(Network issues):
节点与 Kubernetes 控制平面之间的连接问题可能导致 pod 进入"Unknown"状态。例如,如果控制平面无法与节点通信,则无法接收来自 pod 的状态更新。
6.Kubelet 问题
如果节点上运行的 Kubelet 进程出现问题或崩溃,可能会导致无法将 pod 状态上报给控制平面,从而造成 pod 进入"Unknown"状态。
解决方法:
检查节点状态/事件: 检查 pod 所在节点的状态:$ kubectl describe node <node-name>
$ kubectl get events --field-selector involvedObject.kind=Node,involvedObject.name=<node-name>检查节点系统日志$ journalctl -u kubelet
$ journalctl -u docker
$ journalctl -u containerd
$ cat /var/log/messages排空节点: 如果已经确定了节点问题,并且需要执行维护,可以排空节点以安全驱逐所有正在运行的 pod,并将节点标记为不可调度:$ kubectl drain <node-name>
3.7 Pod处于Unknown状态
Unknown 这是一个异常状态,意味着 Pod 的状态不能持续地被 kubelet 汇报给 kube-apiserver,这很有可能是主从节点(Master 和 Kubelet)间的通信出现了问题。