使用 kube-scheduler-simulator 模擬 K8s 調(diào)度器環(huán)境
由于默認(rèn)的 Kubernetes 調(diào)度器是高度可配置的,在很多情況下我們不需要編寫任何代碼來自定義調(diào)度行為。但是,想要了解調(diào)度器如何工作或者有更多二次開發(fā)需求的人員可能會(huì)嘗試開發(fā)自己的調(diào)度器,在本文中,我將介紹如何借助 kube-scheduler-simulator 這個(gè)調(diào)度器模擬器來構(gòu)建調(diào)度程序開發(fā)環(huán)境。
安裝模擬器
首先 Clone 模擬器的代碼:
$ git clone https://github.com/kubernetes-sigs/kube-scheduler-simulator
$ cd kube-scheduler-simulator
為 web 前端和模擬器服務(wù)端構(gòu)建鏡像,執(zhí)行 make docker_build_and_up 命令即可:
鏡像構(gòu)建完成后我們可以直接使用 docker-compose up 命令來啟動(dòng)模擬器:
啟動(dòng)后我們可以直接在瀏覽器中通過 localhost:3000 來訪問模擬器的 Web 頁面,如下所示:
頁面上提供了新建多種資源的方法,比如我們可以點(diǎn)擊 NEW NODE 按鈕來新建一些節(jié)點(diǎn):
只需要點(diǎn)擊 APPLY 按鈕即可新增一個(gè)節(jié)點(diǎn),我們這里新增了 5 個(gè)節(jié)點(diǎn)。然后用同樣的方式點(diǎn)擊 NEW POD 新建一個(gè) Pod,就會(huì)模擬整個(gè)調(diào)度過程:
新建的 Pod 被調(diào)度到了其中一個(gè)節(jié)點(diǎn)上:
點(diǎn)擊 Pod 的名稱可以查看到該 Pod 的整個(gè)調(diào)度過程,包括 Filter 階段、Score 階段和最終打分結(jié)果。
我們可以直接點(diǎn)擊左上角的設(shè)置按鈕來對(duì)調(diào)度器進(jìn)行配置,實(shí)際上就是修改 KubeSchedulerConfiguration 對(duì)象:
使用
我們了解了如果通過模擬器來了解 Pod 的調(diào)度,那么如果我們要開發(fā)一個(gè)新的調(diào)度器插件,那么又應(yīng)該怎么結(jié)合模擬器來使用呢?
這里我們以 https://github.com/sanposhiho/mini-kube-scheduler 這個(gè)程序?yàn)槔M(jìn)行說明,這個(gè)調(diào)度器實(shí)現(xiàn)了隨機(jī)決定 Pod 的 Node。
要讓我們?cè)谀M器中使用該調(diào)度器,需要執(zhí)行以下一些過程:
- 將mini-kube-scheduler/minisched (從分支 initial-random-scheduler)復(fù)制到kube-scheduler-simulator。
- 修改kube-scheduler-simulator/scheduler/scheduler.go 文件來使用minisched。
修改 kube-scheduler-simulator/scheduler/scheduler.go 文件的內(nèi)容如下所示,主要看 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
}
// ......
將調(diào)度器改成 sched := minisched.New(clientSet informerFactory, ),也就是現(xiàn)在我們只使用 minisched 這個(gè)調(diào)度器了。
修改完成后重新編譯項(xiàng)目:
$ make docker_build_and_up
編譯完成后重新啟動(dòng)容器:
$ docker-compose up
啟動(dòng)后可以再次通過 localhost:3000 訪問模擬器,現(xiàn)在我們的模擬器中只有 minisched 這一個(gè)調(diào)度算法了,我們可以新建幾個(gè) Pod 進(jìn)行測(cè)試:
現(xiàn)在就看不到之前調(diào)度器的幾個(gè)階段了,因?yàn)槲覀儧]有注冊(cè):
比如我們將 minisched 調(diào)度器的調(diào)度算法從隨機(jī)選擇一個(gè)節(jié)點(diǎn)改成固定選擇第一個(gè)節(jié)點(diǎn),修改 kube-scheduler-simulator/simulator/minisched/minisched.go 文件的 scheduleOne 函數(shù),如下所示:
同樣修改后重新編譯、重新啟動(dòng)容器,然后重新訪問模擬器的 Web 頁面,現(xiàn)在我們新建的 Pod 可以發(fā)現(xiàn)始終都會(huì)調(diào)度到第一個(gè) Node 節(jié)點(diǎn)去了。
現(xiàn)在我們就可以根據(jù)需求去開發(fā)自己的調(diào)度器算法了,完全不需要一個(gè)真實(shí)的 K8s 集群。