1. Scheduling

  • 为Pod找到一个合适的Node

2. Node定义

kubectl get node node-slave -o yaml > node-slave.yaml
apiVersion: v1
kind: Node
metadata:
  labels:
    kubernetes.io/arch: amd64
    kubernetes.io/hostname: node-slave
    kubernetes.io/os: linux
  name: node-slave
status:
  addresses:
  - address: node-slave
    type: Hostname
  allocatable: # node可分配的资源配额
    cpu: "2"
    memory: 3564872Ki
    pods: "110"
  capacity:
    cpu: "2"
    memory: 3667272Ki
    pods: "110"
  conditions: {...}
  daemonEndpoints:
    kubeletEndpoint:
      Port: 10250
  images: : {...}
  nodeInfo:
    architecture: amd64
    operatingSystem: linux
    osImage: CentOS Linux 8

2.1. 调度资源配额

  • capacity:    node资源配额的系统能力
  • allocatable: node可分配的资源配额--给业务用

2.2. Node资源的盒子模型

  • 实际生产中,capacity 和 allocatable 这两个值有差异,要留出资源给系统和K8S使用,不能都分配给node
  • 可以设置门槛,什么时候可以触发硬驱逐pod,保证k8s系统能正常运行

3. Pod定义

3.1. 查看pod完整的配置字段

kubectl explain pod.spec

3.2. 查看pod定义 

kubectl get pod my-pod-1 -o yaml > my-pod-1.yaml
  • spec
    • 期望
    • k8s调度后的结果
    • pod的状态merge不需要关心,交给调度器
  • 容器
    • containers
    • 1个pod里可以运行多个container
  • 调度资源配额
    • resources
    • 生产中,根据不同的微服务,也要预先指定资源配额
  • 调度器
    • schedulerName

    • 在多调度器的情况下会用到

  • 调度结果

    • nodeName

  • 高级调度策略
    • 根据node的属性决定pod的调度
      • nodeSelector

      • affinity

      • tolerations

apiVersion: v1
kind: Pod
metadata:
  labels:
    app: my-pod-1
  name: my-pod-1
  namespace: default
spec:
  containers:  
    image: nginx
    imagePullPolicy: IfNotPresent
    name: my-pod-1
    ports:
    - containerPort: 3500
      protocol: TCP    
    readinessProbe: {...}
    resources: 
      requests:
        memory: "1Gi"
        cpu: "500m"
      limits:
        memory: "1Gi"
        cpu: "500m"
  schedulerName: default-scheduler
  nodeName: node-slave
  restartPolicy: Always
  nodeSelector: {...}
  affinity: {...}
  tolerations: {...}  
status: {...}

4. K8S调度器的资源分配机制

确保node的资源可以得到最优的利用,确保pod的资源需求可以得到充分的满足。

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

  • resoureces.limits 影响pod的运行资源上限,不影响调度
  • initContainer 
    • 启动container之前,做一些预处理,处理完就退出了
    • 逐一执行initContainer
  • initContainer 取最大值,container 取累加值,最后取大者, 即
Max( Max(initContainers.requests), Sum(containers.requests) )
  • resoureces.request 未指定时, 按0资源需求进行调度
    • 适合一些离线的任务
    • 或者优先级不是很高,只是想夹缝的利用node上没有被分配的资源去做一些计算
    • 如果有资源就利用起来,没资源就不运行

4.2. 基于资源声明量的调度,而非实际占用

  • 不依赖监控,系统不会过于敏感
    • pod的资源用超了,或者没有充分利用,调度器都不会感知
  • 能否调度成功:
pod.request < node.allocatable - node.requested

4.3. 资源分配相关算法

  • GeneralPredicates(主要是PodFitsResources)
    • 检查CPU和内存、硬盘的余量,余量不满足要求,直接排除不满足要求的node,不参与调度
  • LeastRequestedPriority
    • 最少被调度pod的node,优先分配给pod
    • 保证每个node上的pod个数均衡
  • BalancedResourceAllocation,平衡cpu/mem的消耗比例
    • 比较pod所需要cpu/mem的比例,是否和node的cpu/mem比例相近,相近的优先调度
    • 保证node剩余的cpu和mem被后续的pod消费

5. 高级调度

5.1. nodeSelector:将 Pod 调度到特定的 Node 上

nodeSelector
    diskType: ssd
    node-flavor:node-slave
  • 顺序板会默认给node打上label,也可以手动打label,不能重复
  • 语法格式:map [string]:[string]
  • 作用:匹配node.labels
    • 排除不包含nodeSelector中指定label的所有node
    • 匹配机制 —— 完全匹配(上述脚本,指定了两个selector,都要满足)

5.2. nodeAffinity:nodeSelector 升级版

nodeSelector的功能还是有限制的,所以引入新的feature。与nodeSelector关键差异

  • 引入运算符:In,NotIn (labelselector语法)
  • 支持枚举label可能的取值
    • 如让pod调度到不同zone上的node中:zone in [zone1,zong2...]
    • 如让pod调度到指定node上:                 node in [node-master, node-slave...]
  • 支持硬性过滤和软性评分
    • 硬性过滤规则
      • 支持指定多 matchExpressions 条件之间的逻辑或运算
      • 必须满足这些条件,如果没有满足硬性过滤条件的node,就应用软性评分条件
      • requiredDuringSchedulingIgnoredDuringExecution:硬性过滤,排除不具备指定label的node
    • 软性评分规则
      • 支持设置条件权重值。
      • 优先满足这些条件,如果不满足,也要调度成功
      • preferredDuringSchedulingIgnoredDuringExecution:软性评分,不具备指定label的node打低分, 降低node被选中的几率
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    nodeAffinity: # 亲和
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: node-flavor
            operator: In
            values:
            - node-master
            - node-salve
      preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 1
        preference:
          matchExpressions:
          - key: node-flavor
            operator: In
            values:
            - node-slave
  containers:
  - name: with-node-affinity
    image: nginx

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

与nodeAffinity的关键差异

  • 定义在PodSpec中,亲和与反亲和规则具有对称性
  • labelSelector的匹配对象为Pod
  • 对node分组,依据label-key = topologyKey,每个labelvalue取值为一组
  • topologyKey:被调度的pod是在什么级别一致(zone、node、机架),可以自定义
  • 硬性过滤规则
    • 条件间只有逻辑与运算
    • 如果没有满足硬性过滤条件的node,就应用软性评分条件
    • requiredDuringSchedulingIgnoredDuringExecution:硬性过滤,排除不具备指定pod的node组
  • 软性评分
    • 优先满足这些条件,如果不满足,也要调度成功
    • preferredDuringSchedulingIgnoredDuringExecution:软性评分,不具备指定pod的node组打低分, 降低该组node被选中的几率
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    podAffinity: # 亲和
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - nginx
        topologyKey: topology.kubernetes.io/zone # 同一app的pod调度到同一个zone机房
      preferredDuringSchedulingIgnoredDuringExecution:
        - podAffinityTerm:
            labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - nginx
            topologyKey: kubernetes.io/hostname # 同一app的pod调度到同一个node 
          weight: 100
  containers:
  - name: nginx
    image: nginx

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

与podAffinity的差异

  • 匹配过程相同
  • 最终处理调度结果时取反 
    • podAffinity中可调度节点,在podAntiAffinity中为不可调 度
    • podAffinity中高分节点,在podAntiAffinity中为低分
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    podAntiAffinity: # 反亲和
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - nginx
        topologyKey: topology.kubernetes.io/zone # 同一app的pod不调度到同一个zone机房
      preferredDuringSchedulingIgnoredDuringExecution:
        - podAffinityTerm:
            labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - nginx
            topologyKey: kubernetes.io/hostname # 同一app的pod不调度到同一个node 
          weight: 100
  containers:
  - name: nginx
    image: nginx

6. 手动调动Pod

6.1. 适用场景

  • 调度器不工作了,临时救急
  • 或者不是按照你期望的方式调度。
  • 手动直接指定Node name
  • 自定义调度器,将node name为空的提出来,填上
  • describe pod看不到自动调度的event

6.2. DaemonSet

  • 每个node上部署一个相同的pod
  • 通常用来部署集群中的agent,如果网络插件
  • 避免动态计算node数量和扩容操作
  • DaemonSet等价于配置了node级别反亲和的deployment,副本数量要和node数量相等
apiVersion: v1
kind: Pod
metadata:
  labels:
    name: weave-net
  name: weave-net-jhcjh
  namespace: kube-system
  ownerReferences:
  - apiVersion: apps/v1
    controller: true
    kind: DaemonSet
    name: weave-net

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

  • taints 污点排斥

7.1. taints 是带effect的特殊label,对Pod有排斥性

  • 硬性排斥 NoSchedule
  • 软性排斥 PreferNoSchedule

7.2. 系统创建的taint附带时间戳

  • effect为NoExecute:不是调度器处理的,是NodeController用kubelet处理的
  • 便于触发对Pod的超时驱逐

7.3. 典型用法

  • 预留特殊节点做特殊用途
apiVersion: v1
kind: Node
metadata:
    labels:
        beta.kubernetes.io/arch: amd64
        beta.kubernetes.io/os: linux
        kubernetes.io/hostname: node-master
    name: node-master
spec:
    externalID: node-n1
    taints:
    - effect: NoSchedule
    key: accelerator
    timeAdded: null
    value: gpu
    status: {...}

7.4. 允许调度到master

kubectl taint node node-master node-role.kubernetes.io/master-

7.5. 禁止调度到master

kubectl taint node node-master node-role.kubernetes.io/master="":NoSchedule

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

  • Tolerations 容忍污点排斥,可以保证通过taints预留出来的node,有些pod可以调度上去

8.1. 完全匹配

  • 例:<key>=<value>:<effect>
  • Operator为Equal
  • key和value,以及effect要完全相等

8.2. 匹配任意taint effect

  • 例:<key>=<value>
  • effect为空
  • key和value相等就行了

8.3. 匹配任意taint value

  • 例:<key>:<effect>
  • Operator为Exists
  • value为空
  • key相等就行了

8.4. 例子

  • 集群有一个node配置了gpu,不希望不消耗gpu的pod调度上去,避免消耗内存
  • 污点排斥
apiVersion: v1
kind: Node
metadata:
    labels:
        beta.kubernetes.io/arch: amd64
        beta.kubernetes.io/os: linux
        kubernetes.io/hostname: node-gpu
    name: node-gpu
spec:
    externalID: node-gpu
    taints:
        - effect: NoSchedule
        key: accelerator
        timeAdded: null
        value: gpu
status: {...}
  • 容忍污点:将有gpu需求的pod调度的gpu 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

9. 调度失败原因分析

9.1. 查看调度结果

kubectl get pod [podname] –o wide

9.2. 查看调度失败原因

kubectl describe pod [podname]
  • 可以看到调度失败的event 

9.3. 调度失败错误列表

kubernetes/error.go at release-1.9 · kubernetes/kubernetes · GitHub

10. 多调度器

10.1. 适用场景

  • 集群中存在多个调度器,分别处理不同类型的作业调度 

10.2. 使用限制

  • 建议对node做资源池划分,避免调度结果写入冲突,不同的调度器处理不同的node资源池

10.3. 给pod手动指定schedulerName

apiVersion: v1
kind: Pod
metadata:
    labels:
        run: my-pod
    name: my-pod
    namespace: default
spec:
    containers:
        - image: nginx
        imagePullPolicy: Always
        name: my-pod
        ports:
            - containerPort: 80
            protocol: TCP
    schedulerName: my-custom-scheduler

10.4. 自定义调度器配置

  • 查看更多调度器配置项
kube-scheduler --help
  • --policy-config-file
    • 自定义调度器加载的算法
    • 或者调整排序算法权重
    • 或者关闭不需要的算法,避免不必要的消耗
{
  "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
}

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐