当前位置: 首页 > news >正文

使用 Kubernetes Scheduler Framework 插件机制实现 Filter 插件的最小可运行 Demo

使用 Kubernetes Scheduler Framework 插件机制实现 Filter 插件的最小可运行 Demo

本文介绍如何基于 Kubernetes v1.27.0 的 Go SDK(k8s.io/kubernetes),使用 Kubernetes Scheduler Framework 插件机制实现一个最小的 Filter 插件 Demo。该 Demo 展示了一个简单的 Filter 插件,用于过滤不符合特定条件的节点,并将其集成到 Kubernetes 调度器中。文章还包括解决依赖问题的详细步骤,以确保项目在 v1.27.0 环境下正常运行。

前提条件

  • Go 环境(建议 1.18 或以上)
  • Kubernetes 集群(可使用 Minikube 或 Kind 搭建 v1.27.0 环境)
  • k8s.io/kubernetes v1.27.0 SDK
  • 熟悉 Kubernetes 调度器和 Scheduler Framework 基本概念

背景知识

Kubernetes Scheduler Framework 是一个可扩展的框架,允许开发者通过插件机制自定义调度逻辑。Filter 插件是调度过程中的核心组件,用于过滤不满足 Pod 调度需求的节点。本 Demo 实现一个简单的 Filter 插件,检查节点是否包含标签 scheduler.custom/enabled: true,只有满足条件的节点才会被保留。

实现步骤

以下是实现最小可运行 Filter 插件 Demo 的详细步骤,包括代码实现、依赖管理和部署。

1. 项目结构

创建以下项目结构:

custom-scheduler/
├── main.go
├── pkg/
│   └── plugins/
│       └── filter/
│           └── custom_filter.go
├── go.mod
├── scheduler-config.yaml
└── Dockerfile

2. 初始化 Go 模块

在项目根目录下初始化 Go 模块并添加依赖:

go mod init custom-scheduler
go get k8s.io/kubernetes@v1.27.0
go get k8s.io/component-base@v0.27.0
go get k8s.io/klog/v2@v2.100.1
解决依赖问题

在 v1.27.0 中,运行 go mod tidy 可能会遇到模块解析错误,例如 k8s.io/cloud-providerk8s.io/csi-translation-libk8s.io/mount-utils 被解析为无效的 v0.0.0 版本。为解决此问题,编辑 go.mod 文件,明确指定所有相关模块的版本,并使用 replace 指令确保一致性:

module custom-schedulergo 1.18require (k8s.io/api v0.27.0k8s.io/apimachinery v0.27.0k8s.io/client-go v0.27.0k8s.io/component-base v0.27.0k8s.io/klog/v2 v2.100.1k8s.io/kubernetes v1.27.0
)replace (k8s.io/api => k8s.io/api v0.27.0k8s.io/apimachinery => k8s.io/apimachinery v0.27.0k8s.io/client-go => k8s.io/client-go v0.27.0k8s.io/cloud-provider => k8s.io/cloud-provider v0.27.0k8s.io/component-base => k8s.io/component-base v0.27.0k8s.io/component-helpers => k8s.io/component-helpers v0.27.0k8s.io/controller-manager => k8s.io/controller-manager v0.27.0k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.27.0k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.27.0k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.27.0k8s.io/kubelet => k8s.io/kubelet v0.27.0k8s.io/mount-utils => k8s.io/mount-utils v0.27.0
)

运行以下命令整理依赖并生成 vendor 目录:

go clean -modcache
go mod tidy
go mod vendor

如果仍然报错,尝试切换模块代理:

export GOPROXY=https://proxy.golang.org,direct
go mod tidy
go mod vendor

使用 vendor 模式构建以绕过在线模块解析:

go build -mod=vendor -o custom-scheduler .
禁用默认插件(可选)

某些默认插件(如 NodeVolumeLimitsVolumeZone)可能引入不必要的依赖(如 k8s.io/cloud-provider)。为最小化依赖,可以在调度器配置文件中禁用所有默认插件,仅启用自定义插件(见步骤 5)。

3. 实现 Filter 插件

pkg/plugins/filter/custom_filter.go 中实现自定义 Filter 插件,检查节点标签:

package filterimport ("context""k8s.io/apimachinery/pkg/runtime"v1 "k8s.io/api/core/v1"framework "k8s.io/kubernetes/pkg/scheduler/framework""k8s.io/klog/v2"
)type CustomFilterPlugin struct{}var _ framework.FilterPlugin = &CustomFilterPlugin{}func (pl *CustomFilterPlugin) Name() string {return "CustomFilter"
}func (pl *CustomFilterPlugin) Filter(ctx context.Context,state *framework.CycleState,pod *v1.Pod,nodeInfo *framework.NodeInfo,
) *framework.Status {labels := nodeInfo.Node().GetLabels()if labels["scheduler.custom/enabled"] != "true" {klog.Infof("Node %s filtered out: missing label scheduler.custom/enabled=true", nodeInfo.Node().Name)return framework.NewStatus(framework.Unschedulable, "missing required label")}klog.Infof("Node %s passed custom filter", nodeInfo.Node().Name)return nil
}func New(_ runtime.Object, handle framework.Handle) (framework.Plugin, error) {return &CustomFilterPlugin{}, nil
}

4. 实现主程序

main.go 中注册插件并启动调度器:

package mainimport ("context""custom-scheduler/pkg/plugins/filter""k8s.io/component-base/logs""k8s.io/kubernetes/cmd/kube-scheduler/app""k8s.io/klog/v2"
)func main() {logs.InitLogs()defer logs.FlushLogs()command := app.NewSchedulerCommand(app.WithPlugin("CustomFilter", filter.New),)if err := command.ExecuteContext(context.Background()); err != nil {klog.Fatal(err)}
}

5. 配置调度器

创建调度器配置文件 scheduler-config.yaml,启用自定义插件并禁用默认插件以最小化依赖:

apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
profiles:- schedulerName: custom-schedulerplugins:filter:enabled:- name: CustomFilterdisabled:- name: "*"preFilter:disabled:- name: "*"score:disabled:- name: "*"bind:disabled:- name: "*"

注意:禁用所有默认插件可减少依赖,但可能影响完整调度流程(如 Pod 绑定)。如需完整功能,可启用必要的默认插件(如 DefaultBinder),并检查是否引入新依赖。

6. 编译与部署

编译程序

使用 vendor 模式编译:

go build -mod=vendor -o custom-scheduler .
创建 Docker 镜像

创建 Dockerfile

FROM golang:1.18
WORKDIR /app
COPY . .
RUN go build -mod=vendor -o custom-scheduler .
CMD ["/app/custom-scheduler"]

构建镜像:

docker build -t custom-scheduler:latest .
部署调度器

创建 scheduler-deployment.yaml

apiVersion: v1
kind: ConfigMap
metadata:name: custom-scheduler-confignamespace: kube-system
data:scheduler-config.yaml: |apiVersion: kubescheduler.config.k8s.io/v1beta2kind: KubeSchedulerConfigurationprofiles:- schedulerName: custom-schedulerplugins:filter:enabled:- name: CustomFilterdisabled:- name: "*"preFilter:disabled:- name: "*"score:disabled:- name: "*"bind:disabled:- name: "*"
---
apiVersion: apps/v1
kind: Deployment
metadata:name: custom-schedulernamespace: kube-systemlabels:app: custom-scheduler
spec:replicas: 1selector:matchLabels:app: custom-schedulertemplate:metadata:labels:app: custom-schedulerspec:containers:- name: custom-schedulerimage: custom-scheduler:latestargs:- --config=/etc/scheduler/scheduler-config.yamlvolumeMounts:- name: configmountPath: /etc/schedulervolumes:- name: configconfigMap:name: custom-scheduler-config

应用部署:

kubectl apply -f scheduler-deployment.yaml
为节点添加标签

为测试节点添加标签:

kubectl label nodes <node-name> scheduler.custom/enabled=true
创建测试 Pod

创建 test-pod.yaml

apiVersion: v1
kind: Pod
metadata:name: test-pod
spec:schedulerName: custom-schedulercontainers:- name: nginximage: nginx

应用 Pod:

kubectl apply -f test-pod.yaml

7. 验证

检查 Pod 是否调度到带有 scheduler.custom/enabled=true 标签的节点:

kubectl get pods -o wide

查看调度器日志:

kubectl logs -n kube-system -l app=custom-scheduler

如果节点没有所需标签,Pod 将保持 Pending 状态,日志会显示过滤原因。

8. 常见问题与解决方案

依赖解析错误

如果运行 go mod tidy 报错(如 404 Not Found),尝试以下解决方案:

  • 切换模块代理
export GOPROXY=https://proxy.golang.org,direct
go mod tidy
go mod vendor
  • 使用 v1.27.3:如果 v1.27.0 模块发布有问题,修改 go.mod 使用 k8s.io/kubernetes@v1.27.3 和对应的 v0.27.3 版本。
  • 克隆 Kubernetes 源码:作为最后手段,克隆 Kubernetes v1.27.0 源码并在源码树中开发:
git clone -b v1.27.0 https://github.com/kubernetes/kubernetes
调度器功能不完整

禁用所有默认插件可能导致 Pod 无法绑定到节点。如需完整调度流程,在 scheduler-config.yaml 中启用必要插件(如 DefaultBinder):

plugins:bind:enabled:- name: DefaultBinder

总结

通过以上步骤,我们基于 Kubernetes v1.27.0 SDK 实现并部署了一个简单的 Filter 插件 Demo。该插件通过检查节点标签实现自定义过滤逻辑,并成功集成到 Kubernetes 调度器中。依赖管理是实现过程中的关键挑战,通过明确指定版本、使用 vendor 模式和禁用默认插件,我们成功解决了模块解析问题。

相关文章:

  • SparseDrive---论文阅读
  • 【HDFS入门】数据存储原理全解,从分块到复制的完整流程剖析
  • 线程安全学习
  • Python项目--基于Python的自然语言处理文本摘要系统
  • C++面试考点:类(class)
  • 【开源项目】Excel手撕AI算法深入理解(四):AlphaFold、Autoencoder
  • MySQL 锁机制全景图:分类、粒度与示例一图掌握
  • 每天记录一道Java面试题---day39
  • Web自动化测试的详细流程和步骤
  • shell编程正则表达式与文本处理器
  • 显示模组Bonding IC气泡问题
  • bert项目解析
  • uniapp实现图文聊天功能
  • java-spring笔记
  • HackMyVM Gigachad.
  • 《MySQL基础:了解MySQL周边概念》
  • MySQL 慢查询日志深入分析与工具实战(mysqldumpslow pt-query-digest)
  • 分层式设备控制架构、分布式微服务架构及插件化架构
  • 加密软件:数字时代的隐私守护者
  • 再论火车实验-8
  • 做app网站的软件有哪些内容吗/网络推广公司企业
  • wordpress 加载速度优化/什么是seo营销
  • 选择邯郸网站制作/搜索引擎优化关键词
  • 英孚做测试的网站/今日热点新闻事件及评论
  • 长春网站建设有什么/域名注册新网
  • 网站开发岗位思维导图/东莞网站设计公司排名