使用 kube-scheduler-simulator 模擬 K8s 調度器環(huán)境
由于默認的 Kubernetes 調度器是高度可配置的,在很多情況下我們不需要編寫任何代碼來自定義調度行為。但是,想要了解調度器如何工作或者有更多二次開發(fā)需求的人員可能會嘗試開發(fā)自己的調度器,在本文中,我將介紹如何借助 kube-scheduler-simulator 這個調度器模擬器來構建調度程序開發(fā)環(huán)境。
安裝模擬器
首先 Clone 模擬器的代碼:
$ git clone https://github.com/kubernetes-sigs/kube-scheduler-simulator
$ cd kube-scheduler-simulator
為 web 前端和模擬器服務端構建鏡像,執(zhí)行 make docker_build_and_up 命令即可:
鏡像構建完成后我們可以直接使用 docker-compose up 命令來啟動模擬器:
啟動后我們可以直接在瀏覽器中通過 localhost:3000 來訪問模擬器的 Web 頁面,如下所示:
頁面上提供了新建多種資源的方法,比如我們可以點擊 NEW NODE 按鈕來新建一些節(jié)點:
只需要點擊 APPLY 按鈕即可新增一個節(jié)點,我們這里新增了 5 個節(jié)點。然后用同樣的方式點擊 NEW POD 新建一個 Pod,就會模擬整個調度過程:
新建的 Pod 被調度到了其中一個節(jié)點上:
點擊 Pod 的名稱可以查看到該 Pod 的整個調度過程,包括 Filter 階段、Score 階段和最終打分結果。
我們可以直接點擊左上角的設置按鈕來對調度器進行配置,實際上就是修改 KubeSchedulerConfiguration 對象:
使用
我們了解了如果通過模擬器來了解 Pod 的調度,那么如果我們要開發(fā)一個新的調度器插件,那么又應該怎么結合模擬器來使用呢?
這里我們以 https://github.com/sanposhiho/mini-kube-scheduler 這個程序為例進行說明,這個調度器實現(xiàn)了隨機決定 Pod 的 Node。
要讓我們在模擬器中使用該調度器,需要執(zhí)行以下一些過程:
- 將mini-kube-scheduler/minisched (從分支 initial-random-scheduler)復制到kube-scheduler-simulator。
- 修改kube-scheduler-simulator/scheduler/scheduler.go 文件來使用minisched。
修改 kube-scheduler-simulator/scheduler/scheduler.go 文件的內容如下所示,主要看 StartScheduler 函數(shù)的修改:
package scheduler
import (
"context"
"sigs.k8s.io/kube-scheduler-simulator/simulator/minisched"
"golang.org/x/xerrors"
v1 "k8s.io/api/core/v1"
clientset "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/events"
"k8s.io/klog/v2"
v1beta2config "k8s.io/kube-scheduler/config/v1beta2"
"k8s.io/kubernetes/pkg/scheduler"
"k8s.io/kubernetes/pkg/scheduler/apis/config"
"k8s.io/kubernetes/pkg/scheduler/apis/config/scheme"
"k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2"
simulatorschedconfig "sigs.k8s.io/kube-scheduler-simulator/simulator/scheduler/config"
"sigs.k8s.io/kube-scheduler-simulator/simulator/scheduler/plugin"
)
// ......
// StartScheduler starts scheduler.
func (s *Service) StartScheduler(versionedcfg *v1beta2config.KubeSchedulerConfiguration) error {
clientSet := s.clientset
ctx, cancel := context.WithCancel(context.Background())
informerFactory := scheduler.NewInformerFactory(clientSet, 0)
evtBroadcaster := events.NewBroadcaster(&events.EventSinkImpl{
Interface: clientSet.EventsV1(),
})
evtBroadcaster.StartRecordingToSink(ctx.Done())
s.currentSchedulerCfg = versionedcfg.DeepCopy()
sched := minisched.New(
clientSet,
informerFactory,
)
informerFactory.Start(ctx.Done())
informerFactory.WaitForCacheSync(ctx.Done())
go sched.Run(ctx)
s.shutdownfn = cancel
return nil
}
// ......
將調度器改成 sched := minisched.New(clientSet informerFactory, ),也就是現(xiàn)在我們只使用 minisched 這個調度器了。
修改完成后重新編譯項目:
$ make docker_build_and_up
編譯完成后重新啟動容器:
$ docker-compose up
啟動后可以再次通過 localhost:3000 訪問模擬器,現(xiàn)在我們的模擬器中只有 minisched 這一個調度算法了,我們可以新建幾個 Pod 進行測試:
現(xiàn)在就看不到之前調度器的幾個階段了,因為我們沒有注冊:
比如我們將 minisched 調度器的調度算法從隨機選擇一個節(jié)點改成固定選擇第一個節(jié)點,修改 kube-scheduler-simulator/simulator/minisched/minisched.go 文件的 scheduleOne 函數(shù),如下所示:
同樣修改后重新編譯、重新啟動容器,然后重新訪問模擬器的 Web 頁面,現(xiàn)在我們新建的 Pod 可以發(fā)現(xiàn)始終都會調度到第一個 Node 節(jié)點去了。
現(xiàn)在我們就可以根據(jù)需求去開發(fā)自己的調度器算法了,完全不需要一個真實的 K8s 集群。