调度说明
简介
schedule是Kubernetes的调度器, 主要任务是把定义的Pod分配到集群的节点上.
- 公平: 保证每个节点都能被分配资源
- 资源高效利用: 集群所有资源最大化被使用
- 效率: 调度的性能要好, 能够尽快地对大批量的Pod完成调度任务
- 灵活: 允许用户根据自己的需求控制调度的逻辑
Schedule是作为单独的程序运行的, 启动之后会一直监听API Server, 获取PodSpec.NodeName为空的Pod, 对每个Pod都会创建一个Binding, 表明该Pod应该放到哪个节点上
k8s内pod由scheduler调度,scheduler的任务是把pod分配到合适的node节点上。scheduler调度时会考虑到node节点的资源使用情况、port使用情况、volume使用情况等等…在此基础之上,我们也可以控制pod的调度。
调度过程
调度分为几个部分:
1. 过滤掉不满足条件的节点, 这个过程为 predicate;
2. 对通过的节点按照优先级排序, 这个是priority;
3. 从中选择优先级最高的节点. 如果中间发生错误, 就直接返回错误
predicate有一系列算法可以使用:
- PodFitsResources : 节点上剩余的资源是否大于Pod请求的资源
- PodFitsHost: 如果Pod指定了NodeName, 检查节点名称是否和NodeName匹配
- PodFitsHostPorts : 节点上已经使用的Port是否和Pod申请的port冲突
- PodSelectorMatches : 过滤掉和Pod指定的label不匹配的节点
- NoDiskConflict: 已经mount的Volume和Pod指定的Volume不冲突, 除非都是只读
如果在predicate过程中没有合适的节点, Pod会一直在pending状态, 不断重试调度, 直到有节点满足条件.经过这个步骤,如果有多个节点满足条件, 就继续Priority过程: 按照优先级大小对节点排序.
优先级由一系列键值对组成, 键是该优先级项的名称, 值是他的权重. 优先级选项包括:
- leastRequestedPriority: 通过计算CPU和Memory的使用率来决定权重, 使用率越低权重越高.这个优先级指标倾向于资源使用比例更低的节点.
- BalancedResourceAllocation: 节点上CPU和Memory使用率越接近, 权重越高. 这个应该和leastRequestedPriority一起使用, 不应该单独使用
- ImageLocalityPriority: 倾向于已经有要使用镜像的节点, 镜像总大小值越大, 权重越高
自定义调度器
除了Kubernetes自带的调度器, 也可以编写自己的调度器.通过spec.schedulername参数指定调度器的名字, 可以为Pod选择某个调度器进行调度.比如下面pod选择my-scheduler进行调度,而不是默认的default-scheduler
apiVersion: v1
kind: Pod
metadata:
name: annotation-second-scheduler
labels:
name: multischeduler-example
spec:
schedulername: my-scheduler
containers:
- name: pod-with-second-annotation-container
image: gcr.io/google_containers/pause:2.0
调度亲和性
Node亲和性
pod.spec.nodeAffinity
- preferredDuringSchedulingIgnoredDuringExecution: 软策略
- requiredDuringSchedulingIgnoredDuringExecution: 硬策略
apiVersion: v1 kind: Pod metadata: name: node-affinity namespace: test spec: containers: - name: nginx-pod image: nginx:latest affinity: # 节点亲和 nodeAffinity: # 硬策略,条件必须成立 requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: # 要调度到node的标签是kubernetes.io/hostname=k8s-node01的节点上 - matchExpressions: - key: kubernetes.io/hostname operator: In values: - k8s-node01 # 软策略,条件尽量要成立 preferredDuringSchedulingIgnoredDuringExecution: # 多个软策略的权重,范围在1-100内,越大计算的得分越高 - weight: 1 preference: matchExpressions: # 要调度到node的标签是area=beijing的节点上 - key: area operator: In values: - beijing
键值运算关系
- In : label的值在某个列表中
- NotIn: 不在某个列表中
- Gt: 大于
- Lt: 小于
- Exists: 某个label存在
-
Pod亲和性
pod.spec.affinity.podAffinity/podAntiAffinity
preferredDuringSchedulingIgnoredDuringExecution: 软策略
- requiredDuringSchedulingIgnoredDuringExecution: 硬策略
pod亲和常用于避免相同类型的pod调度相同的节点上。
apiVersion: v1
kind: Pod
metadata:
name: pod-affinity
namespace: test
spec:
containers:
- name: nginx-pod
image: nginx:latest
affinity:
# pod亲和 要求与指定的pod在同一个拓扑域
podAffinity:
# 硬策略
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx01
# 拓扑域(node上的标签key)
topologyKey: kubernetes.io/hostname
# pod亲和 要求与指定的pod不在同一个拓扑域
podAntiAffinity:
# 软策略
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx01
# 拓扑域(node上的标签key)
topologyKey: kubernetes.io/hostname
亲和性/反亲和性调度策略比较
调度策略 | 匹配标签 | 操作符 | 拓扑域支持 | 调度目标 |
---|---|---|---|---|
nodeAffinity | 主机 | In, NotIn, Exists, DoesNotExists, Gt, Lt | 否 | 指定主机 |
podAffinity | Pod | In, NotIn, Exists, DoesNotExists | 是 | Pod与指定Pod同一拓扑域 |
podAntiAffinity | Pod | In, NotIn, Exists, DoesNotExists | 是 | Pod与指定Pod同一拓扑域 |
污点与容忍
Taint和Toleration
节点亲和性, 是Pod的一种属性(偏好或硬性要求), 他使Pod被吸引到一类特定的节点. Taint则相反, 他使节点能够排斥一类特定的Pod
Taint和toleration相互配合, 可以用来避免Pod被分配到不合适的节点上. 每个节点上都可以应用一个或多个taint, 这表示对于那些不能容忍这些Taint的Pod, 是不会被该节点接受的. 如果将toleration应用于Pod上, 表示这些Pod可以(但不要求)被调度到具有匹配taint的节点上
污点(Taint)
通过kubctl taint命令可以给某一个node节点设置污点,node上设置了污点之后,可以上node拒绝pod的调度,甚至可以将node上已经存在的pod驱逐出去。
污点可以用于集群节点迁移准备工作,通过打污点来使当前节点上的pod迁移出去。k8s 的master节点自带污点。
污点的组成为key=value:effect,effect有以下三个选项:
- NoSchedule:k8s不会把pod调度到该节点上
- PreferNoSchedule:k8s尽量不会把pod调度到该节点上
- NoExecute:k8s不会把pod调度到该节点上,同时会把已有节点驱逐出去
管理 taints
查看
kubectl describe node master
设置/删除 ```shell
设置污点
kubectl taint nodes k8s-node01 key1=value1:NoSchedule
节点说明中, 查找Taints字段
kubectl describe pod pod-name
去除污点
kubectl taint node k8s-node01 key1:NoSchedule- # 这里的key可以不用指定value kubectl taint node k8s-node01 key1:NoExecute- kubectl taint node k8s-node01 key1- # 删除指定key所有的effect kubectl taint node k8s-node01 key2:NoSchedule-
<a name="P9BZ2"></a>
## 容忍(Toleration)
**设置了污点的Node将根据Taint的effect: NoSchedule、PreferNoSchedule、NoExecute和Pod之间产生互斥的关系, Pod将在一定程度上不会被调度到Node上. 但我们可以在Pod上设置容忍(toleration), 意思是设置了容忍的Pod将可以容忍污点的存在, 可以被调度到存在污点的Node上**
pod.spec.tolerations
```yaml
tolerations:
- key: "key1"
operator: " Equal"
value: "value1"
effect: "NoSchedule"
tolerationSeconds: 3600
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
- key: "key2"
operator: "Exists"
effect: "NoSchedule"
- 其中key,vaule,effect要与Node中设置的taint保持一致
- operator 的值为Exists将会忽略value值
- tolerationSeconds 用于描述当Pod需要被驱逐时可以在Pod上继续保留运行的时间
k8s的namespace可以提供资源的逻辑隔离,但是无法提供物理隔离。物理隔离可以通过污点与容忍来做。
比如想隔离不同产品线的服务,可以提前给node打上不同的污点,不同的产品线的pod容忍对应的污点即可。
当不指定key值时, 表示容忍所有的污点key
toleration:
- operator: "Exists"
当不指定effect值时, 表示容忍所有的污点作用
toleration:
- key: "key"
operator: "Exists"
有多个Master存在时, 防止资源浪费, 可以设置
kubectl taint nodes Node-Name node-role.kubernetes.io/master=:PreferNoSchedule
固定节点调度
pod.spec.nodeName将Pod直接调度到指定的Node节点上, 会跳过Scheduler的调度策略, 匹配规则是强制匹配
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: myweb
spec:
replicas: 7
template:
metadata:
labels:
app: myweb
spec:
nodeName: k8s-node01
containers:
- name: myweb
image: nginx
ports:
- containerPort: 80
pod.spec.nodeSelector: 通过Kubernetes的label-selector机制选择节点, 由调度器策略匹配label, 而后调度pod到目标节点, 该匹配规则属于强制约束
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: myweb1
spec:
replicas: 5
template:
metadata:
labels:
app: myweb1
spec:
nodeSelector:
disk: ssd
containers:
- name: myweb
image: nginx
ports:
- containerPort: 80
没有Node上有disk=ssd的标签, pod找不到调度的节点, 一直处于pending状态
kubectl label node k8s-node01 disk=ssd