k8s调度策略nodename和nodeselector

在k8s中有几大核心组件,Scheduler调度器是其中的一个。调度器通过 kubernetes 的 watch 机制来发现集群中新创建且尚未被调度到 Node 上的 Pod。调度器会将发现的每一个未调度的 Pod 调度到一个合适的 Node 上来运行。

对每一个新创建的 Pod 或者是未被调度的 Pod,kube-scheduler 会选择一个最优的 Node 去运行这个 Pod。然而,Pod 内的每一个容器对资源都有不同的需求,而且 Pod 本身也有不同的资源需求。因此,Pod 在被调度到 Node 上之前,根据这些特定的资源调度需求,需要对集群中的 Node 进行一次过滤。
在一个集群中,满足一个 Pod 调度请求的所有 Node 称之为可调度节点。如果没有任何一个 Node 能满足 Pod 的资源请求,那么这个 Pod 将一直停留在未调度状态(Pending)直到调度器能够找到合适的 Node。
调度器先在集群中找到一个 Pod 的所有可调度节点,然后根据一系列函数对这些可调度节点打分,然后选出其中得分最高的 Node 来运行 Pod。之后,调度器将这个调度决定通知给 kube-apiserver,这个过程叫做绑定。
在做调度决定时需要考虑的因素包括:单独和整体的资源请求、硬件/软件/策略限制、亲和以及反亲和要求、数据局域性、负载间的干扰等等。
调度流程
kube-scheduler 给一个 pod 做调度选择包含两个步骤:

过滤(断言) predicate
打分(优先级)priority

过滤阶段会将所有满足 Pod 调度需求的 Node 选出来。例如,PodFitsResources 过滤函数会检查候选 Node 的可用资源能否满足 Pod 的资源请求。在过滤之后,得出一个 Node 列表,里面包含了所有可调度节点;通常情况下,这个 Node 列表包含不止一个 Node,如果这个列表是空的,代表这个 Pod 不可调度。
在打分阶段,调度器会为 Pod 从所有可调度节点中选取一个最合适的 Node。根据当前启用的打分规则,调度器会给每一个可调度节点进行打分。
最后,kube-scheduler 会将 Pod 调度到得分最高的 Node 上。如果存在多个得分最高的 Node,kube-scheduler 会从中随机选取一个。
实现过滤和打分的手段主要有固定节点调度和节点标签调度、亲和和反亲和、污点和容忍度。如果容器对资源进行了请求(例如CPU、内存),那么节点当前可用内存和CPU也是调度需要考虑的。
1.固定节点调度NodeName
nodeName 是节点选择约束的最简单方法,但是由于其自身限制,通常不使用它。nodeName 是 PodSpec 的一个字段。如果它不为空,调度器将忽略 pod,并且运行在它指定节点上的 kubelet 进程尝试运行该 pod。因此,如果 nodeName 在 PodSpec 中指定了,则它的优先级最高。
使用 nodeName 的方式选择节点存在一些限制:
如果指定的节点不存在,pod将会一直处于Pending状态。
如果指定的节点没有资源来容纳 pod,pod 将会调度失败并且其原因将显示为,比如 OutOfmemory 或 OutOfcpu。
云环境中的节点名称并非总是可预测或稳定的。
下面上一个例子

vi test-schedule.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-schedule
spec:
  nodeName: k8s-node1
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
      name: http
kubectl apply -f test-schedule.yaml
kubectl get pod -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP            NODE        NOMINATED NODE   READINESS GATES
test-schedule   1/1     Running   0          7s    10.244.1.15   k8s-node1   <none>           <none>

2.节点标签调度NodeSelector
nodeSelector 是 PodSpec 的一个字段。 它包含键值对的映射。为了使 pod 可以在某个节点上运行,该节点的标签中必须包含这里的每个键值对。最常见的用法的是一对键值对。
我们现在k8s-node2节点添加一个标签,如果需要覆盖已有标签可以添加--overwrite参数

kubectl label node k8s-node2 gpu=true
kubectl get node --show-labels

微信截图_20220425103144.png

如果要取消这个标签,只需要把key的=value换成-即可,如下命令

kubectl label node k8s-node2 gpu-

然后我们重新编辑下刚才的test-schedule.yaml,使用NodeSelector使其调度到k8s-node2

vi test-schedule.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-schedule
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
      name: http
  nodeSelector:
    gpu: "true"
kubectl apply -f test-schedule.yaml
kubectl get pod -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP            NODE        NOMINATED NODE   READINESS GATES
test-schedule   1/1     Running   0          26s   10.244.2.11   k8s-node2   <none>           <none>

发现已经调度到了k8s-node2节点了,注意gpu的value要加上双引号

3.节点亲和性和反亲和性

这个可以查看我之前的笔记:https://sulao.cn/post/827.html

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://sulao.cn/post/835.html