k8s调度器Scheduler
Kubernetes Scheduler(简称k8s Scheduler)是Kubernetes集群中的一个核心组件,它负责将Pod调度到合适的Node上运行,以实现集群资源的优化分配和负载均衡。以下是对k8s Scheduler的详细介绍:
一、基本概念
- Pod:Kubernetes中的最小可调度单元,包含一个或多个容器,以及这些容器所需的存储、网络等资源。
- Node:运行Pod的物理或虚拟机器,可以是虚拟机、物理机等。
- kube-scheduler:Kubernetes中的调度器进程,运行在Master节点上,负责将Pod调度到合适的Node上。
二、主要功能
- 资源分配:根据Pod的资源请求(如CPU、内存)和Node的当前可用资源情况,选择合适的Node来运行Pod。
- 满足约束条件:考虑Pod的调度约束条件和亲和性/反亲和性规则,如节点标签、区域、拓扑结构等要求,确保Pod被调度到符合其特定需求的Node上。
- 服务稳定性与优化:通过预选(Filtering)和优选(Scoring)两个阶段的策略执行,确保Pod能够成功调度,并尽可能地优化集群的整体性能和可靠性。
三、调度流程
k8s Scheduler的调度流程主要包括以下几个关键步骤:
- 监听事件:Scheduler会持续监听API Server的事件,一旦有新的待调度Pod或已有Pod需要重新调度时,它将介入并进行调度决策。
- 筛选节点:对于每一个Node,检查该节点是否满足Pod的资源需求和其他硬性约束条件,如节点标签匹配、容忍度(Taints and Tolerations)、存储容量等。如果一个Node通过了所有预选策略,则会被加入候选节点集合。
- 打分排序:Scheduler对候选节点集合应用一系列优选策略,为每个节点计算一个优先级分数。这些优选策略可以包括默认的系统策略(如基于资源利用率的打分)以及用户自定义的策略。Scheduler根据各个节点得到的积分排序,得分最高的节点将被选为Pod的最佳调度位置。
- 绑定Pod:当确定了最优节点后,Scheduler会在API Server中为Pod创建一个binding对象,将Pod与选定的Node绑定在一起。调度结果写入etcd,并通知kubelet开始在该Node上启动Pod。
四、调度算法与策略
k8s Scheduler的调度算法和策略可以是多样化的,包括但不限于:
-
优先级调度:根据Pod的优先级和Node的资源情况,优先调度高优先级的Pod。
-
公平调度:尽量平衡各个Node的资源使用情况,避免资源过度集中或浪费。
-
权重调度:根据预设的权重因子,综合考虑多种因素进行调度决策。
-
节点亲和性:根据节点的标签或特性,将Pod调度到具有相似特性的节点上。
在Kubernetes(k8s)中,节点亲和性(Node Affinity)是一种控制Pod调度到特定节点的高级策略。通过定义节点亲和性规则,管理员可以确保Pod被调度到符合特定条件的节点上,从而实现资源优化、性能提升、故障隔离以及满足特定的合规或业务需求。-
一、节点亲和性的基本概念
节点亲和性允许Pod根据节点的标签(Labels)和选择器(Selectors)来指定其应该被调度到的节点。这有助于将Pod与具有特定特征(如硬件类 型、地理位置、操作系统等)的节点关联起来。
-
二、节点亲和性的类型
节点亲和性可以分为两种类型:
- 硬亲和性(requiredDuringSchedulingIgnoredDuringExecution):
Pod必须被调度到满足特定条件的节点上。
如果没有满足条件的节点,Pod将不会被调度,并且将保持Pending状态直到有符合条件的节点出现。
Pod一旦被调度到某个节点上,即使节点的标签或条件发生变化,Pod也不会被重新调度。 - 软亲和性(preferredDuringSchedulingIgnoredDuringExecution):
Pod倾向于被调度到满足特定条件的节点上,但这不是强制性的。
如果没有满足条件的节点,Pod仍然可以被调度到其他节点上。
同样,Pod一旦被调度到某个节点上,即使节点的标签或条件发生变化,Pod也不会被重新调度。
- 硬亲和性(requiredDuringSchedulingIgnoredDuringExecution):
-
三、节点亲和性的配置
节点亲和性的配置通常通过YAML文件实现,在Pod的spec字段下添加affinity字段,并设置nodeAffinity子字段。以下是一个简单的配置示例:
apiVersion: v1 kind: Pod metadata: name: my-pod spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: disktype operator: In values: - ssd containers: - name: my-container image: my-image
在上述示例中,我们定义了一个Pod,它要求被调度到具有disktype=ssd标签的节点上。这是通过硬亲和性规则实现的,因此如果没有满足条件的 节点,Pod将不会被调度。
-
四、节点亲和性的应用场景
-
节点亲和性在多种场景下都非常有用,例如:
- 硬件要求:某些Pod可能对硬件有特殊要求(如需要SSD存储、特定的CPU类型等),这时可以使用节点亲和性将Pod调度到满足这些要求的节点上。
- 地理位置:在分布式系统中,可能希望将某些Pod调度到特定的地理位置(如靠近用户的数据中心),以提高访问速度和降低延迟。
资源优化:通过节点亲和性,可以将具有相似资源需求的Pod调度到同一节点上,以优化资源使用并减少资源浪费。
-
-
五、总结
Kubernetes的节点亲和性提供了一种灵活且强大的方式来控制Pod的调度行为。通过合理配置节点亲和性规则,管理员可以确保Pod被调度到符合特 定条件的节点上,从而实现资源优化、性能提升、故障隔离以及满足特定的合规或业务需求。
-
-
Pod亲和性/反亲和性:根据Pod之间的依赖关系或排斥关系,将相关的Pod调度到相同或不同的节点上。
在Kubernetes(简称K8S)中,Pod亲和性(Pod Affinity)是集群调度策略的一个重要组成部分,它允许用户指定某种规则,使得Pod更倾向 于被调度到满足特定条件的节点上运行,或者与已经在特定节点上运行的其他Pod部署在一起。以下是对K8S Pod亲和性的详细解释:- 一、Pod亲和性的基本概念
Pod亲和性主要用于处理Pod与Pod之间的关系,它允许Pod表达出希望与其相同或不同标签集的Pod共存于同一节点或拓扑域(如机架、可用区等) 的愿望。这种机制有助于优化资源使用、提高服务可靠性,并满足特定的应用程序需求。
- 二、Pod亲和性的类型- Pod亲和性可以分为两种类型: - 硬策略(requiredDuringSchedulingIgnoredDuringExecution): 必须满足条件,比较强硬。 如果没有满足条件的节点,调度器会不断重试,直到找到满足条件的节点为止。 一旦Pod被调度到某个节点,即使后续节点上的Pod标签发生变化,也不会影响已调度Pod的位置。 - 软策略(preferredDuringSchedulingIgnoredDuringExecution): 尽量满足条件,但不强制要求。 如果没有满足条件的节点,Pod仍然可以被调度到其他节点上。 同样,一旦Pod被调度到某个节点,后续节点上的Pod标签变化也不会影响已调度Pod的位置。
- 三、Pod亲和性的配置
Pod亲和性的配置通常通过YAML文件实现,在Pod的spec字段下添加affinity字段,并设置podAffinity子字段。以下是一个简单的配置示例:
apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment spec: replicas: 2 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: containers: - name: my-container image: my-image affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - my-app topologyKey: kubernetes.io/hostname
在上述示例中,我们定义了一个Deployment,它包含两个副本的Pod。这些Pod通过Pod亲和性的硬策略被要求调度到与标签app=my-app相同的Pod 所在的节点上。topologyKey设置为kubernetes.io/hostname,表示Pod将被调度到与已存在Pod相同的物理节点上。
- 四、Pod亲和性的应用场景
Pod亲和性在多种场景下都非常有用,例如:
1. 数据本地性:对于需要频繁访问本地存储的Pod,可以将其与存储服务所在的Pod部署在同一节点上,以减少网络延迟和提高性能。
2. 服务依赖:当Pod之间存在服务依赖关系时,可以使用Pod亲和性将它们部署在同一节点上,以确保服务的可用性和稳定性。
3. 资源优化:通过Pod亲和性,可以将具有相似资源需求的Pod部署在同一节点上,以优化资源使用并减少资源浪费。- 五、总结
K8S Pod亲和性是一种强大的调度策略,它允许用户根据Pod之间的依赖关系或资源需求来优化Pod的部署位置。通过合理配置Pod亲和性,可以提高 集群的资源利用率、服务可靠性和应用程序性能。
预选算法
在Kubernetes(k8s)中,Scheduler的预选算法是Pod调度过程中的一个重要阶段,负责从集群中所有可用的节点中筛选出能够满足Pod资源需求和其他特定条件的候选节点。这一过程主要基于一系列的预选策略(Predicates)进行。以下是关于k8s Scheduler预选算法的详细解析:
预选算法的工作流程
-
获取节点列表:
- Scheduler首先会从kube-apiserver获取集群中所有可用的节点列表。
-
遍历节点并筛选:
- 接着,Scheduler会遍历每一个节点,并根据预定义的预选策略(Predicates)对节点进行筛选。
- 每个预选策略都会检查节点是否满足特定的条件,例如资源是否充足、是否匹配Pod的标签选择器、是否有端口冲突等。
确定候选节点: - 只有通过了所有预选策略的节点才会被视为候选节点,进入后续的优选阶段。
-
默认的预选策略
-
Kubernetes默认加载了多个预选策略,包括但不限于以下几个:
- PodFitsPorts:判断Pod所使用的端口在备选节点中是否被占用。
- PodFitsResources:判断备选节点的资源(如CPU、内存)是否满足Pod的需求。
- PodSelectorMatches(MatchNodeSelector):判断备选节点是否包含Pod的标签选择器指定的标签。
- PodFitHost(HostName):判断Pod的spec.nodeName所指定的节点名称和备选节点的名称是否一致。
- NoDiskConflict:判断Pod的存储卷(如GCEPersistentDisk或AwsElasticBlockStore)和备选节点中已存在的Pod是否存在冲突。
-
预选算法的优化
为了提高预选过程的效率,Kubernetes采用了多种优化措施,如:
- 并行筛选:默认会启动多个goroutine来并行地进行节点的筛选,以提高筛选速度。
- 局部最优解:通过缩小筛选节点的数量范围,来避免在大型集群中遍历所有节点导致的性能问题。
- 平均分布:通过分配索引的方式,确保集群中的节点能够均匀地被分配Pod,以维持集群的负载均衡。
-
自定义预选策略
- 除了默认的预选策略外,用户还可以根据实际需求自定义预选策略,并将其注册到Scheduler中。自定义预选策略需要实现Kubernetes提供的接口,并在Scheduler的配置文件中进行指定。
-
总结
k8s Scheduler的预选算法是Pod调度过程中的关键一环,通过一系列的预选策略对集群中的节点进行筛选,从而确定能够满足Pod需求的候选节点。这一过程不仅确保了Pod能够被调度到合适的节点上运行,还通过多种优化措施提高了调度的效率和性能。
优选算法
k8s Scheduler的优选算法是在预选算法之后进行的,旨在从通过预选的候选节点中选择出最优的节点来运行Pod。这一过程主要基于一系列的优选函数(Priorities)进行,每个函数都会为候选节点打分,最终选择得分最高的节点作为Pod的运行节点。
-
优选算法的工作流程
- 获取候选节点:
- 优选算法首先会接收到预选算法筛选出的候选节点列表。
- 并发打分:
- 对于每个候选节点,优选算法会并发地根据配置的优选函数进行打分。
- 每个优选函数都会根据特定的评估标准(如资源利用率、节点标签、亲和性等)为节点计算一个分数。
- 加权求和:
- 在所有优选函数打分完成后,Scheduler会根据每个优选函数的权重(如果设置了的话)对节点的各个分数进行加权求和,得到节点的最终得分。
- 选择最优节点:
- 最终,Scheduler会选择得分最高的节点作为Pod的运行节点,并将其绑定到该节点上。
- 获取候选节点:
常用的优选函数
-
Kubernetes提供了多种内置的优选函数,包括但不限于以下几个:
- LeastRequestedPriority:
- 计算Pods需要的CPU和内存在当前节点可用资源的百分比,具有最小百分比的节点就是最优的。
- 得分计算公式:(cpu(capacity-sum(requested))*10/capacity)+(memory(capacity-sum(requested))*10/capacity)/2
- BalanceResourceAllocation:
- 选出资源使用率最均匀的节点,即CPU和内存占用率相近的节点。
- NodePreferAvoidPodsPriority:
- 如果节点上有注解信息"scheduler.alpha.kubernetes.io/preferAvoidPods",则该节点对该Pod的得分会很低(甚至为0),反之则得分很高。
- TaintToleration:
- 将Pod对象的spec.tolerations与节点的taints列表项进行匹配度检查,匹配的条目越多得分越低。
- ImageLocalityPriority:
- 根据Node上是否存在Pod的容器运行所需镜像以及镜像的大小对优先级打分。如果Node上存在Pod所需全部镜像,则得分为10分;如果Node上存在Pod容器部分所需镜像,则根据这些镜像的大小来决定分值;如果Node上一个镜像都不存在,则分值为0。
- InterPodAffinityPriority:
- 基于Pod亲和性(affinity)和反亲和性(anti-affinity)计算分数。遍历Pod对象亲和性的条目,并将那些能够匹配到节点的权重相加,值越大的得分越高。
- NodeAffinityPriority:
- 根据Pod对象中的nodeSelector,对节点进行匹配度检查,能够成功匹配的数量越多,得分就越高。
- LeastRequestedPriority:
-
自定义优选函数
- 除了内置的优选函数外,用户还可以根据实际需求自定义优选函数,并将其注册到Scheduler中。自定义优选函数需要实现Kubernetes提供的接口,并在Scheduler的配置文件中进行指定。
综上所述,k8s Scheduler的优选算法通过一系列的优选函数为候选节点打分,并选择得分最高的节点作为Pod的运行节点,从而实现了Pod的优化调度。
五、自定义调度器
Kubernetes支持通过自定义调度器来满足特定的调度需求。开发者可以根据业务需求编写自定义调度器,并将其集成到Kubernetes集群中。Kubernetes提供了调度器框架(Scheduler Framework),简化了自定义调度器的开发。
示例:
创建一个pod
vim 01.deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: myapp
name: myapp
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
schedulerName: my-scheduler
containers:
- image: wangyanglinux/myapp:v1.0
name: myapp
#一直pending状态 因为没有名为my-scheduler的调度器
[root@master Scheduler]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-75cdc5c7df-7dj56 0/1 Pending 0 4m33s
解决方案
# 在 kubernetes Master 节点开启 apiServer 的代理
[root@master Scheduler]# kubectl proxy --port=8001
Starting to serve on 127.0.0.1:8001
#将当前的apiservice的服务端点暴露出来,暴露出来的端点http直接访问
基于 shell 编写一个自定义调度器
vi my-scheduler.sh
#!/bin/bash
#制定当前服务器地址
SERVER='localhost:8001'
while true;
do
for PODNAME in $(kubectl --server $SERVER get pods -o json | jq '.items[] | select(.spec.schedulerName =="my-scheduler") | select(.spec.nodeName == null) | .metadata.name' | tr -d '"')
do
NODES=($(kubectl --server $SERVER get nodes -o json | jq '.items[].metadata.name' | tr -d '"'))
NUMNODES=${#NODES[@]}
CHOSEN=${NODES[$[ $RANDOM % $NUMNODES]]}
curl --header "Content-Type:application/json" --request POST --data '{"apiVersion":"v1","kind":"Binding","metadata": {"name":"'$PODNAME'"},"target": {"apiVersion":"v1","kind": "Node", "name": "'$CHOSEN'"}}' http://$SERVER/api/v1/namespaces/default/pods/$PODNAME/binding/
echo "Assigned $PODNAME to $CHOSEN"
done
sleep 1
done
[root@master Scheduler]# yum install -y epel-release
[root@master Scheduler]# yum install -y jq
[root@master Scheduler]# chmod a+x my-scheduler.sh
[root@master Scheduler]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-75cdc5c7df-8ldv9 0/1 Pending 0 18s
[root@master Scheduler]# ./my-scheduler.sh
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Success",
"code": 201
}Assigned myapp-75cdc5c7df-gbt6t to master
[root@master calico]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-75cdc5c7df-gbt6t 1/1 Running 0 44s
六、污点和容忍
在Kubernetes(k8s)中,污点(Taints)和容忍(Tolerations)是两种相互配合的机制,用于控制Pod的调度行为,确保Pod不会被调度到不合适的节点上。以下是对污点和容忍的详细解释:
一、污点(Taints)
- 定义与作用
污点是定义在节点(Node)上的键值对属性,用于让节点拒绝将Pod调度运行于其上,除非Pod有接纳节点污点的容忍度。污点的主要作用是标识节点具有某些不希望的属性,从而阻止Pod被调度到该节点上。
- 组成
每个污点由一个key、一个可选的value以及一个effect组成,格式为key=value:effect。其中,value可以为空,而effect描述了污点对Pod的作用效果。
-
Effect的类型
NoSchedule:表示Kubernetes不会将Pod调度到具有该污点的节点上,但已经调度到该节点的Pod不受影响。
PreferNoSchedule:软策略版本的NoSchedule,表示Kubernetes将尽量避免将Pod调度到具有该污点的节点上,但不是强制的。
NoExecute:表示Kubernetes不仅不会将Pod调度到具有该污点的节点上,还会将已经存在于该节点的Pod驱逐出去。
PreferNoSchedule: 表示k8s将尽量避免将pod调度到具有该污点的Node上 -
设置与去除
污点可以通过kubectl taint命令进行设置和去除。例如,设置污点使用kubectl taint nodes =:命令,去除污点则使用kubectl taint nodes :-命令。
#设置污点
kubectl taint nodes nodeName key=value1:NoSchedule
# 查找污点
kubectl describe node nodeName
Taints: node-role.kubernetes.io/control-plane:NoSchedule
# 删除污点
kubectl taint nodes nodeName key=value1:NoSchedule-
二、容忍(Tolerations)
- 定义与作用
容忍是定义在Pod上的键值对属性,用于配置Pod可以容忍哪些污点。只有当Pod具有对节点污点的容忍度时,它才有可能被调度到该节点上。
- 组成
每个容忍由一个key、一个可选的operator、一个可选的value以及一个effect组成。其中,operator用于指定与污点value的比较方式,默认为Equal;value用于与污点的value进行匹配;effect则指定了容忍的污点效果。
-
匹配规则
如果operator是Exists,则无需指定value,表示Pod可以容忍所有具有该key的污点。
如果operator是Equal,则Pod的容忍必须与污点的key和value都匹配。
如果不指定operator,则默认为Equal。 -
示例
apiVersion: v1
kind: Pod
metadata:
name: tolerant-pod
spec:
containers:
- name: nginx-container
image: nginx:latest
tolerations:
- key: "special"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
tolerationSeconds: 3600 # 3600秒后驱除pod
当不指定value时,表示容忍所有污点value
- key: "key2"
operator: "Exists"
effect: "NoSchedule"
当不指定key值时,表示容忍所有的污点key
tolerations:
- operator: "Exists"
当不指定effect值时,表示容忍所有污点的作用
tolerations:
- key: "key"
operator: "Exists"
多个master存在,防止资源浪费,使用一下命令可将pod部署至master
kubectl taint nodes nodeName node-role.kubenetes.io/master=:NoSchedule-
kubectl taint nodes nodeName node-role.kubenetes.io/master=:PreferNoSchedule
在上面的示例中,Pod tolerant-pod 定义了一个容忍度,表示它可以被调度到具有special=gpu:NoSchedule污点的节点上。
三、指定节点调度
设置pod.spec.nodeName 指定pod强制调度到master上
apiVersion: apps/v1
kind: Deployment
metadata:
name: nodename-test
spec:
replicas: 7
selector:
matchLabels:
app: nodename
template:
metadata:
labels:
app: nodename
spec:
nodeName: master
containers:
- name: myweb
image: wangyanglinux/myapp:v1.0
ports:
- containerPort: 80
设置pod.spec.nodeSelector 通过label-selecotr机制选择节点,由Scheduler策略匹配label,而后调度pod到目标节点,该规则属于强制约束 master如果有noSchedule污点选项 则master有label type=nodeselect也不能在master上创建
apiVersion: apps/v1
kind: Deployment
metadata:
name: nodeselect-test
spec:
replicas: 2
selector: # 选择器
matchLabels:
app: nodeselect
template:
metadata:
labels:
app: nodeselect
spec:
nodeSelector:
type: nodeselect # key:value 节点需要有此标签
containers:
- name: myweb
image: wangyanglinux/myapp:v1.0
ports:
- containerPort: 80
四、总结
污点和容忍是Kubernetes中用于控制Pod调度行为的两种重要机制。通过给节点设置污点,可以阻止不希望的Pod被调度到该节点上;通过在Pod上定义容忍度,可以使得Pod能够容忍节点的污点,从而被调度到该节点上。这两种机制相互配合,实现了对Pod调度行为的灵活控制。
七、高可用性与扩展性
- 高可用性:k8s Scheduler支持多实例部署,通过负载均衡确保调度服务的连续性。
- 扩展性:k8s Scheduler提供了丰富的扩展点(Extension Points),允许用户开发自己的插件来扩展调度器的功能。这些扩展点包括预选、优选、绑定等多个阶段,用户可以在这些阶段中插入自定义的逻辑来满足特定的调度需求。
综上所述,k8s Scheduler是Kubernetes集群中至关重要的组件之一,它通过精细的调度策略和高可用性配置,确保了集群资源的合理分配和高效利用。