kube-scheduler
是 kubernetes 系统的核心组件之一,主要负责整个集群资源的调度功能,根据特定的调度算法和策略,将 Pod 调度到最优的工做节点上面去,从而更加合理、更加充分的利用集群的资源,这也是咱们选择使用 kubernetes 一个很是重要的理由。若是一门新的技术不能帮助企业节约成本、提供效率,我相信是很难推动的。nginx
默认状况下,kube-scheduler 提供的默认调度器可以知足咱们绝大多数的要求,咱们前面和你们接触的示例也基本上用的默认的策略,均可以保证咱们的 Pod 能够被分配到资源充足的节点上运行。可是在实际的线上项目中,可能咱们本身会比 kubernetes 更加了解咱们本身的应用,好比咱们但愿一个 Pod 只能运行在特定的几个节点上,或者这几个节点只能用来运行特定类型的应用,这就须要咱们的调度器可以可控。算法
kube-scheduler
是 kubernetes 的调度器,它的主要做用就是根据特定的调度算法和调度策略将 Pod 调度到合适的 Node 节点上去,是一个独立的二进制程序,启动以后会一直监听 API Server,获取到 PodSpec.NodeName 为空的 Pod,对每一个 Pod 都会建立一个 binding。数据库
kube-scheduler structrueapi
这个过程在咱们看来好像比较简单,但在实际的生产环境中,须要考虑的问题就有不少了:app
考虑到实际环境中的各类复杂状况,kubernetes 的调度器采用插件化的形式实现,能够方便用户进行定制或者二次开发,咱们能够自定义一个调度器并以插件形式和 kubernetes 进行集成。ide
kubernetes 调度器的源码位于 kubernetes/pkg/scheduler 中,大致的代码目录结构以下所示:(不一样的版本目录结构可能不太同样)函数
kubernetes/pkg/scheduler -- scheduler.go //调度相关的具体实现 |-- algorithm | |-- predicates //节点筛选策略 | |-- priorities //节点打分策略 |-- algorithmprovider | |-- defaults //定义默认的调度器
其中 Scheduler 建立和运行的核心程序,对应的代码在 pkg/scheduler/scheduler.go,若是要查看kube-scheduler
的入口程序,对应的代码在 cmd/kube-scheduler/scheduler.go。工具
调度主要分为如下几个部分:性能
Predicates
Priorities
Predicates
阶段首先遍历所有节点,过滤掉不知足条件的节点,属于强制性规则,这一阶段输出的全部知足要求的 Node 将被记录并做为第二阶段的输入,若是全部的节点都不知足条件,那么 Pod 将会一直处于 Pending 状态,直到有节点知足条件,在这期间调度器会不断的重试。优化
因此咱们在部署应用的时候,若是发现有 Pod 一直处于 Pending 状态,那么就是没有知足调度条件的节点,这个时候能够去检查下节点资源是否可用。
Priorities
阶段即再次对节点进行筛选,若是有多个节点都知足条件的话,那么系统会按照节点的优先级(priorites)大小对节点进行排序,最后选择优先级最高的节点来部署 Pod 应用。
下面是调度过程的简单示意图:
更详细的流程是这样的:
其中Predicates
过滤有一系列的算法可使用,咱们这里简单列举几个:
除了这些过滤算法以外,还有一些其余的算法,更多更详细的咱们能够查看源码文件:k8s.io/kubernetes/pkg/scheduler/algorithm/predicates/predicates.go。
而Priorities
优先级是由一系列键值对组成的,键是该优先级的名称,值是它的权重值,一样,咱们这里给你们列举几个具备表明性的选项:
除了这些策略以外,还有不少其余的策略,一样咱们能够查看源码文件:k8s.io/kubernetes/pkg/scheduler/algorithm/priorities/ 了解更多信息。每个优先级函数会返回一个0-10的分数,分数越高表示节点越优,同时每个函数也会对应一个表示权重的值。最终主机的得分用如下公式计算得出:
finalScoreNode = (weight1 * priorityFunc1) + (weight2 * priorityFunc2) + … + (weightn * priorityFuncn)
上面就是 kube-scheduler 默认调度的基本流程,除了使用默认的调度器以外,咱们也能够自定义调度策略。
kube-scheduler
在启动的时候能够经过 --policy-config-file
参数来指定调度策略文件,咱们能够根据咱们本身的须要来组装Predicates
和Priority
函数。选择不一样的过滤函数和优先级函数、控制优先级函数的权重、调整过滤函数的顺序都会影响调度过程。
下面是官方的 Policy 文件示例:
{ "kind" : "Policy", "apiVersion" : "v1", "predicates" : [ {"name" : "PodFitsHostPorts"}, {"name" : "PodFitsResources"}, {"name" : "NoDiskConflict"}, {"name" : "NoVolumeZoneConflict"}, {"name" : "MatchNodeSelector"}, {"name" : "HostName"} ], "priorities" : [ {"name" : "LeastRequestedPriority", "weight" : 1}, {"name" : "BalancedResourceAllocation", "weight" : 1}, {"name" : "ServiceSpreadingPriority", "weight" : 1}, {"name" : "EqualPriority", "weight" : 1} ] }
若是默认的调度器不知足要求,还能够部署自定义的调度器。而且,在整个集群中还能够同时运行多个调度器实例,经过podSpec.schedulerName
来选择使用哪个调度器(默认使用内置的调度器)。
apiVersion: v1 kind: Pod metadata: name: nginx labels: app: nginx spec: schedulerName: my-scheduler # 选择使用自定义调度器 my-scheduler containers: - name: nginx image: nginx:1.10
要开发咱们本身的调度器也是比较容易的,好比咱们这里的 my-scheduler:
phase=Pending
和schedulerName=my-scheduler
的podBinding
对象与前面所讲的调度优选策略中的优先级(Priorities)不一样,前面所讲的优先级指的是节点优先级,而咱们这里所说的优先级 pod priority 指的是 Pod 的优先级,高优先级的 Pod 会优先被调度,或者在资源不足低状况牺牲低优先级的 Pod,以便于重要的 Pod 可以获得资源部署。
要定义 Pod 优先级,就须要先定义PriorityClass
对象,该对象没有 Namespace 的限制:
apiVersion: v1 kind: PriorityClass metadata: name: high-priority value: 1000000 globalDefault: false description: "This priority class should be used for XYZ service pods only."
其中:
value
为 32 位整数的优先级,该值越大,优先级越高globalDefault
用于未配置 PriorityClassName 的 Pod,整个集群中应该只有一个PriorityClass
将其设置为 true而后经过在 Pod 的spec.priorityClassName
中指定已定义的PriorityClass
名称便可:
apiVersion: v1 kind: Pod metadata: name: nginx labels: app: nginx spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent priorityClassName: high-priority
另一个值得注意的是当节点没有足够的资源供调度器调度 Pod,致使 Pod 处于 pending 时,抢占(preemption)逻辑就会被触发。Preemption
会尝试从一个节点删除低优先级的 Pod,从而释放资源使高优先级的 Pod 获得节点资源进行部署。
如今咱们经过下面的图再去回顾下 kubernetes 的调度过程是否是就清晰不少了: