首先要做的是大致瀏覽下幾個目錄與大致的文件!!
基本的流程可以簡述為:
1 創建pod
2 schedulor notice到有新的pod待分配。
3 scedulor為pod分配一個node
大致的一個結構就像
~~~
while True:
pods = get_all_pods()
for pod in pods:
if pod.node == nil:
assignNode(pod)
~~~
確實整個scheduler的核心就是這個,在此基礎上的就是對于整個的實現,
根據官方文件描述:程序的main入口在schedulor.go下。
通過這個方法點擊進入,然后就被各種不認識的結構體方法愣住了(哈哈)。沒關系,我們要做的不是仔細看代碼,要做的是獲取其主要的代碼結構。
通過跳轉就到了server.go這個文件下,首先看下包注釋:~~~
Package app implements a Server object for running the scheduler.
~~~
實現一個server對象用于run scheduler。
然后大致瀏覽下方法,
~~~
~~~
// NewSchedulerCommand creates a *cobra.Command object with default parameters and registryOptions
func NewSchedulerCommand(registryOptions ...Option) *cobra.Command {
注釋寫明了創建具有默認參數的cobra對象。
~~~
接著往下
~~~
// runCommand runs the scheduler.
func runCommand(cmd *cobra.Command, opts *options.Options, registryOptions ...Option) error {
這就找到了schedulor的run函數。easy 對不對!
~~~
~~~
// Run executes the scheduler based on the given configuration. It only returns on error or when context is done.
func Run(ctx context.Context, cc *schedulerserverconfig.CompletedConfig, sched *scheduler.Scheduler) error {
在給定的配置上run scheduler。(恩,一個是runscheduler,一個是在給定的配置基礎上run scheduler。那你肯定會問點什么。)
~~~
~~~
// Setup creates a completed config and a scheduler based on the command args and options
func Setup(ctx context.Context, opts *options.Options, outOfTreeRegistryOptions ...Option) (*schedulerserverconfig.CompletedConfig, *scheduler.Scheduler, error) {
if errs := opts.Validate(); len(errs) > 0 {
接著往下:Step函數基于命令行參數與完整的配置run一個schedulor,通過注釋就可以知道,這三者的關系應該很清晰啦!
~~~
server這個文件里面主要的模塊就是這樣。不用看代碼就知道,
(如何能夠找到Run函數,或許是通過調試運行)
仔細看run函數,
~~~
// Leader election is disabled, so runCommand inline until done.
close(waitingForLeader)
sched.Run(ctx)
return fmt.Errorf("finished without leader elect")
return的是finished without leader elect。說明scheduler已經在里面run起來了,那么在哪里呢?你找找看。
找到之后,就是下面這樣,跟前面的while循環一個道理。
~~~
~~~
// Run begins watching and scheduling. It starts scheduling and blocked until the context is done.
sched.SchedulingQueue.Run()
wait.UntilWithContext(ctx, sched.scheduleOne, 0)
sched.SchedulingQueue.Close()
注釋就說的很清楚啦,大意就是跟那個while循環一樣。這里為了便于理解:放一個更早的版本。
~~~
~~~
func (sched *Scheduler) scheduleOne() {
pod := sched.config.NextPod()
// do all the scheduler stuff for `pod`
}
其他的方法暫時也看不懂,不管啦,哈哈。
可以找到scheduler的結構體定義。以及一個schelorOne。進入。
~~~
~~~
// scheduleOne does the entire scheduling workflow for a single pod. It is serialized on the scheduling algorithm's host fitting.
func (sched *Scheduler) scheduleOne(ctx context.Context)
通過注釋就可以看到,這是方法是處理整個調度器的核心流程啦。
~~~
閱讀scheduler方法,碰到這行,
~~~
scheduleResult, err := sched.Algorithm.Schedule(schedulingCycleCtx, fwk, state, pod)
~~~
點擊進去
~~~
// ScheduleAlgorithm is an interface implemented by things that know how to schedule pods
// onto machines.
// TODO: Rename this type.
type ScheduleAlgorithm interface {
Schedule(context.Context, framework.Framework, *framework.CycleState, *v1.Pod) (scheduleResult ScheduleResult, err error)
// Extenders returns a slice of extender config. This is exposed for
// testing.
Extenders() []framework.Extender
}
是一個結構,(編譯器搜索不到這個接口的方法。)
~~~
繼續往下,就能看到這個接口方法的實現
~~~
// Schedule tries to schedule the given pod to one of the nodes in the node list.
// If it succeeds, it will return the name of the node.
// If it fails, it will return a FitError error with reasons.
func (g *genericScheduler) Schedule(ctx context.Context, fwk framework.Framework, state *framework.CycleState, pod *v1.Pod)
調度器嘗試將給定的pod調度到node list的node里面
成功則返回名字,失敗則返回error信息。
~~~
~~~
feasibleNodes, filteredNodesStatuses, err :=g.findNodesThatFitPod(ctx, fwk, state, pod)
點擊方法
// Filters the nodes to find the ones that fit the pod based on the framework
// filter plugins and filter extenders.
func (g *genericScheduler) findNodesThatFitPod(ctx context.Context, fwk framework.Framework, state *framework.CycleState, pod *v1.Pod)
找到了有一個主要的方法,基于
framework filter plugins and filter extenders 去為pod篩選node,返回可行節點,這就是node篩選算法
~~~
繼續往下
~~~
priorityList, err := g.prioritizeNodes(ctx, fwk, state, pod, feasibleNodes)
查看方法注釋
// prioritizeNodes prioritizes the nodes by running the score plugins,
// which return a score for each node from the call to RunScorePlugins().
// The scores from each plugin are added together to make the score for that node, then
// any extenders are run as well.
// All scores are finally combined (added) to get the total weighted scores of all nodes
大致翻譯一下:通過score plugins為node劃分優先級,然后從RunScorePlugins方法里面為每一個node返回一個評分,待仔細翻譯
這就是node優先級算法。
~~~
我們已經找到了優先級算法,篩選算法。
(這里如何理解func (g *genericScheduler) )
點擊genericScheduler,查看到結構體,搜索哪個地方創建了這個結構體對象?
~~~
然后就能找到
// NewGenericScheduler creates a genericScheduler object.
func NewGenericScheduler(
~~~
繼續搜索,查看那個地方調用了該方法。
~~~
algo := core.NewGenericScheduler(
c.schedulerCache,
c.nodeInfoSnapshot,
extenders,
c.percentageOfNodesToScore,
)
這段代碼是在create方法中,
// create a scheduler from a set of registered plugins.
func (c *Configurator) create() (*Scheduler, error) {
從注冊的plug中創建scheduler。
繼續搜索哪些地方調用了create方法,
// createFromProvider creates a scheduler from the name of a registered algorithm provider.
func (c *Configurator) createFromProvider(providerName string) (*Scheduler, error) {
一個是createFromProvider,一個是createFromConfig
// createFromConfig creates a scheduler from the configuration file
// Only reachable when using v1alpha1 component config
func (c *Configurator) createFromConfig(policy schedulerapi.Policy) (*Scheduler, error) {
~~~
這里貌似還有一些地方沒有找到,待補充。
前面進行了一些列的準備動作,return 前面的一行sched.RUN方法。
點進去看看。
我寫這個出發點是以一個完全不依賴于實現對其有所了解的思維去寫。也即是如何以及自己的思維去閱讀這個東西。我認為這是怎么樣能夠以自己的理解去學習。
如果從一個完全陌生的角度去,我認為就是我上面這個思路,但不好意思的是明顯我也參考了別人的資料,哈哈。
核心就是,把握大致的設計思路,嘗試在代碼中找到他。然后再去理解每一個分支。不依靠其他的資料,自己去發現與探索,enjoy it。
- 文章翻譯
- Large-scale cluster management at Google with Borg
- Borg Omega and kubernetes
- scaling kubernetes to 7500 nodes
- bpf 的過去,未來與現在
- Demystifying Istio Circuit Breaking
- 知識圖譜
- skill level up graph
- 一、運維常用技能
- 1.0 Vim (編輯器)
- 1.1 Nginx & Tengine(Web服務)
- 基礎
- 1.2 zabbix
- 定義
- 登錄和配置用戶
- 1.3 RabbitMQ(消息隊列)
- 原理
- RabbitMQ(安裝)
- 1.4虛擬化技術
- KVM
- 1.5 Tomcat(Web中間件)
- 1.6Jenkins
- pipline
- 1.7 Docker
- network
- 1.8 Keepalived(負載均衡高可用)
- 1.9 Memcache(分布式緩存)
- 1.10 Zookeeper(分布式協調系統)
- 1.11 GitLab(版本控制)
- 1.12 Jenkins(運維自動化)
- 1.13 WAF(Web防火墻)
- 1.14 HAproxy負載均衡
- 1.15 NFS(文件傳輸)
- 1.16 Vim(編輯器)
- 1.17 Cobbler(自動化部署)
- 二、常用數據庫
- 2.1 MySQL(關系型數據庫)
- mysql主從復制
- 2.2 Mongodb(數據分析)
- 2.3 Redis(非關系數據庫)
- 三、自動化運維工具
- 3.1 Cobbler(系統自動化部署)
- 3.2 Ansible(自動化部署)
- 3.3 Puppet(自動化部署)
- 3.4 SaltStack(自動化運維)
- 四、存儲
- 4.1 GFS(文件型存儲)
- 4.2 Ceph(后端存儲)
- 五、運維監控工具
- 5.1 云鏡
- 5.2 ELK
- 六、運維云平臺
- 6.1 Kubernetes
- 6.2 OpenStack
- 介紹
- 安裝
- 七、Devops運維
- 7.1 理念
- 7.2 Devops運維實戰
- 八、編程語言
- 8.1 Shell
- 書籍《Wicked Cool Shell Scripts》
- 8.2 Python
- 8.3 C
- 8.4 Java
- leecode算法與數據結構
- 九、雜記
- 高優先級技能
- 知識點
- JD搜集
- 明顯的短板
- 1.0 Python
- 1.1 Kubernetes
- 1.18.2 《kubernetes in action》
- 遺漏知識點
- 1.18.3 GCP、azure、aliyun
- Azure文檔
- 1.18.5 《program with kubernetes》
- Istio
- HELM
- 《Kubernetes best practice》
- Kubernetes源碼學習
- Scheduler源碼
- 調度器入口
- 調度器框架
- Node篩選算法
- Node優先級算法
- pod搶占調度
- 入口
- 主要代碼結構
- new
- 文章翻譯
- Flannel
- 從二進制集群搭建
- 信息收集
- docker優化
- 1.2 shell
- 面試題
- grep awk sed 常見用法
- shell實踐
- 1.3 Data structure(數據結構)
- Calico
- Aliyun文檔以及重點模塊
- git
- 大數據組件
- 前端,后端,web框架
- cgroup,namespace
- 內核
- Linux搜集
- crontab
- centos7常用優化配置
- centos Mariadb
- eBPF
- ebpf的前世今生
- Linux性能問題排查與分析
- 性能分析搜集
- 性能分析常用10條
- 網絡性能優化
- 文本處理命令
- sql
- Iptables
- python面試題
- iptables
- iptables詳細
- zabbix面試題,proj
- prometheus
- web中間件
- nginx
- Haproxy
- grep sed awk
- Linux常用命令
- 云平臺
- 書籍Linux應用技巧
- kafka
- kafka面試題
- ETCD
- Jenkins
- 3天補充的點
- K8s源碼
- K8s
- k8s實操
- etcd
- test
- BPF
- PSFTP使用
- StackOverflow問答精選
- 問題
- 我對于學習思考
- 修改ssh超時時間
- 課程目錄
- 運維與運維開發
- The Person
- 個人雜談
- mysql主從復制
- 對于工作的認識與思考