Kubernetes 优先级与调度管理

一、调度器工作原理

Kubernetes 调度器(kube-scheduler)负责为 Pod 选择最佳运行节点,核心流程:

plaintext

复制代码
┌─────────────────────────────────────────────────────────────────────┐
│                    Pod 创建到调度完整流程                             │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  1. API Server 接收 Pod 创建请求                                     │
│                    ↓                                                 │
│  2. Pod 进入调度队列(Scheduling Queue)                              │
│                    ↓                                                 │
│  3. 调度器执行预选(Filtering)→ 筛选可用节点                          │
│     ┌─────────────────────────────────────────────────────────────┐ │
│     │  预选条件: 资源充足 | 端口可用 | 选择器匹配 | 容忍匹配        │ │
│     └─────────────────────────────────────────────────────────────┘ │
│                    ↓                                                 │
│  4. 调度器执行优选(Scoring)→ 节点打分排序                            │
│     ┌─────────────────────────────────────────────────────────────┐ │
│     │  打分维度: 资源利用率 | 亲和性 | 数据局部性 | 优先级          │ │
│     └─────────────────────────────────────────────────────────────┘ │
│                    ↓                                                 │
│  5. 绑定(Binding)→ 将 Pod 绑定到最优节点                             │
│                    ↓                                                 │
│  6. Kubelet 在目标节点拉取并启动容器                                  │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

调度决策受多种因素影响:优先级、资源请求、亲和性、污点等。

二、PriorityClass 优先级类

2.1 核心概念

PriorityClass 定义 Pod 的调度优先级,数值越大优先级越高。高优先级 Pod 可抢占低优先级 Pod 的资源。

plaintext

复制代码
┌─────────────────────────────────────────────────────────────────────┐
│                        PriorityClass 抢占机制                        │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  高优先级 Pod (priority=1000)                                       │
│       │                                                             │
│       ├─→ 调度失败(无合适节点)                                      │
│       │                                                             │
│       └─→ 抢占低优先级 Pod 资源 ──→ 驱逐低优先级 Pod ──→ 调度成功      │
│                                      ↓                               │
│                           低优先级 Pod (priority=100)               │
│                           被驱逐后重新进入调度队列                    │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

2.2 系统内置 PriorityClass

表格

名称 优先级值 用途
system-cluster-critical 2000000000 集群关键组件(kube-system)
system-node-critical 2000001000 节点关键组件(kubelet 等)

注意:数值超过 10 亿的为系统保留,不要自定义这么高的值。

2.3 自定义 PriorityClass

yaml

复制代码
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 10000
globalDefault: false
description: "生产环境高优先级应用"
---
apiVersion: v1
kind: Pod
metadata:
  name: high-priority-app
spec:
  priorityClassName: high-priority
  containers:
  - name: app
    image: nginx:latest
    resources:
      requests:
        memory: "128Mi"
        cpu: "100m"
      limits:
        memory: "256Mi"
        cpu: "200m"

三、nodeSelector 节点选择器

最简单的调度方式,通过标签筛选节点。

bash

复制代码
# 为节点添加标签
kubectl label node k8s-node-1 disk-type=ssd
kubectl label node k8s-node-2 disk-type=HDD

# 查看节点标签
kubectl get nodes --show-labels

yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: ssd-app
spec:
  nodeSelector:
    disk-type: ssd          # 只会调度到带此标签的节点
  containers:
  - name: app
    image: nginx:latest

四、nodeAffinity 节点亲和性

比 nodeSelector 更强大的节点选择机制,支持硬限制软偏好

4.1 两种策略对比

表格

类型 行为 等同于
requiredDuringSchedulingIgnoredDuringExecution 硬限制,不满足则不调度 nodeSelector 必选
preferredDuringSchedulingIgnoredDuringExecution 软偏好,尽量满足 nodeSelector 首选

4.2 YAML 示例

yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: multi-zone-app
spec:
  affinity:
    nodeAffinity:
      # 硬性要求:必须运行在 amd64 架构节点
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/arch
            operator: In
            values:
            - amd64
            - arm64
      # 软性偏好:优先选择 zone=prod 的节点
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 80
        preference:
          matchExpressions:
          - key: zone
            operator: In
            values:
            - prod
      - weight: 20
        preference:
          matchExpressions:
          - key: disk-type
            operator: In
            values:
            - ssd
  containers:
  - name: app
    image: nginx:latest

五、podAffinity 与 podAntiAffinity

5.1 核心概念

  • podAffinity:让 Pod 倾向于与某些 Pod 部署在同一区域(同一节点/可用区)
  • podAntiAffinity:让 Pod 倾向于与其他 Pod 分开部署

5.2 YAML 示例

yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web-server
spec:
  affinity:
    # 希望与 redis Pod 部署在一起
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - redis
        topologyKey: kubernetes.io/hostname    # 同一节点
    # 避免与其他 web-server 部署在同一节点
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - web-server
        topologyKey: kubernetes.io/hostname
  containers:
  - name: nginx
    image: nginx:latest

topologyKey 常用值:

  • kubernetes.io/hostname:同一节点
  • topology.kubernetes.io/zone:同一可用区
  • topology.kubernetes.io/region:同一地域

六、Taints 污点与 Tolerations 容忍

6.1 污点效果类型

表格

效果 行为
NoSchedule 不调度新 Pod 到此节点(不影响已有 Pod)
PreferNoSchedule 尽量不调度,不强制
NoExecute 驱逐已有 Pod,且不再调度新 Pod

6.2 污点管理命令

bash

复制代码
# 添加污点(节点不可调度)
kubectl taint node k8s-node-1 dedicated=apps:NoSchedule

# 添加污点(节点不可调度,含特殊值)
kubectl taint node k8s-node-1 key=value:NoExecute --overwrite

# 移除污点
kubectl taint node k8s-node-1 dedicated-

# 查看节点污点
kubectl describe node k8s-node-1 | grep Taints

6.3 Pod 容忍配置

yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: tolerating-app
spec:
  tolerations:
  # 容忍指定污点
  - key: "dedicated"
    operator: "Equal"
    value: "apps"
    effect: "NoSchedule"
  # 容忍所有 NoSchedule 污点
  - key: "dedicated"
    operator: "Exists"
    effect: "NoSchedule"
  # 容忍所有污点(慎用)
  - operator: "Exists"
  # 容忍 NoExecute 污点,300秒后驱逐
  - key: "node.kubernetes.io/not-ready"
    operator: "Exists"
    effect: "NoExecute"
    tolerationSeconds: 300
  containers:
  - name: app
    image: nginx:latest

七、资源限制与调度

调度器根据 requests 评估节点可用资源,而非 limits。

yaml

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: resource-demo
spec:
  containers:
  - name: app
    image: nginx:latest
    resources:
      requests:
        memory: "1Gi"      # 调度依据:节点需满足此资源
        cpu: "500m"
      limits:
        memory: "2Gi"     # 硬限制:超过则 OOM 或限流
        cpu: "1000m"

plaintext

复制代码
┌─────────────────────────────────────────────────────────────────────┐
│                    requests vs limits 调度影响                       │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  requests (调度依据):                                                │
│  - 调度器计算: Node 可分配资源 = 节点总资源 - 已调度 Pod requests      │
│  - Pod 只有 requests ≤ 可分配资源 时才能调度                          │
│                                                                      │
│  limits (运行时限制):                                                 │
│  - 不影响调度决策                                                    │
│  - 仅在容器运行时生效(CPU 限流 / 内存 OOM)                          │
│                                                                      │
│  ⚠️ 如果 requests 未设置:                                            │
│  - 默认等于 limits(若有定义)                                       │
│  - 或默认为 0(完全不受控,风险极高)                                │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

八、常见问题与排查

8.1 Pod 一直处于 Pending 状态

bash

复制代码
# 1. 查看 Pod 详情和事件
kubectl describe pod <pod-name>

# 2. 检查是否有可用节点
kubectl get nodes

# 3. 检查节点资源
kubectl describe node <node-name> | grep -A 5 "Allocated resources"

# 4. 检查调度器日志
kubectl logs -n kube-system kube-scheduler-<pod> --tail=100

常见原因

  • 节点资源不足(requests > 可用资源)
  • nodeSelector/nodeAffinity 条件无匹配节点
  • 污点无对应容忍

8.2 抢占成功但原 Pod 未被驱逐

bash

复制代码
# 检查被抢占 Pod 的调度状态
kubectl get pod <pod-name> -o wide
kubectl describe pod <pod-name>

# 查看 Pod 优先级
kubectl get pod <pod-name> -o jsonpath='{.spec.priority}'

注意 :抢占后原 Pod 进入 Terminating 状态,需要等待 kubelet 真正删除才会调度新 Pod。

8.3 调度不均匀

bash

复制代码
# 查看各节点 Pod 分布
kubectl get pods -o wide --sort-by='.spec.nodeName'

# 检查是否存在软亲和性权重问题
kubectl describe pod <pod-name> | grep -A 10 "Affinity"

九、最佳实践

  1. 合理设置 PriorityClass 值:生产环境建议 1000-10000,避免占用系统优先级

  2. 避免资源 requests 过小:设置为实际需求的 80-90%,预留弹性空间

  3. 优先使用 nodeAffinity 而非污点:污点影响范围大,affinity 更精细

  4. 生产环境禁用 PreferNoSchedule:该策略不强制,可能导致调度不符合预期

  5. DaemonSet 配合容忍使用:确保关键组件能在带污点的 master 节点运行

  6. PodAntiAffinity 谨慎使用 :配合 topologyKey: topology.kubernetes.io/zone 防止单点故障

  7. 调度失败及时排查:优先检查事件(kubectl describe)和调度器日志

  8. 监控调度延迟:调度耗时过长可能影响业务响应,及时优化调度器配置

相关推荐
hopsky1 小时前
docker 容器文件异常大的问题排查
运维·docker·容器
bloglin999991 小时前
兼容旧版 docker-compose 和新版 docker compose
运维·docker·容器
老码观察1 小时前
K8s集群断电后MySQL恢复实录:从InnoDB崩溃到数据完整迁移
mysql·adb·kubernetes
largecode1 小时前
给用户打电话,怎么在对方手机显示为“XX旅游”?号码认证办理教程
linux·服务器·容器·智能手机·ssh·旅游·vagrant
Cat_Rocky2 小时前
K8S中的优先级
云原生·容器·kubernetes
刘某的Cloud3 小时前
docker && containerd 镜像加速
运维·docker·容器·containerd·镜像加速
2301_780789663 小时前
容器环境漏洞扫描:适配 K8s 架构的镜像与 Pod 安全检测方案
网络·安全·web安全·云原生·架构·kubernetes·ddos
运维老郭3 小时前
【K8s 调度三阶段 · 避坑完全指南】过滤→打分→绑定,9 成 Pending 都卡在第一关
运维·云原生·kubernetes
云游牧者3 小时前
深入理解K8S-Pod生命周期与资源管理-CSDN博客
kubernetes·探针·pod生命周期·pod优雅终止