侧边栏壁纸
  • 累计撰写 51 篇文章
  • 累计创建 23 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

K8s Pod 和 Service 5

zhanjie.me
2020-11-12 / 0 评论 / 0 点赞 / 3 阅读 / 0 字

5.1 kube-scheduler 简介

kube-scheduler 通过监听 kube-apiserver,获取未调度的 Pod 列表,通过调度算法计算出分配给 Pod 的 Node,并将 Node 信息与 Pod 进行绑定(Bind),结果存储在 etcd 中。而根据调度结果执行 Pod 的创建操作是由 Node 上的 kubelet 执行的。

kube-scheduler 作为 Master 上的核心模块,我们可以把它当做一个黑盒来处理,黑盒的输入为待调度的 Pod 和全部计算节点(Node)的信息,经过黑盒内部的调度算法和策略处理,输出为最优节点,然后由 kubelet 执行将 Pod 调度到对应 Node 的具体操作,kubelet 获取对应的 Pod 清单,下载镜像并启动容器。

kube-scheduler 职责及调度流程

kube-scheduler 的职责主要有以下 3 个:

  1. 集群高可用

kube-scheduler 可以设置 leader-elect 启动参数,这样会通过 etcd 进行节点选主。kube-scheduler 和 kube-controller-manager 都使用了一主多从的高可用方案。简单理解的话是这样的:kube-scheduler 启动时,会在 etcd 中创建 endpoint,endpoint 的信息中记录了当前的 leader 节点信息,以及上次更新时间。leader 节点会定期更新 endpoint 的信息,维护自己的 leader 身份,每个从节点的服务都会定期检查 endpoint 的信息,如果 endpoint 的信息在规定的时间范围内没有更新,从节点将会尝试更新自己的 leader 节点。

  1. 调度资源监听

通过 Watch 机制监听 kube-apiserver 上资源(Pod 和 Node)的变化。

kube-apiserver 给其它的组件(比如:kubelet、kube-controller-manager、kube-scheduler)等提供了一套 Watch 机制用于监控各种资源的变化,类似于消息中间件的发布-订阅模式(Push),这样 kube-apiserver 可以主动通知这些组件。

kube-apiserver 初始化时,会建立对 etcd 的连接并 watch etcd。当 kube-scheduler 客户端调用 Watch API 时,kube-apiserver 内部会建立一个 WatchServer,WatchServer 会从 etcd 中获取资源的 Watch event,Watch event 经过加工过滤后就会发送给客户端,Watch API 本质上是一个 GET 请求,通常有两种实现模式:通过 websocket 协议发送;或是通过 Transfer-Encoding=chunked 方式建立长连接。

  1. 调度节点分配

这个职责也是我们本节点将会重点介绍的部分。调度节点分配分为两个环节:预选(Predicates)与优选 (Priorites)。调度资源监听也是为了这个环节提供数据输入。

  • 预选:遍历所有目标 Node,根据配置的预选策略 Predicates Policies 过滤掉不符合策略的 Node,剩下符合要求的候选节点。预选的输出将会作为优选的输入。预选策略默认使用的是 DefaultProvider 中定义的 default predicates policies 集合。
  • 优选:根据配置的优选策略 Priorites Policies,为前一步过滤后的 Node 进行打分排名,得分最高的 Node 将作为最适合的 Node,该 Pod 将绑定(Bind)到最适合的 Node 上。如果打分排名后,有多个 Node 并列得分最高,kube-scheduler 会从中随机选取一个 Node 作为目标 Node。优选策略默认使用的是 DefaultProvider 中定义的 default priorites policies 集合。

kube-scheduler 调度节点分配需要考虑的问题较多,有:

  • 公平:如何保证每个 Node 都能够分配资源
  • 资源高效利用:集群所有资源能够被最大化使用
  • 效率:调度性能高,能够尽快对大批量的 Pod 完成调度工作
  • 灵活:允许用户自定义调度逻辑

kube-scheduler 官方流程图如下所示:

For given pod:

    +---------------------------------------------+
    |               Schedulable nodes:            |
    |                                             |
    | +--------+    +--------+      +--------+    |
    | | node 1 |    | node 2 |      | node 3 |    |
    | +--------+    +--------+      +--------+    |
    |                                             |
    +-------------------+-------------------------+
                        |
                        |
                        v
    +-------------------+-------------------------+

    Pred. filters: node 3 doesn't have enough resource

    +-------------------+-------------------------+
                        |
                        |
                        v
    +-------------------+-------------------------+
    |             remaining nodes:                |
    |   +--------+                 +--------+     |
    |   | node 1 |                 | node 2 |     |
    |   +--------+                 +--------+     |
    |                                             |
    +-------------------+-------------------------+
                        |
                        |
                        v
    +-------------------+-------------------------+

    Priority function:    node 1: p=2
                          node 2: p=5

    +-------------------+-------------------------+
                        |
                        |
                        v
            select max{node priority} = node 2

5.2 常用参数

kube-scheduler 在启动的时候也可以指定一些参数,列表如下:

参数 含义 默认值
--adress 监听地址 "0.0.0.0"
--port 调度器监听的端口 10251
--algorithm-provider 提供调度算法的对象 "DefaultProvider"
--master API Server 的 HTTP 地址 /
--profiling 是否开启 profiling,开启后可以在host:port/debug/pprof访问 profile 信息 true
--scheduler-name 调度器名称,用来唯一确定该调度器 "default-shcheduler"
--kube-api-burst 和 API Server 通信时的最大 burst 值 100
--kube-api-qps 和 API Server 通信时的 QPS 值 50
--log_dir 日志保存的目录 /
--policy-config-file json 配置文件,用来指定调度器的 Predicates 和 Priorites 策略 /

关于自定义策略的 JSON 文件的格式示例如下:

{
  "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 },
    ],
  "hardPodAffinitySymmetricWeight": 10,
  "alwaysCheckAllPredicates": false,
}

5.3 预选策略 (Predicates Policies)

预选策略的主要目的是过滤掉不符合条件的 Node 节点,预选策略大体上可以分为如下 4 类:

  • GeneralPredicates:负责最基础的调度策略
  • 与 Volume 相关的过滤规则:负责与容器持久化 Volume 相关的调度策略
  • 与 Node 相关的过滤规则:负责考察待调度 Pod 是否满足 Node 本身的一些条件
  • 与已运行 Pod 相关的过滤规则:负责检查待调度 Pod 与 Node 上已有 Pod 之间的亲和性关系

当开始调度 Pod 时,调度器会同时开启多个协程并发进行 Predicates 过滤,每个协程按照固定的顺序进行过滤,最后返回过滤后可以运行 Pod 的 Node 列表。

  1. GeneralPredicates

是最基础的调度策略,这个接口也会被其它组件直接调用,比如 kubelet 在启动 Pod 前会再执行一遍 GeneralPredicates 用于二次确认。

它包含的具体策略有:

  • PodFitsResources:计算 Node 的 CPU、内存、扩展资源(如 GPU)是否够用
  • PodFitsHost:检查 Node 的名字是否跟 Pod 的 spec.nodeName 匹配
  • PodFitsHostPorts:检查 Pod 申请的 Node 端口是否冲突
  • PodMatchNodeSelector:检查 Node 是否能匹配 Pod 的 nodeSelector 和 nodeAffinity2. 与 Volume 相关的过滤规则

它包含的具体策略有:

  • NoDiskConflict:检查 Node 上所有的 Pods 是否与待调度 Pod 的 Volume 有冲突,比如 AWS、GCE 的 Volume 不能被两个 Pod 同时使用
  • VolumeZonePredicate:检查 Pod Volume 的 zone 标签是否与节点的 zone 标签匹配,如果 Node 没有 zone 标签就认定为匹配
  • MaxPDVolumeCountPredicate:检查 Node 上某种类型的 Volume 是否已经超过指定数目
  • CSIMaxVolumeCountPredicate:检查 CSI Volume 相关的限制
  • VolumeBindingPredicate:检查 Pod 对应的 Local PV 的 nodeAffinity 字段,是否跟某个 Node 标签相匹配。如果该 Pod PVC 还没有绑定 PV,调度器要检查所有待绑定的 PV,且该 PV 的 nodeAffinity 是否与 Node 标签匹配3. 与 Node 相关的过滤规则

它包含的具体策略有:

  • NodeConditionPredicate:检查 Node 是否还未准备好或处于 NodeOutOfDisk、NodeNetworkUnavailable 状态,或者 Node 的 spec.Unschedulable 设置为 true,如果出现以上的情况,该 Node 都无法被调度
  • PodTolerateNodeTaints:检查 Node 的 taint(污点)机制,只有当 Pod 的 Toleration 与 Node 的 Taint 匹配时,Pod 才能调度到该 Node 上
  • NodeMemoryPressurePredicate:检查 Node 的内存是否不够使用
  • NodeDiskPressurePredicate:检查 Node 的磁盘是否不够使用
  • NodePIDPressurePredicate:检查 Node 的 PID 是否不够使用4. 与已运行 Pod 相关的过滤规则
    它包含的具体策略主要是:PodAffinityPredicate,用于检查待调度 Pod 与 Node 上已有 Pod 之间的亲和性与反亲和性关系。

5.4 优选策略 (Priorites Policies)

通过前面预选策略过滤出来的 Node 列表,会再一次使用优选策略为这些 Node 打分,最终得分最高的 Node 会作为该 Pod 的调度对象。

有多个优选策略就相当于有多个打分函数,那么总得分的计算公式为:总分 = (打分函数 1 * 权重 1) + (打分函数 2 * 权重 2) + ... + (打分函数 3 * 权重 3),打分函数的打分范围为 0 - 10 分,0 表示非常不合适,10 表示非常合适。每个打分函数都可以配置对应的权重,默认权重值为 1,如果某个打分函数特别重要就可以增加该权重值。

常用的优选策略有:

  • LeastRequestedPriority:选出空闲资源(CPU & Memory)最多的 Node
  • BalancedResourceAllocation:主要用于资源平衡,选出各项资源分配最均衡的 Node,避免出现某些 Node CPU 被大量分配,而 Memory 大量剩余的情况
  • SelectorSpreadPriority:为了更好容灾,对属于同一个 Service 或是 RC 的多个 Pod 副本,尽量调度到多个不同的 Node 上
  • InterPodAffinityPriority:优先将 Pod 调度到相同的拓扑上(如同一个节点、Rack、Zone 等)
  • NodeAffinityPriority:优先调度到匹配 NodeAffinity 的 Node 上
  • TaintTolerationPriority:优先调度到匹配 TaintToleration 的 Node 上
  • ImageLocalityPriority:优先选择已经存在 Pod 所需 Image 的 Node(已注册但默认未使用)
  • MostRequestedPriority:优先选择已经使用过的 Node,适用于 cluster-autoscaler(已注册但默认未使用)

因此kube-scheduler 算法流程图如下所示:

image-inhrsttq.png


5.5 自定义调度器

除了使用集群自带的调度器,也可以编写自定义的调度器,然后在 Pod YAML 文件中通过参数 spec.schedulername 指定调度器的名称,这样在 Pod 创建时就会使用自定义的调度器而不是集群默认的调度器。

比如:

apiVersion: v1
kind: Pod
metadata:
  name: Pod-example
spec:
  # 使用自定义调度器 my-scheduler
  schedulername: my-scheduler
  containers:
    - name: nginx
      image: nginx

而自定义调度器的实现逻辑依然是:读取 API Server 中 Pod 列表,通过特定算法找到最适合的 Node,然后把调度结果写回到 API Server。

0

评论区