找回密码
立即注册
搜索
发回帖 发新帖

5542

积分

0

好友

714

主题
发表于 17 小时前 | 查看: 6| 回复: 0

一个 Deployment 有足够的 CPU 和内存 request,却仍然长期 Pending;或者所有副本恰好落在同一台节点、同一个可用区,节点维护时一起中断。这类问题往往不是“调度器坏了”,而是工作负载表达的约束与集群的真实拓扑不匹配。调度器只能在声明的资源、标签、污点、亲和性、反亲和性和拓扑规则之间寻找可行节点;约束互相矛盾时,它正确的行为就是不调度。

Pod 亲和性、反亲和性与 topologySpreadConstraints 都能影响副本放置,但解决的不是同一个问题。Node affinity 表达“这个 Pod 可以或必须去哪些节点”;Pod affinity/anti-affinity 表达“这个 Pod 相对于另一个 Pod 应该靠近还是远离”;拓扑分布约束表达“同一类 Pod 在 zone、hostname 等域之间允许有多不均衡”。把它们同时堆到一个 Pod spec 里并不会自动提高可用性,反而常使候选节点集合缩小到空集。

本文面向已经具备基础 Kubernetes 运维经验的读者,使用 <命名空间>、<应用标签>、<节点标签>、<镜像>、<区域标签> 等占位符。它们都需要替换为集群真实值。示例以 networking、工作负载和调度对象为主;所有 kubectl 命令显式携带 -n <命名空间>。不同 Kubernetes 版本对 minDomains、matchLabelKeys、nodeAffinityPolicy 等字段支持不同,应用 YAML 前应先通过 kubectl version、CRD/OpenAPI schema 或 kubectl explain 确认。文中未逐项列出的尖括号变量也按中文含义替换为真实节点、对象、版本、路径或数量,并写入经过审查的声明配置。

先区分三个“距离”概念

调度策略常被描述成“分散部署”,但至少有三种不同距离:

目标 更合适的机制 典型例子 常见误用
选择具备硬件或隔离标签的节点 nodeSelector 或 NodeAffinity GPU、特定 CPU、合规节点池 用 Pod anti-affinity 代替节点标签
与另一类 Pod 同机或同可用区 PodAffinity 缓存代理与本地数据服务 未考虑资源竞争和故障域
避免同类副本同机、同区 PodAntiAffinity 或 topology spread 高可用 API 多副本 把 required 规则设得比节点数更苛刻
控制跨域副本偏差 topologySpreadConstraints 6 个副本尽量均匀分到 3 个 zone 以为它自动创建新节点或新 zone

nodeSelector 是最简单的硬条件,只能按完全匹配标签筛选。NodeAffinity 更灵活,可使用 In、NotIn、Exists、DoesNotExist、Gt、Lt,并区分 required 与 preferred。PodAntiAffinity 按拓扑域排斥已有匹配 Pod,范围受 topologyKey 控制;其 required 形式会直接改变可调度性。拓扑分布约束用 maxSkew 表达允许的偏差,常适合“希望均衡但仍要可调度”的业务副本。

在设计前先写明服务目标:例如“任意一个节点故障不影响超过一个副本”“任意一个 zone 故障后仍保留两个可用副本”“GPU 推理只跑在 gpu=true 节点池”“批任务不得挤占在线服务节点”。目标必须与副本数、节点数、zone 数、PDB、HPA 和容量计划一起看。3 个副本无法同时保证跨 4 个 zone 均匀;1 个 zone 不可能通过 YAML 获得跨 zone 高可用。

先从调度证据开始

不要先修改 affinity。Pending 的根因可能是 request 超过节点余量、Pod 有未容忍污点、PVC 受卷拓扑限制、镜像拉取失败、抢占被禁止,或者亲和性确实无解。调度器事件是第一证据,节点标签和现有副本分布是第二证据。

# 代码 1:盘点节点、可用区标签与污点
kubectl get nodes -n <命名空间> -L kubernetes.io/hostname -L topology.kubernetes.io/zone -L <节点标签>
kubectl describe nodes -n <命名空间> | rg -n 'Name:|Taints:|Allocated resources:|topology.kubernetes.io/zone'
kubectl get pods -n <命名空间> -o wide

标签的存在不等于标签可信。由 kubelet 可随意修改的业务标签不应用来承载安全或合规边界;需要可信节点属性时,应使用经过 NodeRestriction 保护的标签前缀或由受控自动化写入。污点必须与容忍一起评估:即使 affinity 匹配,未容忍 NoSchedule 污点的 Pod 仍然无法落到该节点。

# 代码 2:定位 Pending Pod 的调度失败事件
kubectl get pods -n <命名空间> --field-selector=status.phase=Pending -o wide
kubectl describe pod -n <命名空间> <Pod名称>
kubectl get events -n <命名空间> --sort-by=.lastTimestamp | rg 'FailedScheduling|Preempt|Unschedulable'

FailedScheduling 中会列出被排除节点数量和常见原因,例如 Insufficient cpu、node(s) didn't match Pod's node affinity、node(s) didn't match pod anti-affinity rules。不要截取其中一句就下结论;同一次调度尝试可能同时命中资源、污点和亲和性多个限制,真正修复应减少最不符合目标的约束,而不是逐条强行放宽。

# 代码 3:比较同一应用的实际副本与节点分布
kubectl get pods -n <命名空间> -l app=<应用标签> \
  -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName,PHASE:.status.phase,IP:.status.podIP
kubectl get deployment -n <命名空间> <部署名称> -o yaml
kubectl get replicaset -n <命名空间> -l app=<应用标签> -o wide

先分清“计划中的规则”和“已经运行的历史副本”。亲和性中的 IgnoredDuringExecution 表示节点标签后来变化时,已运行 Pod 通常不会被自动驱逐;这不是规则失效,而是字段语义。若要重平衡,要结合安全的 rollout、descheduler 或人工迁移策略,而不是期待调度器自动移动已运行工作负载。

节点标签与 NodeAffinity:描述硬件、隔离和容量边界

适合用 NodeAffinity 的条件应是相对稳定、可审计的节点属性,例如 CPU 架构、已验证的 GPU 型号、合规节点池、网络设备、存储局部性或维护域。不要用一个临时标签去修复短期 Pending;那会把临时故障固化为长期调度依赖。

如果需要为受管节点池增加业务标签,先导出当前标签和污点,再使用 server dry-run 验证操作形式。给节点打标签会影响未来调度,不会自动迁移已经运行的 Pod;对自动扩缩的节点池,还要把标签写进节点池模板,避免新节点缺失标签。

# 代码 4:标签变更前的检查与 dry-run
kubectl get node -n <命名空间> <节点名称> --show-labels
kubectl describe node -n <命名空间> <节点名称> | rg -n 'Taints:|Labels:|Unschedulable:'
kubectl label node -n <命名空间> <节点名称> <节点标签>=true --dry-run=server

这是潜在高影响操作。执行前确认节点属于正确节点池、没有与现有标签冲突、不会把敏感工作负载引到错误故障域。server dry-run 不能模拟后续所有 Pod 的调度结果,因此变更应先在一台灰度节点或测试节点池验证,并保留原标签快照用于回滚。

# 代码 5:简单 nodeSelector,适合单个稳定标签
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: <命名空间>
spec:
  replicas: 3
  selector:
    matchLabels:
      app: <应用标签>
  template:
    metadata:
      labels:
        app: <应用标签>
    spec:
      nodeSelector:
        <节点标签>: "true"
      containers:
      - name: api
        image: <镜像>@sha256:<镜像摘要>
        resources:
          requests:
            cpu: 250m
            memory: 512Mi
          limits:
            cpu: "1"
            memory: 1Gi

nodeSelector 是硬约束。只有所有键值匹配的节点才是候选节点,因此至少要确认目标节点数大于在该节点池上的副本数,并留出维护余量。资源 requests 影响调度器的可用容量计算;没有 requests 的示例无法用于评估是否真的可调度。

# 代码 6:required NodeAffinity,选择多个允许的节点池
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: <命名空间>
spec:
  replicas: 3
  selector:
    matchLabels:
      app: <应用标签>
  template:
    metadata:
      labels:
        app: <应用标签>
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: <节点标签>
                operator: In
                values:
                - standard
                - compute
      containers:
      - name: api
        image: <镜像>@sha256:<镜像摘要>

同一个 nodeSelectorTerm 内的多个 matchExpressions 是 AND,不同 nodeSelectorTerms 是 OR。这个逻辑很容易写反:如果要求节点既在标准池又在 compute 池,通常不会有候选节点;若希望任一池可用,应放在不同 values 或不同 term 中,具体写法取决于标签模型。

# 代码 7:preferred NodeAffinity,优先选择本地区域但保留回退
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: <命名空间>
spec:
  replicas: 3
  selector:
    matchLabels:
      app: <应用标签>
  template:
    metadata:
      labels:
        app: <应用标签>
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 80
            preference:
              matchExpressions:
              - key: topology.kubernetes.io/zone
                operator: In
                values:
                - <首选可用区>
      containers:
      - name: api
        image: <镜像>@sha256:<镜像摘要>

preferred 不是保证。调度器会在满足硬约束的节点中打分,资源压力、污点、其他插件和已有 Pod 都可能改变最终位置。它适合“有偏好但不能因偏好而不可用”的需求,例如降低跨区延迟;不适合必须满足合规或硬件要求的场景。

# 代码 8:应用节点约束前后验证候选节点和滚动状态
kubectl diff -n <命名空间> -f api-node-affinity.yaml || true
kubectl apply -n <命名空间> -f api-node-affinity.yaml
kubectl rollout status -n <命名空间> deployment/api --timeout=180s
kubectl get pods -n <命名空间> -l app=<应用标签> -o wide

更新 Deployment 后,旧 Pod 不一定立即消失,最终分布要在 rollout 完成后检查。若 rollout 卡住,先看新 ReplicaSet 的 Pod 事件;不要为了继续发布把所有 affinity 删除,因为旧副本和新副本可能因此落在不希望的节点上。

Pod 亲和性与反亲和性:明确副本之间的关系

PodAffinity 和 PodAntiAffinity 通过 labelSelector 找到“参考 Pod”,再按照 topologyKey 判断是否同域。topologyKey=topology.kubernetes.io/zone 表示可用区;topologyKey=kubernetes.io/hostname 表示同一节点。前者适用于 zone 级高可用和区域内靠近,后者适用于单节点故障隔离或本地协作。

反亲和性的 required 规则很强:当副本数大于可用拓扑域数、匹配标签写错、或者节点缺少 topologyKey 时,Pod 会 Pending。对在线服务常见的做法是:把“不得同机”设为 required(前提是节点数充足),把“尽量跨 zone”设为 preferred 或 topology spread,以避免一个 zone 容量不足时全局不可用。

# 代码 9:required PodAntiAffinity,确保同一应用副本不共用主机
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: <命名空间>
spec:
  replicas: 3
  selector:
    matchLabels:
      app: <应用标签>
  template:
    metadata:
      labels:
        app: <应用标签>
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchLabels:
                app: <应用标签>
            topologyKey: kubernetes.io/hostname
      containers:
      - name: api
        image: <镜像>@sha256:<镜像摘要>

这条规则要求每个匹配 Pod 占用不同 hostname 域。执行前必须确认可用、可调度、且满足其他硬约束的节点数不少于 replicas,另外还要考虑节点维护和故障时的余量。若集群只有两台符合条件节点而副本数是三,第三个 Pending 是正确结果。

# 代码 10:preferred PodAntiAffinity,尽量避免同可用区集中
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: <命名空间>
spec:
  replicas: 3
  selector:
    matchLabels:
      app: <应用标签>
  template:
    metadata:
      labels:
        app: <应用标签>
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchLabels:
                  app: <应用标签>
              topologyKey: topology.kubernetes.io/zone
      containers:
      - name: api
        image: <镜像>@sha256:<镜像摘要>

如果业务真正要求任何 zone 都不应失去超过一个副本,仅用 preferred 不够;还需在副本数、节点容量、PDB 与拓扑分布约束中共同验证。但如果当前集群偶尔只有一个 zone 有余量,强制跨 zone 可能导致发布无法完成,preferred 就是更符合可用性优先级的表达。

# 代码 11:PodAffinity,让本地代理优先与缓存服务同 zone
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cache-client
  namespace: <命名空间>
spec:
  replicas: 3
  selector:
    matchLabels:
      app: cache-client
  template:
    metadata:
      labels:
        app: cache-client
    spec:
      affinity:
        podAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 50
            podAffinityTerm:
              labelSelector:
                matchLabels:
                  app: shared-cache
              topologyKey: topology.kubernetes.io/zone
      containers:
      - name: client
        image: <镜像>@sha256:<镜像摘要>

亲和性适合降低跨区延迟或减少跨域流量,但不应把有状态依赖的单点位置当成“必须同机”的理由。与缓存同 zone 只是性能偏好;如果缓存本身不可用,应用仍要能通过服务发现和超时重试正常降级。

# 代码 12:验证亲和性选择器是否能匹配真实 Pod
kubectl get pods -n <命名空间> -l app=<应用标签> --show-labels -o wide
kubectl get pods -n <命名空间> -l app=shared-cache --show-labels -o wide
kubectl get events -n <命名空间> --sort-by=.lastTimestamp | rg 'FailedScheduling'

亲和性匹配的是 Pod template 的 labels,不是 Deployment 名称、Service 名称或 Helm release 名称。若标签选择器一个 Pod 都选不到,podAffinity 的 required 规则往往导致无法调度;anti-affinity 则可能等同于没有排斥。改前先核对标签比事后解释 Pending 更可靠。

拓扑分布约束:在可用性和可调度性之间设定偏差

topologySpreadConstraints 是更直接的副本均衡工具。maxSkew 表示各拓扑域中符合选择器的 Pod 数量允许的最大差值;whenUnsatisfiable=DoNotSchedule 让它成为硬限制,ScheduleAnyway 则优先均衡但允许在容量不足时继续调度。它不替代资源请求和节点容量,也不会把现有副本自动搬走。

对于稳定在线服务,常用组合是:hostname 域 maxSkew=1、DoNotSchedule 保证尽量不共机;zone 域 maxSkew=1、ScheduleAnyway 保留区域容量不足时的发布能力。是否把 zone 也设为 DoNotSchedule,取决于 SLO 是否允许“少一个副本”还是“发布卡住”。不要在未压测过扩容和故障域的前提下给出通用答案。

# 代码 13:同时控制 hostname 与 zone 的拓扑分布
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: <命名空间>
spec:
  replicas: 6
  selector:
    matchLabels:
      app: <应用标签>
  template:
    metadata:
      labels:
        app: <应用标签>
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: kubernetes.io/hostname
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: <应用标签>
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: ScheduleAnyway
        labelSelector:
          matchLabels:
            app: <应用标签>
      containers:
      - name: api
        image: <镜像>@sha256:<镜像摘要>

同一 Pod 同时受两个约束限制,候选节点必须满足所有 DoNotSchedule 条件。6 个副本在只有两台节点、一个 zone 的集群中,hostname 条件就可能使第四个以后无法调度。先用当前节点数、故障域数和目标副本数做容量表,再决定 maxSkew 和硬/软语义。

# 代码 14:需要最小故障域数量时的 minDomains 示例
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: <命名空间>
spec:
  replicas: 3
  selector:
    matchLabels:
      app: <应用标签>
  template:
    metadata:
      labels:
        app: <应用标签>
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        minDomains: 3
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: <应用标签>
      containers:
      - name: api
        image: <镜像>@sha256:<镜像摘要>

minDomains 需要 Kubernetes 版本支持。它表达“至少需要几个合格拓扑域”的语义,适用于明确依赖三可用区的服务;如果集群平时只有两个可用 zone 或某个 zone 正在维护,该约束会阻断新副本。版本不支持时不要盲目删除字段后继续用同样的可用性承诺。

# 代码 15:在发布前核对拓扑标签覆盖面
kubectl get nodes -n <命名空间> -L kubernetes.io/hostname -L topology.kubernetes.io/zone
kubectl get pods -n <命名空间> -l app=<应用标签> -o wide
kubectl get deployment -n <命名空间> api -o jsonpath='{.spec.replicas}{"\n"}'

若部分节点缺少 topologyKey,调度器对这些节点的处理取决于约束和版本,不能把它们视为正常故障域。先补齐节点池模板和现有节点标签,或者从候选集明确排除缺失标签的节点;不要让同一节点池中部分节点带 zone 标签、部分不带。

与 PDB、优先级和容量协同

调度分散并不等于应用可用。PDB 约束的是自愿中断期间允许不可用的副本数,不能防止节点硬故障;HPA 改变 replicas 后会重新测试原有拓扑规则;PriorityClass 会影响抢占与资源竞争。它们必须和 affinity 一起做故障演练。

# 代码 16:与三副本在线服务配套的 PDB
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: api-pdb
  namespace: <命名空间>
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: <应用标签>

minAvailable=2 只是在有三个健康副本时允许一次自愿驱逐一个 Pod;若副本已经不健康、拓扑规则无法补副本,节点 drain 可能被阻塞。PDB 应按服务实际可用副本、发布策略和维护窗口设计,不应机械复制到单副本或批处理 Job。

# 代码 17:为关键在线服务设置受控 PriorityClass
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: online-critical
value: 100000
globalDefault: false
description: "仅供经过容量评审的在线服务使用"

PriorityClass 是集群级资源,过高优先级可能触发抢占,使低优先级工作负载被驱逐。创建前应盘点现有优先级值并由平台团队分配区间;不能把它当成解决长期容量不足的工具。业务 Deployment 仅在确有审批时引用 priorityClassName。

# 代码 18:在工作负载中引用优先级和受控终止时间
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: <命名空间>
spec:
  replicas: 3
  selector:
    matchLabels:
      app: <应用标签>
  template:
    metadata:
      labels:
        app: <应用标签>
    spec:
      priorityClassName: online-critical
      terminationGracePeriodSeconds: 30
      containers:
      - name: api
        image: <镜像>@sha256:<镜像摘要>
        resources:
          requests:
            cpu: 250m
            memory: 512Mi

优先级只影响调度和抢占顺序,不替代 PDB、反亲和性或容量预留。终止宽限期也应按应用实际的连接排空和事务行为确定;盲目缩短可能造成连接中断,盲目拉长则会拖慢故障恢复和滚动更新。

# 代码 19:变更后检查副本、PDB 与调度事件
kubectl rollout status -n <命名空间> deployment/api --timeout=180s
kubectl get pods -n <命名空间> -l app=<应用标签> -o wide
kubectl get poddisruptionbudget -n <命名空间> api-pdb -o yaml
kubectl get events -n <命名空间> --sort-by=.lastTimestamp

发布成功不代表分布满足目标。应对照 hostname 与 zone 列检查每个副本位置,并在一个可控的维护窗口演练 drain 或副本扩缩,记录 PDB、调度器事件、重建时间和业务错误率。没有演练证据时,不要声称规则一定能承受节点或 zone 故障。

用指标验证趋势,而不是用截图判断均衡

调度与分布应在时间维度上观察。一次 get pods 只是一瞬间,无法揭示 HPA 扩缩、节点替换、长期 Pending 或某个 zone 容量耗尽。Prometheus 可辅助观察不可调度 Pod、节点资源和副本数,但指标名称、标签与 kube-state-metrics 版本有关,下面查询必须以实际 exporter 暴露的指标为准。

# 代码 20:观察不可调度 Pod,指标以实际 kube-state-metrics 暴露为准
sum by (namespace, pod) (
  kube_pod_status_unschedulable{
    namespace="<命名空间>"
  }
)

指标为 1 只能说明 kube-state-metrics 观察到 Pod 不可调度,根因仍要回到 Pod 事件和调度器日志。告警中应设置持续时间,避免短暂的扩缩容 Pending 造成噪声;同时避免按 pod 直接做高基数长期告警。

# 代码 21:按节点统计应用 Pod 数量,指标以实际 exporter 暴露为准
count by (node) (
  kube_pod_info{
    namespace="<命名空间>",
    pod=~"<应用Pod正则>"
  }
)

这个查询用于趋势和人工核对,不应替代拓扑约束本身。若节点名称经常变化,可在仪表盘中进一步映射到 zone;不要把所有 Pod 标签拼进 Prometheus label,避免指标基数失控。

# 代码 22:在一次变更窗口保存调度证据
#!/usr/bin/env bash
set -euo pipefail

namespace="<命名空间>"
app_label="<应用标签>"
evidence_dir="<证据目录>"

mkdir -p "$evidence_dir"
kubectl get deployment -n "$namespace" api -o yaml > "$evidence_dir/deployment.yaml"
kubectl get pods -n "$namespace" -l "app=$app_label" -o wide > "$evidence_dir/pods.txt"
kubectl get events -n "$namespace" --sort-by=.lastTimestamp > "$evidence_dir/events.txt"
kubectl get poddisruptionbudget -n "$namespace" -o yaml > "$evidence_dir/pdb.yaml"

该脚本不修改集群,适合作为变更后证据采集。保存路径必须受控,避免把包含内部镜像、节点名和事件内容的文件放到公开仓库。若需要进一步定位调度器插件行为,应由平台团队在控制面日志和审计权限范围内处理。

回滚原则:恢复上一份经过验证的 Pod spec

亲和性、反亲和性和 topology spread 是 Pod template 的一部分,修改会触发滚动更新。回滚不能只删除一小段 YAML 而不看当前 ReplicaSet:可能已存在一部分新版本副本,且旧版本的调度规则与当前节点容量也未必仍然兼容。最稳妥的方法是使用已经验证的 Git revision 或部署系统版本进行回退。

# 代码 23:先检查可回滚版本,再执行 Deployment 回滚
kubectl rollout history -n <命名空间> deployment/api
kubectl rollout undo -n <命名空间> deployment/api --to-revision=<修订号>
kubectl rollout status -n <命名空间> deployment/api --timeout=180s
kubectl get pods -n <命名空间> -l app=<应用标签> -o wide

rollout undo 会修改工作负载,影响范围是该 Deployment 的全部副本。执行前确认 <修订号> 对应的镜像、配置和调度规则确实是已验证版本,并确认 PDB、配额和节点容量允许重新拉起副本。回滚后要检查业务接口与调度分布,而不只是 rollout status。

# 代码 24:从受控 YAML 回滚前进行差异检查
#!/usr/bin/env bash
set -euo pipefail

namespace="<命名空间>"
known_good_file="<备份目录>/api-known-good.yaml"

test -r "$known_good_file"
kubectl diff -n "$namespace" -f "$known_good_file" || true
kubectl apply -n "$namespace" -f "$known_good_file"
kubectl rollout status -n "$namespace" deployment/api --timeout=180s
kubectl get events -n "$namespace" --sort-by=.lastTimestamp

这个回滚路径适合声明式发布,但前提是 known-good 文件不含过期 Secret 引用、已删除节点标签或不再适用的镜像。若 Pending 由节点容量真实不足造成,回滚亲和性只是在恢复旧行为,不能替代扩容、节点池修复或请求值校正。

调度策略的目标不是让 YAML 看起来复杂,而是把可用性、成本、性能与可运维性之间的取舍表达清楚。每增加一个硬约束,都应回答:当一个节点、一个 zone 或一个标签池不可用时,是否仍有足够的候选节点?如果答案不明确,先补容量与演练,再把规则推到生产。更多 Kubernetes 调度与容灾实践,可以持续关注云栈社区。




上一篇:DirectX光追迎来最大更新,聚类几何帧率提升66倍显存降90%
下一篇:Intel 18A产能转向Intel 3:PC四季度暴跌超20%
您需要登录后才可以回帖 登录 | 立即注册

关闭

站长推荐上一条 /1 下一条

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-11-4 21:16 , Processed in 0.097277 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表