这是一个专为初学者设计的Kubernetes调度插件练手项目。通过这个项目,你将学会:
- Kubernetes调度框架的基本概念
- 如何创建自定义调度插件
- 插件的编译、部署和测试流程
- 调度插件的调试和日志分析
scheduler-plugins/
├── pkg/helloscheduler/ # 插件源代码
│ ├── hello_scheduler.go # 主要插件实现
│ └── README.md # 插件说明文档
├── manifests/helloscheduler/ # 配置和测试文件
│ ├── scheduler-config.yaml # 调度器配置
│ └── test-pod.yaml # 测试Pod定义
├── cmd/scheduler/main.go # 调度器主程序(已修改)
└── HelloScheduler开发指南.md # 本文档
- Go 1.19+
- Kubernetes集群(可以是minikube、kind或真实集群)
- kubectl工具
- Docker(用于构建镜像)
# 检查Go版本
go version
# 检查Kubernetes集群
kubectl cluster-info
# 检查节点状态
kubectl get nodesHelloScheduler插件实现了framework.ScorePlugin接口,主要包含以下方法:
Name(): 返回插件名称Score(): 为节点计算分数ScoreExtensions(): 返回分数扩展接口NormalizeScore(): 标准化分数到框架要求的范围New(): 插件初始化函数
插件使用两个因子计算分数:
- 节点名称分数:基于节点名称首字母
- 资源分数:基于CPU和内存使用率
// Score方法是核心评分逻辑
func (hs *HelloScheduler) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) (int64, *framework.Status) {
// 获取节点名称
nodeName := nodeInfo.Node().Name
// 计算名称分数
score := int64(150 - nodeName[0])
// 计算资源分数
cpuUsageRatio := float64(requested.MilliCPU) / float64(allocatable.MilliCPU)
memUsageRatio := float64(requested.Memory) / float64(allocatable.Memory)
resourceScore := int64((2.0 - cpuUsageRatio - memUsageRatio) * 50)
return score + resourceScore, nil
}# 进入项目根目录
cd /Users/tal/cursor/scheduler-plugins
# 编译调度器二进制文件
make build
# 或者手动编译
go build -o bin/kube-scheduler cmd/scheduler/main.go# 构建镜像
make image
# 或者手动构建
docker build -t hello-scheduler:latest .首先修改调度器配置文件中的kubeconfig路径:
# 获取你的kubeconfig路径
echo $KUBECONFIG
# 或者
ls ~/.kube/config
# 编辑配置文件,替换REPLACE_ME_WITH_KUBE_CONFIG_PATH
vi manifests/helloscheduler/scheduler-config.yaml示例配置:
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
leaderElection:
leaderElect: false
clientConnection:
kubeconfig: "/Users/tal/.kube/config" # 替换为你的实际路径
profiles:
- schedulerName: hello-scheduler
plugins:
score:
enabled:
- name: HelloScheduler
weight: 100# 方式1:直接运行二进制文件
./bin/kube-scheduler --config=manifests/helloscheduler/scheduler-config.yaml --v=2
# 方式2:使用go run
go run cmd/scheduler/main.go --config=manifests/helloscheduler/scheduler-config.yaml --v=2打开新的终端窗口:
# 部署测试Pod
kubectl apply -f manifests/helloscheduler/test-pod.yaml
# 查看Pod状态
kubectl get pods -l app=hello-test
# 查看Pod调度到哪个节点
kubectl get pods -l app=hello-test -o wide
# 查看Pod事件
kubectl describe pod test-pod-1在运行调度器的终端中,你应该能看到类似这样的日志:
I1201 10:30:15.123456 1 hello_scheduler.go:45] HelloScheduler正在计算分数 pod=default/test-pod-1 node=node1
I1201 10:30:15.123456 1 hello_scheduler.go:65] HelloScheduler计算完成 node=node1 nameScore=85 resourceScore=75 finalScore=160 cpuUsage=15.50% memUsage=12.30%
# 使用更详细的日志级别
./bin/kube-scheduler --config=manifests/helloscheduler/scheduler-config.yaml --v=5# 查看Pod分布
kubectl get pods -o wide
# 查看节点资源使用情况
kubectl top nodes
# 查看Pod资源请求
kubectl describe nodes问题1:Pod一直处于Pending状态
# 检查Pod事件
kubectl describe pod <pod-name>
# 检查调度器是否运行
ps aux | grep kube-scheduler
# 检查调度器日志
# 在调度器终端查看错误信息问题2:找不到hello-scheduler
# 确认调度器名称配置正确
grep schedulerName manifests/helloscheduler/test-pod.yaml
grep schedulerName manifests/helloscheduler/scheduler-config.yaml问题3:编译错误
# 检查Go模块
go mod tidy
# 检查依赖
go mod verify# 创建多个Pod测试
for i in {1..10}; do
kubectl run test-pod-$i --image=nginx --restart=Never --scheduler-name=hello-scheduler
done
# 观察调度分布
kubectl get pods -o wide | grep test-pod你可以修改pkg/helloscheduler/hello_scheduler.go中的评分逻辑:
// 示例:优先调度到CPU使用率低的节点
func (hs *HelloScheduler) Score(...) (int64, *framework.Status) {
// 修改这里的逻辑
cpuScore := int64((1.0 - cpuUsageRatio) * 100)
return cpuScore, nil
}重新编译和测试:
# 重新编译
make build
# 重启调度器
./bin/kube-scheduler --config=manifests/helloscheduler/scheduler-config.yaml --v=2apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-scheduler
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: hello-scheduler
template:
metadata:
labels:
app: hello-scheduler
spec:
serviceAccountName: system:kube-scheduler
containers:
- name: kube-scheduler
image: hello-scheduler:latest
command:
- /usr/local/bin/kube-scheduler
- --config=/etc/kubernetes/scheduler-config.yaml
- --v=2
volumeMounts:
- name: config
mountPath: /etc/kubernetes
volumes:
- name: config
configMap:
name: hello-scheduler-configapiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: hello-scheduler
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:kube-scheduler
subjects:
- kind: ServiceAccount
name: hello-scheduler
namespace: kube-system尝试实现其他调度接口:
FilterPlugin: 过滤不合适的节点PreFilterPlugin: 预过滤PostFilterPlugin: 后过滤PermitPlugin: 许可控制
# 删除测试Pod
kubectl delete -f manifests/helloscheduler/test-pod.yaml
# 停止调度器(Ctrl+C)
# 删除生成的二进制文件
rm -f bin/kube-scheduler
# 清理Docker镜像(如果构建了)
docker rmi hello-scheduler:latest通过这个HelloScheduler项目,你应该已经掌握了:
- ✅ Kubernetes调度插件的基本结构
- ✅ 插件接口的实现方法
- ✅ 调度器的编译和运行
- ✅ 调度结果的观察和调试
- ✅ 自定义评分策略的实现
这个基础项目可以作为你开发更复杂调度插件的起点。建议接下来尝试:
- 实现Filter插件进行节点过滤
- 添加插件配置参数
- 集成外部数据源进行调度决策
- 实现多调度器协作
恭喜你完成了第一个Kubernetes调度插件的开发!🎉