在 Kubernetes 集群中,Pod 调度失败是一个常见的问题,尤其是在大规模、复杂的应用场景下。最近,我们遇到一个诡异的 Pod 调度问题,一个简单的 Deployment 始终无法成功调度到任何节点,持续处于 Pending 状态。经过一番抽丝剥茧的排查,最终定位到问题根源,也让我对 Kubernetes 的调度机制有了更深入的理解。接下来,我将分享这次问题排查的全过程,以及一些实用的排查技巧。
问题重现:Pod 持续 Pending
我们的目标是在 Kubernetes 集群中部署一个简单的 Nginx 服务。Deployment 的 YAML 文件如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
使用 kubectl apply -f nginx-deployment.yaml 命令部署后,Pod 并没有如预期般运行起来,而是长时间处于 Pending 状态。使用 kubectl describe pod <pod-name> 命令查看 Pod 的详细信息,发现 Event 列表中有如下信息:
Events:
Type Reason Age From Message
---- ------ ---- ---- ------
Warning FailedScheduling 10s default-scheduler 0/3 nodes are available: 3 Insufficient cpu.
底层原理:Kubernetes 调度器的工作机制
要解决 Kubernetes Pod 调度失败的问题,首先需要了解 Kubernetes 调度器的工作机制。Kubernetes 调度器(kube-scheduler)负责将新创建的 Pod 分配到集群中的节点上。调度过程大致分为以下几个阶段:
- 过滤(Filtering):调度器会根据 Pod 的资源需求(CPU、内存等)、节点亲和性、反亲和性、污点和容忍度等条件,过滤掉不满足条件的节点。
- 打分(Scoring):对于通过过滤的节点,调度器会根据一定的策略(例如资源利用率、节点负载等)进行打分,选择得分最高的节点。
- 绑定(Binding):调度器将 Pod 绑定到选定的节点上,kubelet 接收到调度指令后,开始创建和运行 Pod。
上述 Event 信息中的 Insufficient cpu 表明,Pod 因为 CPU 资源不足而无法调度。这可能是由于以下原因导致的:
- 集群中所有节点的 CPU 资源都已耗尽。
- Pod 声明的 CPU 资源需求超过了集群中任何节点的剩余 CPU 资源。
- Pod 声明的 CPU 资源需求与节点的可用资源不匹配(例如,Pod 需要独占 CPU 核心)。
解决方案:资源限制与请求的合理配置
首先,我们需要检查集群中节点的资源使用情况。可以使用 kubectl top node 命令查看节点的 CPU 和内存使用情况。如果发现所有节点的 CPU 使用率都接近 100%,则需要增加节点数量,或者优化应用的资源使用。
其次,我们需要检查 Pod 的资源请求(requests)和限制(limits)是否配置合理。资源请求是 Kubernetes 调度器用于判断节点是否有足够资源来运行 Pod 的依据。资源限制是 Pod 能够使用的最大资源量。合理的配置资源请求和限制可以避免 Pod 占用过多的资源,影响其他 Pod 的运行。
例如,我们可以为 Nginx Deployment 配置资源请求和限制:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
resources:
requests:
cpu: 100m # 100 millicores
memory: 128Mi
limits:
cpu: 500m # 500 millicores
memory: 256Mi
上述配置表示,每个 Nginx Pod 至少需要 100m CPU 和 128Mi 内存,最多可以使用 500m CPU 和 256Mi 内存。
如果 Pod 仍然无法调度,可以尝试以下方法:
- 调整 Pod 的资源请求和限制:逐步降低资源请求,直到 Pod 可以成功调度。
- 检查节点亲和性和反亲和性:确保 Pod 的节点亲和性和反亲和性配置正确,不会导致 Pod 无法调度到任何节点。
- 检查污点和容忍度:确保 Pod 具有足够的容忍度,可以容忍节点上的污点。
- 使用资源配额(ResourceQuota):如果集群中启用了资源配额,需要确保 Pod 的资源请求不超过配额限制。
实战避坑:排查的经验总结
在 Kubernetes Pod 调度失败的排查过程中,以下几点经验值得注意:
- 详细阅读
kubectl describe pod的输出:Event 列表通常包含关键的调度失败信息,例如资源不足、节点亲和性冲突等。 - 使用
kubectl top node和kubectl top pod命令监控资源使用情况:及时发现资源瓶颈,避免 Pod 调度失败。 - 合理配置资源请求和限制:根据应用的实际需求,合理配置资源请求和限制,避免资源浪费或资源不足。
- 关注 Kubernetes 集群的日志:kube-scheduler、kubelet 等组件的日志可能包含更详细的调度信息。
- 考虑使用监控工具:Prometheus、Grafana 等监控工具可以帮助你更好地了解集群的资源使用情况和 Pod 的调度状态,快速定位问题。
此外,国内很多开发者喜欢使用宝塔面板来简化服务器管理,但在 Kubernetes 环境中,不建议直接在节点上安装宝塔面板,因为它可能会与 Kubernetes 的资源管理机制冲突,导致 Pod 调度异常。如果需要使用类似的功能,可以考虑使用 Kubernetes 社区提供的 Dashboard 或其他专门的监控工具。
掌握了这些排查技巧,相信你也能轻松应对 Kubernetes Pod 调度失败的问题,让你的应用在 Kubernetes 集群中稳定运行。
冠军资讯
DevOps小王子