k8s 调度

本文详细介绍了k8s的调度过程,包括Pod调度、调度策略,如nodeSelector、podAffinity、podAntiAffinity、taints与tolerations,以及自定义调度和调度失败分析。内容涵盖k8s架构、Node与Pod定义,强调了调度器资源分配机制,如request与limit的影响,并探讨了公平性、高效性和性能优化。

k8s 调度

1、 k8s 架构



k8s的架构如图:

我们都知道k8s分为master、node,其中:

master 主要有如下几个组件:

  • Kubernetes Controller Manager(kube-controller-manager):Kubernetes资源对象的”大总管”,是所有资源对象的自动化控制中心,比如Deployment中的pod副本数

  • Kubernetes API Server (kube-apiserver):Kubernetes的“心脏”,是集群控制的入口进程,也是所有资源增、删、查、改等操作的唯一入口

  • Kubernetes Scheduler(kube-scheduler):Kubernetes的”调度室“,负责资源调度(Pod调度)

  • etcd:是用于共享配置和服务发现的分布式,一致性的KV存储系统,被用作Kubernetes集群后端数据的持久化存储


  node 主要包含以下组件:

  • kubelet:负责Pod对应容器的创建、启停和销毁等任务

  • kube-proxy:与Kubernetes Service通信与负载均衡机制

  • Container Runtime:Docker Engine,负责本机容器的创建、启停与销毁等工作

2、k8s 调度


2.1  Pod 调度

这个过程看起来似乎比较简单,但实际生产环境的调度过程中,有很多问题需要考虑:

  • 首先,如何保证全部计算节点调度的公平性?如何保证每个节点都能被分配资源?

  • 其次,计算资源如何能够被高效利用?集群所有计算资源如何才能被最大化的使用?

  • 再次,如何保证Pod调度的性能和效率?如何能够快速的对大批量的Pod完成调度到较优的计算节点之上?

  • 最后,用户最了解自己的业务,用户是否可以根据实际需求定制自己的调度逻辑和策略?


2.2  Pod 调度过程

调度过程分为2个阶段:

  • 第一阶段:预选过程,过滤节点,调度器用一组规则过滤掉不符合要求的主机。比如Pod指定了所需要的资源量,那么可用资源比Pod需要的资源量少的主机会被过滤掉。

  • 第二阶段:优选过程,节点优先级打分,对第一步筛选出的符合要求的主机进行打分,在主机打分阶段,调度器会考虑一些整体优化策略,比如把容一个Replication Controller的副本分布到不同的主机上,使用最低负载的主机等。


代码位置(1.10 ):

https://github.com/kubernetes/kubernetes/tree/release-1.10/pkg/scheduler/algorithm

优选(Priorities)

经过预选策略(Predicates)对节点过滤,获取节点列表,再对符合需求节点列表进行打分,最终选择Pod调度到一个分值最高节点。

最终主机的得分用以下公式计算得出:

finalScoreNode = (weight1 * priorityFunc1) + (weight2 * priorityFunc2) + … + (weightn * priorityFuncn)

2.3  Node 定义

查看一个node的资源信息:

apiVersion: v1
kind: Node
metadata:
  labels:
    beta.kubernetes.io/arch: amd64
    beta.kubernetes.io/os: linux
    kubernetes.io/hostname: node-n1
  name: node-n1
spec:
  externalID: node-n1
status:
  addresses:
  - address: 10.162.197.135
    type: InternalIP
  allocatable:
    cpu: "8"
    memory: 16309412Ki
    pods: "110"
  capacity:
    cpu: "8"
    memory: 16411812Ki
    pods: "110"
  conditions: {...}
  daemonEndpoints:
    kubeletEndpoint:
      Port: 10250
  images: {...}
  nodeInfo: {...}

2.4  Pod 定义

查看一个pod的资源信息:

kubectl explain pod.spec

我们看这个pod:

  • requests:申请范围是0到node节点的最大配置

  • limits:申请范围是requests到无限大,即0 <= requests <=Node Allocatable, requests <= limits <= Infinity。

    说明:resoureces.limits影响pod的运行资源上限,不影响调度。

注释:

  • 红色部分表示资源分配

  • 浅蓝色表示采用的调度器

  • 灰色表示普通调度策略

  • 荧光色表示高级调度策略

2.5  k8s 调度器资源分配机制

  1. 基于Pod 中容器 request 资源“总和”调度

    a. resoureces.limits 影响 pod 的运行资源上限,不影响调度

    b. initContainer 取最大值,container 取累加值,最后两者中取大,即 Max( Max(initContainers.requests), Sum(containers.requests) )

    c. 未指定request资源时(QoS Guaranteed除外), 按资源需求为0进行调度

  2. 基于资源声明量的调度,即:request 字段值,而非实际占用

    i. 不依赖监控,系统不会过于敏感

    ii. 能否调度成功:pod.request < node.allocatable - node.requested

  3. Kubernetes node 资源的盒子模型

  4. 资源分配相关算法

    A. GeneralPredicates(主要是PodFitsResources)

    B. LeastRequestedPriority

    C. BalancedResourceAllocation,平衡cpu/mem的消耗比例

3、k8s 调度策略

3.1  普通调度策略

nodeSelector【将来会被废弃】:将 Pod 调度到特定的 Node 上:

apiVersion: v1
kind: Pod
metadata:
  labels:
    pod-template-hash: "4173307778"
    run: my-pod
  name: my-pod
  namespace: default
spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: my-pod
    ports:
    - containerPort: 80
      protocol: TCP
    resources: {}
  nodeSelector:
    disktype: ssd
    node-flavor: s3.large.2
  • 匹配node.labels

  • 排除不包含nodeSelector中指定label的所有node

  • 匹配机制 :完全匹配

3.2  高级调度策略

1. podAffinity:让某些 Pod 分布在同一组 Node 上:

apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: kubernetes.io/zone
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security
              operator: In
              values:
              - S2
          topologyKey: kubernetes.io/hostname
  containers:
  - name: with-pod-affinity
    image: k8s.gcr.io/pause:2.0

与nodeAffinity的关键差异:

  • 定义在PodSpec中,亲和与反亲和规则具有对称性

  • labelSelector的匹配对象为Pod

  • 对node分组,依据label-key = topologyKey,每个label-value取值为一组

  • 硬性过滤规则,条件间只有逻辑与运算

硬性过滤:排除不具备指定pod的node组

requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: kubernetes.io/zone

软性:不具备指定pod的node组打低分,降低该组node被选中的几率

- weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security
              operator: In
              values:
              - S2
          topologyKey: kubernetes.io/hostname

2. podAntiAffinity:避免某些 Pod 分布在同一组 Node 上:

apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: kubernetes.io/zone
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security
              operator: In
              values:
              - S2
          topologyKey: kubernetes.io/hostname
  containers:
  - name: with-pod-affinity
    image: k8s.gcr.io/pause:2.0

与podAffinity的差异:

  • 匹配过程相同

  • 最终处理调度结果时取反,podAffinity中可调度节点,在podAntiAffinity中为不可调度,podAffinity中高分节点,在podAntiAffinity中为低分

3. Taints:避免 Pod 调度到特定 Node 上:

apiVersion: v1
kind: Node
metadata:
  labels:
    beta.kubernetes.io/arch: amd64
    beta.kubernetes.io/os: linux
    kubernetes.io/hostname: node-n1
  name: node-n1
spec:
  externalID: node-n1
  taints:
  - effect: NoSchedule
    key: accelerator
    timeAdded: null
    value: gpu
  • 带effect的特殊label,对Pod有排斥性

    1. 硬性排斥 NoSchedule(如果一个pod没有声明容忍这个Taint,则系统不会把该Pod调度到有这个Taint的node上)

    2. 软性排斥 PreferNoSchedule(如果一个Pod没有声明容忍这个Taint,则系统会尽量避免把这个pod调度到这一节点上去,但不是强制的)

  • 系统创建的taint附带时间戳

    1. effect为NoExecute

    2. 便于触发对Pod的超时驱逐

  • 典型用法:预留特殊节点做特殊用途

kubectl taint node node-n1 foo=bar:NoSchedule


kubectl taint node node-n1 foo:NoSchedule-

4. Tolerations:允许 Pod 调度到有特定 taints 的 Node 上:

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: my-pod
  name: my-pod
  namespace: default
spec:
  containers:
  - name: my-pod
    image: nginx
  tolerations:
  - key: accelerator
    operator: Equal
    value: gpu
    effect: NoSchedule

可以无视排斥:

apiVersion: v1
kind: Node
metadata:
  labels:
    beta.kubernetes.io/arch: amd64
    beta.kubernetes.io/os: linux
    kubernetes.io/hostname: node-n1
  name: node-n1
spec:
  externalID: node-n1
  taints:
  - effect: NoSchedule
    key: accelerator
    timeAdded: null
    value: gpu
  • 完全匹配

    例:<key>=<value>:<effect>

  • 匹配任意taint value

    Operator为Exists,value为空

    例:<key>:<effect>

  • 匹配任意 taint effect

    effect为空

    例:<key>=<value>

3.3  无调度器调度 pod

1. nodeName:将Pod手动调度到特定的 Node 上:

2. DaemonSet:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: my-daemonset
spec:
  selector:
    matchLabels:
      name: my-daemonset
  template:
    metadata:
      labels:
        name: my-daemonset
    spec:   
      containers:
      - name: container
        image: k8s.gcr.io/pause:2.0

等同于:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deploy
spec:
  replicas: <# of nodes>
  selector:
    matchLabels:
      podlabel: daemonset
  teplate:
    metadata:
      labels:
        podlabel: daemonset
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: podlabel
                operator: In
                values:
                - daemonset
            topologyKey: kubernetes.io/hostname
      containers:
      - name: container
        image: k8s.gcr.io/pause:2.0

3.4  调度结果和失败原因分析


查看调度结果:

kubectl get po podname –o wide

查看调度失败原因:

kubectl describe po podname

调度错误列表:

3.5  自定义调度

例子:

https://kubernetes.io/blog/2017/03/advanced-scheduling-in-kubernetes/

前面讲的调度是指资源节点的调度,优先级也是指节点的优先级。高优先级的Pod会优先被调度,或者在资源不足低情况牺牲低优先级的Pod,以便于重要的Pod能够得到资源部署。

为了定义Pod优先级,需要先定义PriorityClass对象,该对象没有Namespace限制,官网示例:

然后通过在Pod的spec. priorityClassName中指定已定义的PriorityClass名称即可:

  • 当节点没有足够的资源供调度器调度Pod、导致Pod处于pending时,抢占(preemption)逻辑会被触发。

  • Preemption会尝试从一个节点删除低优先级的Pod,从而释放资源使高优先级的Pod得到节点资源进行部署。

欢迎大家关注个站哟:damon8.cn

最后介绍新公号:天山六路折梅手,欢迎关注。

往期回顾

微服务自动化部署CI/CD

如何利用k8s拉取私有仓库镜像

个站建设基础教程

ArrayList、LinkedList&nbsp;你真的了解吗?

大佬整理的mysql规范,分享给大家

如果张东升是个程序员

微服务架构设计之解耦合

浅谈负载均衡

Oauth2的认证实战-HA篇

Oauth2的授权码模式《上》

浅谈开发与研发之差异

浅谈&nbsp;Java&nbsp;集合&nbsp;|&nbsp;底层源码解析

基于 Sentinel 作熔断 | 文末赠资料

基础设施服务k8s快速部署之HA篇

今天被问微服务,这几点,让面试官刮目相看

Spring cloud 之多种方式限流(实战)

Spring cloud 之熔断机制(实战)

面试被问finally 和 return,到底谁先执行?

Springcloud Oauth2 HA篇

Spring Cloud Kubernetes之实战一配置管理

Spring Cloud Kubernetes之实战二服务注册与发现

Spring Cloud Kubernetes之实战三网关Gateway

关注公众号,回复入群,获取更多惊喜!公众号(程序猿Damon)里回复 ES、Flink、Java、Kafka、MQ、ML、监控、大数据、k8s 等关键字可以查看更多关键字对应的文章。

如有收获,点个在看,谢谢

### Kubernetes 调度器工作原理 Kubernetes 调度器的核心任务是将新创建的 Pod 分配到最适合运行它的节点上[^1]。这一过程涉及多个阶段,主要包括以下几个方面: #### 1. **调度流程概述** 调度器作为一个独立的控制平面组件,持续监控集群中的未分配 Pod,并为其寻找最佳目标节点[^3]。整个调度过程可以分为两个主要阶段:过滤(Filtering)和评分(Scoring)。 - **过滤阶段**:调度器首先筛选出能够满足 Pod 运行条件的所有候选节点。这一步骤基于预定义的规则集完成,例如资源可用性、亲和性和反亲和性约束等[^4]。 - **评分阶段**:对于通过过滤阶段的节点,调度器会应用一系列优先级函数对其进行打分。最终得分最高的节点会被选中作为目标节点。 #### 2. **绑定操作** 一旦选定目标节点,调度器会向 `kube-apiserver` 发送绑定请求,通知该 Pod 应当部署在哪一节点上。此步骤称为绑定(Binding),它是调度过程中不可或缺的一部分[^5]。 --- ### 配置方法 为了实现更灵活的调度行为,用户可以通过多种方式调整默认调度逻辑: #### 自定义调度策略 Kubernetes 支持自定义调度策略文件,允许管理员指定不同的调度算法或权重设置。以下是配置自定义调度策略的一个简单示例: ```yaml apiVersion: kubescheduler.config.k8s.io/v1beta1 kind: KubeSchedulerConfiguration profiles: - schedulerName: default-scheduler plugins: score: enabled: - name: NodeResourcesBalancedAllocation weight: 1 ``` 上述 YAML 文件展示了如何修改内置插件 `NodeResourcesBalancedAllocation` 的权重值。通过这种方式,用户可以根据实际需求微调调度决策。 #### 动态调度框架 从 v1.16 开始,Kubernetes 引入了扩展性强的动态调度框架(Dynamic Scheduling Framework)。开发者可以编写自定义调度插件并将其集成至现有调度器中,从而支持更为复杂的业务场景。 --- ### 使用注意事项 在大规模生产环境中使用 Kubernetes 调度器时需要注意以下几点: - **性能优化**:随着集群规模的增长,调度延迟可能成为瓶颈。为此,建议启用多线程调度模式以提升效率[^2]。 - **高可用性设计**:为了避免单点故障风险,通常推荐采用多副本的方式部署 kube-scheduler 实例。 --- ### 示例代码 下面是一段用于测试自定义调度策略效果的小型 Python 客户端脚本: ```python from kubernetes import client, config config.load_kube_config() v1 = client.CoreV1Api() pod_manifest = { 'apiVersion': 'v1', 'kind': 'Pod', 'metadata': {'name': 'test-pod'}, 'spec': { 'schedulerName': 'custom-scheduler', # 指定自定义调度器名称 'containers': [{ 'name': 'busybox', 'image': 'busybox', 'command': ['sleep', 'infinity'] }] } } resp = v1.create_namespaced_pod(body=pod_manifest, namespace='default') print(f"Pod {resp.metadata.name} created.") ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值