Google Kubernetes Engine集群无法自动缩容:配置PodDisruptionBudget后仍出现kube-system Pod不可移动日志报错
从你给出的Autoscaler日志报错 no.scale.down.node.pod.kube.system.unmovable 来看,核心问题很明确:你的kube-dns Pod被标记为不可移动,所以集群没法缩容它所在的节点——哪怕你配置了PDB也没用。别着急,咱们一步步拆解问题,找出解决办法:
一、先搞懂报错到底啥意思
这个报错说明Cluster Autoscaler觉得 kube-dns-b4f5c58c7-26xdm 这个Pod不能被安全驱逐,所以绝不会动它所在的节点。这里要澄清一个误区:
- PDB是用来控制Pod驱逐时的可用性,但它不能强迫Autoscaler认为Pod是可迁移的——Autoscaler自身还有一堆额外检查条件。
- kube-system命名空间下的系统Pod,Autoscaler默认会特殊对待,很多带
Critical优先级或者绑定了特定节点的Pod,根本不允许被驱逐。
二、一步步排查不可移动的原因
1. 检查kube-dns Pod的关键配置
先看看这个Pod的详细信息,重点盯这几个点:
kubectl describe pod kube-dns-b4f5c58c7-26xdm -n kube-system
- 优先级类(Priority Class):如果Pod用了
system-cluster-critical或者system-node-critical优先级,Autoscaler默认不会碰这类Pod(除非你手动开权限)。 - 节点亲和性/选择器:如果Pod绑定了特定节点标签(比如
node-role.kubernetes.io/master或者你自定义的标签),Autoscaler没法把它移到别的节点,自然不会缩容当前节点。 - 污点容忍(Tolerations):如果Pod依赖某个节点的污点,而集群里其他节点没有这个污点,那它也没法迁移过去。
2. 确认你的PDB真的匹配这个Pod
你的PDB用了matchLabels: k8s-app: kube-dns作为选择器,得先确认目标Pod确实带这个标签:
kubectl get pod kube-dns-b4f5c58c7-26xdm -n kube-system --show-labels
要是Pod的标签和PDB的选择器对不上,那PDB相当于没生效,Autoscaler该认为Pod不可移动还是会那么认为。
3. 检查Cluster Autoscaler对kube-system Pod的限制
GKE里的Cluster Autoscaler默认对kube-system下的Pod管得很严,你得看看它的配置是不是允许驱逐这类Pod:
- 对于1.19版本的GKE,默认参数是
--skip-nodes-with-system-pods=true,意思就是有系统Pod的节点不能缩容。你得把这个参数改成false才行。 - 就算开了这个参数,Autoscaler也只会驱逐那些能安全迁移的系统Pod——比如有Deployment/StatefulSet管着,PDB允许驱逐,而且没绑定特定节点。
三、对应的解决方案
1. 先把PDB和Pod的匹配问题解决
如果发现Pod标签和PDB选择器不匹配,要么修改PDB的selector,要么给Pod补上对应的标签,确保PDB能覆盖到这个kube-dns Pod。
2. 调整Autoscaler的kube-system Pod驱逐策略
在GKE里改这个配置有两种方式:
- 控制台操作:进入集群的「节点」→「节点池」,选你要调整的节点池,编辑Autoscaler设置,找到「允许节点池缩容即使包含系统Pod」这个选项,把它打开。
- 命令行操作:用gcloud命令更新集群配置:
gcloud container clusters update 你的集群名 --zone 你的集群区域 --enable-autoscaling --min-nodes=最小节点数 --max-nodes=最大节点数 --skip-nodes-with-system-pods=false
注意:开了这个选项后,Autoscaler才会尝试驱逐kube-system Pod,但前提是这些Pod真的能被安全迁移(比如有足够的副本,PDB允许)。
3. 检查kube-dns的Deployment配置
确保kube-dns的Deployment没有限制迁移的设置:
kubectl describe deployment kube-dns -n kube-system
- 确认
spec.replicas大于1,这样你的PDBmaxUnavailable:1才能发挥作用(要是只有1个副本,驱逐了就没了,Autoscaler肯定不敢动)。 - 看看有没有
nodeSelector或者affinity把Pod绑死在特定节点上,如果有,要么移除这些限制,要么确保其他节点也满足这些条件。
4. 手动验证Pod能不能被驱逐
你可以手动试试驱逐这个Pod,看能不能成功,这能直接告诉你问题出在哪:
kubectl drain 节点名 --ignore-daemonsets --delete-local-data
如果驱逐失败,报错信息会明明白白告诉你原因——比如副本数不够,或者Pod用了本地存储没法迁移之类的。
总结
你的问题大概率逃不开这几个原因:
- Cluster Autoscaler默认不让缩容带系统Pod的节点;
- PDB和kube-dns Pod的标签不匹配,导致PDB没生效;
- kube-dns Pod有优先级、节点绑定等限制,没法被迁移。
按上面的步骤挨个排查,应该就能解决自动缩容的问题了。
内容的提问来源于stack exchange,提问作者Eric Gumba

