Kubernetes调度原理与实践:从基础到高级策略
1. 当Kubernetes调度遇上"挖呀挖":一场集群资源的精准耕作
在Kubernetes集群管理的世界里,资源调度就像在数字花园中耕作——你需要知道在哪里播种(调度Pod)、如何施肥(分配资源)、何时修剪(驱逐低优先级任务)。最近爆火的"挖呀挖"儿歌,意外地成为了我们团队内部形容kube-scheduler工作原理的暗号。每当有同事抱怨"Pod为什么卡在Pending状态"时,总会有人哼起"在k8s调度的花园里面挖呀挖呀挖,用合适的Node种小小的Pod..."
2. 调度器工作原理深度解析
2.1 调度流水线四步走
典型的kube-scheduler工作流程就像园丁的日常工作清单:
- 过滤阶段(Filtering):用NodeAffinity、Taints/Tolerations等条件筛掉不符合要求的节点,相当于先排除石头地、盐碱地等不适合耕种的土地
- 打分阶段(Scoring):对剩余节点按资源余量、均衡性等指标评分,就像评估哪块地光照更充足、土壤更肥沃
- 绑定阶段(Binding):将Pod与最佳Node绑定,完成"播种"动作
- 抢占阶段(Preemption):当高优先级Pod需要资源时,会优雅终止低优先级Pod(相当于间苗)
实战技巧:通过
kubectl describe pod <pod-name>查看Events字段,能清晰观察到调度器决策过程
2.2 调度策略配置实战
这是我们在生产环境使用的调度策略配置片段:
apiVersion: kubescheduler.config.k8s.io/v1beta3 kind: KubeSchedulerConfiguration profiles: - schedulerName: default-scheduler plugins: score: enabled: - name: NodeResourcesBalancedAllocation weight: 2 - name: NodeAffinity weight: 1这个配置特别强调了资源分配的均衡性(权重2),确保不会出现某些节点过载而其他节点闲置的情况,就像均匀分布不同作物的种植密度。
3. 高级调度模式详解
3.1 拓扑分布约束(Topology Spread Constraints)
当我们需要将Pod像作物一样均匀分布在不同可用区时:
spec: topologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: app: nginx这个配置确保每个可用区的nginx Pod数量差异不超过1,相当于在花园的每个区域均匀种植同种花卉。
3.2 资源配额与限制实践
我们曾经遇到过因为未设置资源限制导致节点过载的惨痛教训。现在团队强制要求所有Pod必须声明requests和limits:
resources: requests: cpu: "500m" memory: "512Mi" limits: cpu: "1000m" memory: "1Gi"这就像明确规定每株作物需要的水量范围——太少会枯萎,太多会浪费。
4. 常见调度问题排查指南
4.1 Pod卡在Pending状态的7个原因
我们整理了排错检查清单:
| 症状表现 | 可能原因 | 检查命令 |
|---|---|---|
| 0/1 nodes available | 资源不足 | kubectl describe node |
| didn't have free ports | 端口冲突 | kubectl get endpoints |
| node(s) didn't match constraints | 节点选择器错误 | kubectl get pod -o yaml |
4.2 调度性能优化
当集群规模超过500节点时,我们采用了以下优化措施:
- 启用调度器缓存(默认开启)
- 设置
percentageOfNodesToScore: 50%(大型集群可降低此值) - 使用多个调度器分片
5. 自定义调度器开发入门
5.1 实现基本调度框架
这是一个Go语言调度器的最小实现:
func main() { clientset := createClient() informerFactory := informers.NewSharedInformerFactory(clientset, 0) scheduler := NewScheduler( clientset, informerFactory.Core().V1().Nodes(), informerFactory.Core().V1().Pods(), ) informerFactory.Start(wait.NeverStop) scheduler.Run() }5.2 调度算法扩展点
可以覆盖的决策点包括:
- PreFilter:前置检查
- Filter:节点过滤
- PostFilter:抢占逻辑
- Score:节点评分
- Reserve:资源预留
我们团队基于这些扩展点开发了考虑GPU碎片化的定制调度器,将GPU利用率提升了40%。
6. 多集群调度实践
6.1 Cluster API集成
使用Cluster API管理多集群调度时,关键配置包括:
apiVersion: cluster.x-k8s.io/v1beta1 kind: Cluster metadata: name: prod-cluster spec: topology: workers: machineDeployments: - class: worker-medium replicas: 56.2 联邦调度策略
跨集群部署应用时,我们使用如下分布策略:
placement: clusterAffinity: clusterNames: - cluster-1 - cluster-2 spreadConstraints: - maxGroups: 2 minReplicas: 1这相当于在不同花园区域种植相同作物,确保灾害时的冗余性。
在经历了无数次"挖呀挖"的调试过程后,我们总结出Kubernetes调度的黄金法则:明确的资源请求、合理的分布策略、持续的性能监控。当你在调度花园里"挖"得越深,就越能体会到这个系统的精妙设计——它就像最智能的自动灌溉系统,让每个Pod都能在最适合的节点上茁壮成长。