首先要做的是大致浏览下几个目录与大致的文件!!
基本的流程可以简述为:
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主从复制
- 对于工作的认识与思考