spec.nodeName 是什么
在 Pod 规格里直接写 spec.nodeName,等于跳过分发环节:kube-scheduler 不参与该 Pod 的调度,kubelet 拿到以后直接在指定节点上启动。它是「我把 Pod 放哪儿我自己说了算」的写法,适合调试、临时排障和特殊拓扑,但不做资源余量、节点亲和性、Pod 反亲和以及 Taint 的判定,可靠性由使用者自己负责。
基本信息
| 字段位置 | Pod.spec.nodeName,字符串,创建时写入 |
|---|---|
| 决策方 | 没有调度器参与,Pod 直接落到指定节点 |
| 不可变性 | Pod 创建后不能改节点,换节点只能重建 Pod |
| 跳过的检查 | 节点亲和性、Pod 反亲和、污点过滤、节点资源余量预检 |
| 常见写入方 | 排障脚本、平台工具、少数专用控制器 |
典型使用场景
- 排障:节点疑似有问题时,把诊断 Pod 精确放到该节点上验证磁盘、网络与运行时
- 验证节点本地资源:确认某块 GPU、某块本地盘或某个设备插件只在这台机器上生效
- 平台工具接管调度:由外部系统决定落点并直接创建 Pod,不使用集群默认调度器
- 演示与教学:直观说明调度器在 Pod 创建过程中承担了哪些判断
- 临时应急:某节点需要立刻跑一个脚本,来不及等调度器与控制器链路
直绑节点
直绑节点
apiVersion: v1
kind: Pod
metadata:
name: debug-pod
spec:
nodeName: node1 # 名称必须与 kubectl get nodes 完全一致
restartPolicy: Never # 排障 Pod 常用 Never,避免异常状态下被反复拉起
containers:
- name: shell
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]创建与核对
创建与核对
kubectl get nodes -o wide # 第一步:核对准确的节点名与 Ready 状态
kubectl run diag-shell --image=busybox:1.36 --restart=Never \
--overrides='{"spec":{"nodeName":"node1"}}' -- sleep 3600 # 命令行直接直绑
kubectl get pod diag-shell -o wide # 看 NODE 列是否符合预期
kubectl get node node1 -o jsonpath='{.spec.taints}{"\n"}' # 直绑不会被污点拦住,先看节点是否被标记为专用
kubectl describe node node1 | head -30 # 节点状态、资源余量与现有 Pod 占用定位节点方式对比
| 方式 | 谁做决策 | 约束检查 | 适用场景 |
|---|---|---|---|
| spec.nodeName | 创建者写死 | 调度器不参与,亲和性与污点判定都不执行 | 调试、临时排障、外部调度器接管 |
| nodeSelector | kube-scheduler | 按标签过滤节点 | 用固定标签做简单选择 |
| nodeAffinity 与反亲和 | kube-scheduler | 支持软硬约束与拓扑分散 | 生产环境表达放置意图的首选 |
节点名在公有云和自动伸缩组里常常不稳定:实例重建后被替换成新名字,写死的 nodeName 就指向了一个不存在的节点。需要「跟着这台机器跑」的负载用标签加 nodeAffinity 表达,让标签由重命名过程自己维护。
排障顺序:先 kubectl get nodes 确认节点存在且 Ready,再看 kubectl get pod -o wide 与 Pod 事件,然后到节点上查 kubelet 日志(journalctl -u kubelet 加 Pod 名过滤)。直绑场景下报错往往来自 kubelet 本地准入或容器运行时,而不是调度器。
直绑节点等于自己承担超卖风险:调度器不会帮你算余量,也不会在节点故障时重新安排。生产工作负载请用 nodeAffinity、污点容忍与反亲和表达意图,把 nodeName 留给排障和特殊场景。