一、Kubernetes集群不稳定的常见表现
你有没有遇到过这种情况:明明集群资源充足,但Pod就是频繁重启,或者某些节点莫名其妙地负载飙升?这些现象往往和默认调度策略有关。比如:
- 节点资源挤兑:多个高负载Pod被调度到同一个节点,导致OOM(内存不足)
- 热点节点问题:新Pod总是往少数几个节点上堆
- 调度延迟:明明有空闲节点,Pod却卡在Pending状态
举个真实案例:某电商平台大促时,订单服务的Pod在node-1上密集部署,结果该节点CPU飙到95%,而其他节点利用率还不到30%。
二、默认调度器的工作原理
Kubernetes的默认调度器(kube-scheduler)其实是个"老实人",它主要看两个指标:
- 资源请求(Requests):比如你声明需要2核CPU,调度器就找至少有2核空闲的节点
- 默认谓词(Predicates):包括节点内存是否足够、端口是否冲突等基础检查
但问题在于,它不会主动考虑:
- 节点现有工作负载的实际情况
- Pod之间的亲和/反亲和需求
- 跨节点的资源均衡
# 典型的问题部署示例(技术栈:Kubernetes)
apiVersion: apps/v1
kind: Deployment
metadata:
name: problem-service
spec:
replicas: 5
template:
spec:
containers:
- name: nginx
image: nginx:1.25
resources:
requests:
cpu: "1" # 每个Pod要1核CPU
memory: "1Gi" # 和1G内存
limits:
memory: "2Gi"
tolerations:
- key: "disktype"
operator: "Exists" # 这个容忍度会导致Pod可能被调度到特殊节点
三、精准调度解决方案
3.1 给节点打标签定向调度
就像给快递包裹贴"易碎品"标签一样,我们可以给节点分类:
# 给SSD节点打标签
kubectl label nodes node-1 disktype=ssd
# 然后让数据库Pod只跑在这些节点上
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis-cache
spec:
template:
spec:
nodeSelector:
disktype: ssd # 关键选择器
3.2 使用反亲和性避免扎堆
就像疫情期间要保持社交距离,重要服务也应该分散部署:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values: ["payment-service"] # 支付服务必须分散
topologyKey: "kubernetes.io/hostname" # 按主机名分散
3.3 自定义调度器扩展
当默认调度器不够用时,可以自己写调度插件。比如这个Go语言示例:
// 技术栈:Kubernetes调度器扩展(Go语言)
package main
import (
"k8s.io/kubernetes/pkg/scheduler/framework"
)
type BalancePlugin struct{}
func (bp *BalancePlugin) Name() string {
return "BalancePlugin"
}
func (bp *BalancePlugin) Filter(ctx context.Context,
state *framework.CycleState,
pod *v1.Pod,
nodeInfo *framework.NodeInfo) *framework.Status {
// 检查节点现有Pod的CPU使用率
if nodeInfo.UsedCPU > nodeInfo.AllocatableCPU * 0.7 {
return framework.NewStatus(framework.Unschedulable, "节点负载过高")
}
return framework.NewStatus(framework.Success)
}
四、实战中的进阶技巧
4.1 优先级和抢占配置
就像医院急诊科优先处理危重病人,我们可以设置:
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000 # 数值越大优先级越高
description: "用于关键业务服务"
# 在Deployment中引用
spec:
priorityClassName: high-priority
4.2 基于实际负载的调度
默认调度器只看资源请求,但我们可以通过metrics-server获取真实数据:
# 安装metrics-server
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 查看节点实时负载
kubectl top nodes
4.3 调度器性能调优
在大规模集群中,可以调整这些参数:
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: default-scheduler
percentageOfNodesToScore: 50 # 检查半数节点即可
nodeResourcesBalancedAllocation: true # 开启资源均衡
五、避坑指南
别过度依赖默认值:
- 默认CPU请求是0.5核,可能不符合实际需求
- 默认没有设置反亲和规则
注意资源限制的副作用:
resources: limits: cpu: "2" # 设置太严格会导致throttling跨AZ调度要特殊处理:
topologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: DoNotSchedule
六、总结
就像交通指挥系统需要智能红绿灯一样,Kubernetes调度也需要精细化管理。关键要点:
- 重要服务必须设置反亲和性
- 利用节点标签实现分类调度
- 实时监控实际负载比静态配置更可靠
- 自定义调度器是解决复杂场景的终极方案
下次当你发现集群不稳定时,不妨先从调度策略入手检查,或许就能找到那把隐藏的钥匙。
评论