一 简介
在 Kubernetes 中,调度 是指将 Pod 放置到合适的 Node 上,然后对应 Node 上的 Kubelet 才能够运行这些 pod
1 调度概览
调度器通过 kubernetes 的监测(Watch)机制来发现集群中新创建且尚未被调度到 Node 上的 Pod。 调度器会将发现的每一个未调度的 Pod 调度到一个合适的 Node 上来运行。 调度器会依据下文的调度原则来做出调度选择。
2 kube-scheduler
kube-scheduler 是 Kubernetes 集群的默认调度器,并且是集群 控制面 的一部分。 如果你真的希望或者有这方面的需求,kube-scheduler 在设计上是允许 你自己写一个调度组件并替换原有的 kube-scheduler。
对每一个新创建的 Pod 或者是未被调度的 Pod,kube-scheduler 会选择一个最优的 Node 去运行这个 Pod。然而,Pod 内的每一个容器对资源都有不同的需求,而且 Pod 本身也有不同的资源需求。因此,Pod 在被调度到 Node 上之前, 根据这些特定的资源调度需求,需要对集群中的 Node 进行一次过滤。
在一个集群中,满足一个 Pod 调度请求的所有 Node 称之为 可调度节点。 如果没有任何一个 Node 能满足 Pod 的资源请求,那么这个 Pod 将一直停留在 未调度状态直到调度器能够找到合适的 Node。
调度器先在集群中找到一个 Pod 的所有可调度节点,然后根据一系列函数对这些可调度节点打分, 选出其中得分最高的 Node 来运行 Pod。之后,调度器将这个调度决定通知给 kube-apiserver,这个过程叫做 绑定。
在做调度决定时需要考虑的因素包括:单独和整体的资源请求、硬件/软件/策略限制、 亲和以及反亲和要求、数据局域性、负载间的干扰等等
3 kube-scheduler 调度流程
kube-scheduler 给一个 pod 做调度选择包含两个步骤:
过滤
打分
过滤阶段会将所有满足 Pod 调度需求的 Node 选出来。 例如,PodFitsResources 过滤函数会检查候选 Node 的可用资源能否满足 Pod 的资源请求。 在过滤之后,得出一个 Node 列表,里面包含了所有可调度节点;通常情况下, 这个 Node 列表包含不止一个 Node。如果这个列表是空的,代表这个 Pod 不可调度。
在打分阶段,调度器会为 Pod 从所有可调度节点中选取一个最合适的 Node。 根据当前启用的打分规则,调度器会给每一个可调度节点进行打分。
最后,kube-scheduler 会将 Pod 调度到得分最高的 Node 上。 如果存在多个得分最高的 Node,kube-scheduler 会从中随机选取一个。
支持以下两种方式配置调度器的过滤和打分行为:
调度策略 允许你配置过滤的 断言(Predicates) 和打分的 优先级(Priorities) 。
调度配置 允许你配置实现不同调度阶段的插件, 包括:QueueSort, Filter, Score, Bind, Reserve, Permit 等等。 你也可以配置 kube-scheduler 运行不同的配置文件。
二 调度
调度器通过 kubernetes 的 watch 机制来发现集群中新创建且尚未被调度到 Node 上的 Pod。调度器会将发现的每一个未调度的 Pod 调度到一个合适的 Node 上来运行。
kube-scheduler 是 Kubernetes 集群的默认调度器,并且是集群控制面的一部分。如果你真的希望或者有这方面的需求,kube-scheduler 在设计上是允许你自己写一个调度组件并替换原有的 kube-scheduler。
在做调度决定时需要考虑的因素包括:单独和整体的资源请求、硬件/软件/策略限制、亲和以及反亲和要求、数据局域性、负载间的干扰等等。
默认策略可以参考:https://kubernetes.io/zh/docs/concepts/scheduling/kube-scheduler/
调度框架:https://kubernetes.io/zh/docs/concepts/configuration/scheduling-framework/
nodeName 是节点选择约束的最简单方法,但一般不推荐。如果 nodeName 在 PodSpec 中指定了,则它优先于其他的节点选择方法。
使用 nodeName 来选择节点的一些限制:
如果指定的节点不存在。
如果指定的节点没有资源来容纳 pod,则pod 调度失败。
云环境中的节点名称并非总是可预测或稳定的。
三 将 Pod 分配给节点(nodeSelector)
你可以约束一个 Pod 只能在特定的 节点 上运行。 有几种方法可以实现这点,推荐的方法都是用 标签选择算符来进行选择。 通常这样的约束不是必须的,因为调度器将自动进行合理的放置(比如,将 Pod 分散到节点上, 而不是将 Pod 放置在可用资源不足的节点上等等)。但在某些情况下,你可能需要进一步控制 Pod 停靠的节点,例如,确保 Pod 最终落在连接了 SSD 的机器上,或者将来自两个不同的服务 且有大量通信的 Pods 被放置在同一个可用区
1 nodeSelector
nodeSelector 是节点选择约束的最简单推荐形式。nodeSelector 是 PodSpec 的一个字段。 它包含键值对的映射。为了使 pod 可以在某个节点上运行,该节点的标签中 必须包含这里的每个键值对(它也可以具有其他标签)。
2 添加标签到节点
[root@server1 schedu]# kubectl label nodes server2 disktype=ssd
node/server2 labeled
3 添加 nodeSelector 字段到 Pod 配置中
[root@server1 schedu]# cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
[root@server1 schedu]# kubectl apply -f pod.yaml
pod/nginx created
[root@server1 schedu]# kubectl get pod
NAME READY STATUS RESTARTS AGE
demo 1/1 Running 2 21h
nginx 1/1 Running 0 11s
[root@server1 schedu]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
demo 1/1 Running 2 21h 10.244.141.209 server3 <none> <none>
nginx 1/1 Running 0 24s 10.244.179.89 server2 <none> <none>
[root@server1 schedu]# kubectl get all
NAME READY STATUS RESTARTS AGE
pod/demo 1/1 Running 2 21h
pod/nginx 1/1 Running 0 45s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d15h
[root@server1 schedu]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
server1 Ready control-plane,master 6d15h v1.21.3 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=server1,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
server2 Ready <none> 6d15h v1.21.3 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=server2,kubernetes.io/os=linux
server3 Ready <none> 6d15h v1.21.3 beta.kubernetes.io/arch