kube-scheduler负责分配调度pod到集群内的节点上,它监听kube-apiserver,查询还未分配Node的pod,根据调度策略为这些pod分配节点,调度器在给pod分配节点时需要充分考虑多方面信息,需要考虑的信息如下所示:
公平调度
资源高效利用
Qos
affinity和anti-affinity
数据本地化(data locality)
内部负载干扰(inter-workload interference)
deadlines等
kube-scheduler调度分为两个阶段,predicate和priority,predicate过滤不符合条件的节点,priority选择高优先级的节点。Predicate策略有多个,
内置的Predicate策略如下所示,除下面列举的部分策略外,还有其他策略,另外,还可以自定义Predicate策略。
- PodFitsHostPorts:检查是否有Host Ports冲突
- PodFitsResources:检查Node的资源是否充足,包括允许的Pod数、CPU、内存等
- HostName:检查pod.Spec.NodeName是否与候选节点一致
- MatchNodeSelector:检查候选节点的pod.Spec.NodeSelector是否匹配
- PodTolerateNodeTaints:检查Pod是否容忍Node Taints
- MatchInterPodAffinity:检查是否匹配Pod的亲和性要求
和Predicate一样,priority也内置了很多策略,如下所示,下面列举了部分priority策略。
- InterPodAffinityPriority:优先将pod调度到相同拓扑上(如同一个节点、Rack、Zone等)
- LeastRequestedPriority:优先调度到请求资源少的节点上
- BalancedResourceAllocation:优先平衡各个节点的资源使用
- NodeAffinityPriority:优先调度到匹配NodeAffinity的节点上
- TaintTolerationPriority:优先调度到匹配TaintToleration的节点上
接着我们来看看实际例子,第一类例子是在定义pod的deployment文件时,可以设置pod请求的cpu/memory资源以及cpu/memory资源上限,这样kube-scheduler在调度的时候可以根据这些信息把pod分配到更合理的node节点上,具体的yaml文件如下所示:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: 1Gi
cpu: 1
requests:
memory: 256Mi
cpu: 100m
通过上面的文件创建pod,查看pod的信息(kubectl describe podname)可以看到启动的pod的资源设置和yaml文件中设置一致。
除了对单个pod或者container进行资源限制设置外,还可以对namespace中所有pod或者所有container中所使用的资源进行限制。如下所示创建limitRange对象,namespace中创建的pod或者container总使用的cpu或者memory量不能大于max cpu和max memory。
接着看第二类例子,第二类例子是设置nodeSelector或者设置pod-anti-affinity,这样kube-scheduler在调度pod的时候会根据设置的信息将pod调度到合理的node节点上。
pod的Deployment yaml文件中设置的nodeSelector,如下所示
创建pod,会看到pod一直是pending状态,查看pod信息,可以看到因为没有找到match的node
给node打上label,pod从pending状态变成running状态。
查看node节点的标签命令:kubectl get node --show-labels
给node节点打上标签命令:kubectl label nodes nodename key=value
删除node节点上的标签命令:kubectl label nodes nodename key-
除了通过nodeSelector将pod分配到指定的node节点上外,还可以通过nodeAffinity来设置,下面是一个强node亲和性设置,如果集群中不存在如下标签的node节点,pod会处于pending状态
除了强亲和性,还可以设置弱亲和性,当有满足条件的pod时,就分配到满足的node上,如果不存在则分配到任意一个node上。
Node可以设置亲和性,pod间也可以设置亲和性和反亲和性,例如相同的一个服务,需要部署多个pod副本,为了高可用,这些pod期望分配到不同node节点上,那么可以设置pod的反亲和性达到这样的效果。下面的例子中podAffinity设置了pod部署到一个已经存在运行的pod的节点上,且这个允许的pod的label key=a,value=b。podAntiAffinity设置了pod不能部署到这样的node,node上存在了已经允许pod,pod的label的key=app,value=anti-nginx.
上述的deployment文件创建pod,pod使用处于pending状态,因为node节点上不存在允许的pod,且pod的label key=a,value=b.删除podAffinity,只保留podAntiAffinity,再次创建pod,可以看到pod创建成功,因为replicas=2,所以会创建两个pod,且两个pod分别被创建在不同的node节点上。
接着再看看如何通过设置污点(Taints)和容忍度(Tolerations)来控制哪些pod被部署到期望的node节点上。例如大数据的项目非常耗费资源,可能想把大数据类的应用部署到独享的某些节点上,防止其他应用占用了这些节点资源,针对这种需求,那么可以把这些节点设置Taints,其他团队在不知道节点的Taints的情况下,所有的应用就不会部署到这些节点上。
给节点打上污点的命令:kubectl taint nodes nodename for-special-user=taintstest:NoSchedule
取消节点上的污点命令:kubectl taint nodes nodename for-special-user=taintstest:NoSchedule-
查看节点上的污点命令:kubectl describe nodes {Node名称}
pod的deployment yaml文件中如果设置了tolerations,那么这个pod就会被部署到指定的node节点上,具体内容如下所示:
以上介绍了如何设置资源limit/request,nodeSelector,podAffinity/podAntiAffinity,taints&&tolerations来影响kube-schedule,从而实现将某些pod部署到指定的node节点上。