一、概述
kube-scheduler作为 K8s 集群的默认调度器,它监听(watch机制)kube-apiserver,查询还未调度的 pod,根据调度策略将 pod 调度至集群内最适合的Node。
二、调度流程
首先我们通过 API 或者 kubectl 工具创建 pod,kube-apiserver 收到请求信息存储到 etcd 中,调度器通过 watch 机制监听 apiserver 查看到还未被调度的 pod 列表,循环遍历的为每个 pod 尝试分配 node,这个分配过程如下:
- kube-scheduler 内 Informer 组件 list-watch apiserver,使用spec.nodeName=""筛选出还未调度的 Pod
- 预选(predicate):调度器通过 Predicate 算法过滤掉不满足条件的节点
- 优选(priorlty):对于通过预选的节点,通过打分机制,筛选出得分最高的node
- 当调度器为 Pod 选择了一个合适的节点后,将 Pod 和节点进行绑定(将节点名称赋值给 pod 的 spec.nodeName 字段)
注意 :Pod.spec.nodeName 用于强制约束将 Pod 调度到指定的 Node上,通过指定 nodeName 可直接绕过调度器,并不会做任何的资源过滤和检查。
三、kuble-scheduler 调度原理
Kube-scheduler 的调度框架,在 Kubernetes 里面叫作 Scheduler Framework。Pod 在调度过程中,都需要依次经过以下的各个阶段,每个阶段自带调度算法,调度算法由插件提供,也可以在指定阶段开发自己的插件。每个插件可以在指定阶段实现具体的调度算法,比如 NodeAffinity 插件在 Filter 阶段过滤掉与 Pod 不亲和的节点。
- PreFilter: 预处理 Pod 的相关信息,或者检查集群或 Pod 必须满足的某些条件。如果 PreFilter 插件返回错误,则调度周期将终止
- Filter: 过滤出不能运行该 Pod 的节点。对于每个节点,调度器将按照其配置顺序调用这些过滤插件。如果任何过滤插件将节点标记为不可行,则节点直接排除,不会为该节点调用剩下的过滤插件
- PostFilter: 在 Filter 阶段后调用,但仅在该 Pod 没有可行的节点时调用。典型的后筛选实现是抢占,试图通过抢占其他 Pod 的资源使该 Pod 可以调度
- PreScore: 运行评分任务以生成可评分插件的共享状态,如果 PreScore 插件返回错误,则调度周期将终止
- Score: 通过调用每个评分插件对可调度节点评分
- NormalizeScore: 规范每个插件的打分在[0,100]之间
- Reserve: 在绑定周期之前选择保留的节点
- Permit: 批准或拒绝 pod 调度周期的结果
- PreBind: 用于执行 Pod 绑定前所需的任何工作。例如,一个预绑定插件可能需要提供网络卷并且在允许 Pod 运行在该节点之前 将其挂载到目标节点上
- Bind: 用于将 Pod 绑定到节点上。直到所有的 PreBind 插件都完成,Bind 插件才会被调用
- PostBind: 这是个信息性的扩展点。绑定后插件在 Pod 成功绑定后被调用。这是绑定周期的结尾,可用于清理相关的资源
调度器预选阶段对应filter,主要用于过滤不满足 Pod 调度条件的节点;优选阶段对应 score,主要用于为每个节点打分,节点分数=插件打分*插件权重;然后排序选出分数最高的节点。
|--------|--------------------------------|---------------------------------------------------------------------------------------------| | 调度阶段 | 实现插件名称 | 插件功能介绍 | | filter | PodTopologySpread | 判断节点是否满足 Pod 的拓扑分布,不满足则过滤该节点 | | filter | InterPodAffinity | 判断节点是否满足 Pod 的亲和性配置,不满足则过滤该节点 | | filter | NodePorts | 判断节点是否满足 Pod 的端口申请,不满足则过滤该节点 | | filter | NodeAffinity | 判断节点是否满足 Pod 的节点亲和性配置,不满足则过滤该节点 | | filter | VolumeBinding | 判断节点是否满足 pv 的节点亲和性,并且将满足动态创建 pvc 条件(比如拓扑)的节点保存起来,以便后续阶段使用 | | filter | TaintToleration | 根据 Pod 容忍和节点污点的 NoSchedule 和 NoExecute过滤节点 | | Score | NodeAffinity | 根据插件权重算出得分,再根据策略权重比例算出节点分数,分数区间0~100,权重默认2 | | Score | NodeResourcesBalancedAllocatio | 根据不同resource(cpu、mem、volume)对节点容量的占比再加上对应 resource 的权重得到分数,分数区间0~100,权重默认1 | | Score | ImageLocality | 根据 Pod 中镜像大小以及镜像在所有节点上的分布来打分,分数区间0~100,权重默认1 | | Score | InterPodAffinity | 根据插件权重算出得分,再根据策略权重比例算出节点分数,分数区间0~100,权重默认2 | | Score | TaintToleration | 根据PreferNoSchedule策略算出分数,分数区间0~100,权重默认3 | | Score | NodeResourcesFit | 三种策略:LeastAllocated (分配越少得分越高)、MostAllocated (分配越多得分越高)、RequestedToCapacityRatio (请求值与容量比率) | | Score | PodTopologySpread | 根据拓扑匹配度和权重得出分数,分数区间0~100,权重默认2 |
3.1 kubernetes 1.23版本调度器filter阶段和score阶段源码分析
3.2 修改调度器插件默认权重示例
3.2.1 环境准备
环境:( 集群中有两个节点:k8s-0001和 k8s-0002;已有工作负载 nginx,调度至节点 k8s-0002,工作负载 test),yaml 文件如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
spec:
selector:
matchLabels:
app: test
template:
metadata:
labels:
app: test
spec:
containers:
- name: container-1
image: nginx:latest
dnsPolicy: ClusterFirst
affinity:
nodeAffinity: #利用节点亲和使其调度至k8s-0001
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k8s-0001
podAffinity: #利用负载亲和使其调度至k8s-0002
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
namespaces:
- default
topologyKey: kubernetes.io/hostnam
3.2.2 调整InterPodAffinity权重,使工作负载test调度至节点k8s-0002
```
apiVersion: v1
kind: ConfigMap
metadata:
name: scheduler-config
namespace: kube-system
data:
scheduler-config.yaml: |
apiVersion: kubescheduler.config.k8s.io/v1beta3 #1.23以上版本集群可用v1beta3
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: default-scheduler
plugins:
score:
disabled:
- name: InterPodAffinity
- name: NodeAffinity
enabled:
- name: InterPodAffinity #提高负载亲和权重
weight: 100
- name: NodeAffinity
weight: 1
```
查看 kube-scheduler 调度日志,k8s-002 score得分为打分100 * 权重 100共得10000分,调度到 k8s-002 节点上。
3.2.3 调整NodeAffinity权重,使工作负载test调度至节点k8s-0001
```
apiVersion: v1
kind: ConfigMap
metadata:
name: scheduler-config
namespace: kube-system
data:
scheduler-config.yaml: |
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: default-scheduler
plugins:
score:
disabled:
- name: InterPodAffinity
- name: NodeAffinity
enabled:
- name: InterPodAffinity
weight: 1
- name: NodeAffinity #提高节点亲和权重
weight: 100
```
本文转载自:容器魔方,版权归原作者所有。
免责声明:本文内容来源于网络,所载内容仅供参考。转载仅为学习和交流之目的,如无意中侵犯您的合法权益,请及时联系Docker中文社区!