Tip
- kube-scheduler负责调度Pod到集群内的节点上,它监听kube-apiserver,查询还未分配Node的Pod
- 然后根据调度策略为这些Pod分配节点(最终体现为更新Pod的spec.nodeName字段)
pkg/scheduler/scheduler.go#New
snapshot := internalcache.NewEmptySnapshot()
1 nodeName
Important
直接指定节点名字,跳过调度器, 实际就没有走调度流程
2 nodeSelector
Tip
直接通过键值对将Pod调度到具有特定label的Node上
3 Affinity
3.1 基础介绍
Tip
- 亲和: 亲近
- requiredDuringSchedulingIgnoredDuringExecution 硬亲和
- requiredDuringScheduling
- 调度时必须满足, 比如你设置了想要调度到有标签是app=web的节点,那么节点上必须有这样的标签
- IgnoredDuringExecution
- 执行时忽略, 比如你pod已经调度完在节点上运行了, 然后现在将节点上的标签app=web 删除了, 那么不会影响这个pod
- requiredDuringScheduling
- preferredDuringSchedulingIgnoredDuringExecution 软亲和
- preferredDuringScheduling
- 调度时最好满足, 首选这样的节点.
- IgnoredDuringExecution
- 同硬亲和
- preferredDuringScheduling
3.2 节点亲和性
Tip
- NodeSelector 的升级版,也是用labels来约束, 支持更丰富的配置规则,使用更灵活
- 如果
nodeSelector和nodeAffinity两者都指定,那 node 需要两个条件都满足,pod 才能调度
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
affinity:
nodeAffinity:
1 requiredDuringSchedulingIgnoredDuringExecution:
2 nodeSelectorTerms:
3 - matchExpressions:
- key: disk-type
4 operator: In
values:
- ssd
5 preferredDuringSchedulingIgnoredDuringExecution:
6 - weight: 1
7 preference:
matchExpressions:
- key: label-1
operator: In
values:
- key-1
- weight: 50
preference:
matchExpressions:
- key: label-2
operator: In
values:
- key-2
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent- 1
- 硬亲和力配置,必须符合
- 2
- 节点选择器配置, 可以配置多个matchExpressions,满足一个即可
- 3
- 可以配置多个key, 必须都满足
- 4
- 这里表示节点必须包含键名为 disk-type 的标签,并且其值为ssd
- 5
- 软亲和力配置,表示最好符合
- 6
- 软亲和力的权重, 权重越高优先级越大,范围1-100
- 7
- 软亲和力配置项,和weight同级
如果存在两个候选节点,都满足 requiredDuringSchedulingIgnoredDuringExecution 规则,其中一个节点具有标签 label-1:key-1,另一个节点具有标签 label-2:key-2, 调度器会考察各个节点的 weight 取值,并将该权重值添加到节点的其他得分值之上
3.3 pod间 亲和性和反亲和性
Tip
- PodAffinity : 想要和含有某些标签的pod 部署在”一起” (一个topology中)
- podAntiAffinity: 与PodAffinity 相反
什么是topologyKey
- 拓扑域,主要针对节点进行区域的划分,比如服务器有华东区这类的,{==用节点的label进行判断==},key相同且value也相同才是属于同一个的拓扑域
- 对于 Pod 亲和性而言,在 requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution 中,topologyKey 不允许为空
- 对于 requiredDuringSchedulingIgnoredDuringExecution 要求的 Pod 反亲和性, 准入控制器 LimitPodHardAntiAffinityTopology 要求 topologyKey 只能是 kubernetes.io/hostname. 如果你希望使用其他定制拓扑逻辑,你可以更改准入控制器或者禁用之
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis-cache
spec:
selector:
matchLabels:
app: store
replicas: 3
template:
metadata:
labels:
app: store
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- store
topologyKey: "kubernetes.io/hostname"
containers:
- name: redis-server
image: redis:3.2-alpine- 反亲和性规则表示: Pod 不能被调度到这样的节点(集群/域)中
- 具有标签
kubernetes.io/hostname=xxx的节点们(集群),或说在这样一个名字叫kubernetes.io/hostname=xxx的域中 - 且 集群(或域)中至少有一个节点运行着一个带有 app=store 标签的 Pod
- 具有标签
- 首先第一个redis副本, 因为现在虽然每个节点都有kubernetes.io/hostname的标签,但是没有运行着 app=store标签 的pod,所以随便选一个节点部署第一个redis副本,比如node1
- 部署第一个redis副本后, 这个时候出现了这样的节点
- 运行着带有 app=store 标签的 Pod,且节点具有标签kubernetes.io/hostname=node1
- 部署第二个redis副本, 这个时候发现 node1 是不符合的, 因为有 app=store 的pod 且节点有标签是kubernetes.io/hostname,那么就在其他节点上随便选一个
- 部署第三个同理, 这样就会将3个redis 部署到不同的节点上去了.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
selector:
matchLabels:
app: web-store
replicas: 3
template:
metadata:
labels:
app: web-store
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web-store
topologyKey: "kubernetes.io/hostname"
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- store
topologyKey: "kubernetes.io/hostname"
containers:
- name: web-app
image: nginx:1.16-alpine- 现在我们可以马上理解,根据反亲和性规则 ,它们3个副本肯定会部署到不同的节点上
- 接着根据亲和性规则: pod要被调度到这样的节点(集群/域)中
- 具有标签
kubernetes.io/hostname=xxx的节点们(集群),或说在这样一个名字叫kubernetes.io/hostname=xxx的域中 - 且 集群(或域)中至少有一个节点运行着一个带有
app=store标签的 Pod
- 具有标签
- 根据前面的redis副本, 现在3个节点是 有
app=store标签的pod运行,然后节点标签具有kubernetes.io/hostname=xxx,它们符合亲和性规则 - 第一个副本随机选择一个 redis所在的节点, 然后第二个根据反亲和会选择另外一个 redis所在的节点, 第三个同理
最后的结果
| node-1 | node-2 | node-3 |
|---|---|---|
| web-server-1 | web-server-2 | web-server-3 |
| redis-cache-1 | redis-cache-2 | redis-cache-3 |
4 Taint与Toleration
4.1 基础介绍
Tip
- Taint: 污点
- Toleration: 容忍
- 原理:一旦某个节点被加上了一个Taint(理解为被打上了”污点”),那么正常情况下所有Pod都嫌这样的节点”脏”,都不会在这样的节点上运行
- 除非有个别的Pod声明自己能”容忍”这个”污点”,即声明了Toleration, 这样它可以在这个节点上运行
- Toleration是让Pod容忍节点上设置的污点Taint
- pod有容忍不是说你就会调度到有个污点的节点, 只是说你这个pod可以调度到有这个污点的节点
- 节点可以有多个污点, pod必须全部容忍这些污点才能够调度到该节点
Note
就像找男/女朋友, 不能容忍对方的缺点,pass, 可以容忍,ok
| Taint 效果(类型) | 解释 |
|---|---|
| NoSchedule |
|
| NoExecute |
|
| PreferNoSchedule |
|
4.2 污点操作命令
Important
key 和effect一起 才能表示 是否是同一个 污点
4.3 污点相关配置
4.3.1 内置污点
node.kubernetes.io/not-ready:节点未准备好,相当于节点状态Ready的值为False。
node.kubernetes.io/unreachable:Node Controller访问不到节点,相当于节点状态Ready的值为Unknown。
node.kubernetes.io/out-of-disk:节点磁盘耗尽。
node.kubernetes.io/memory-pressure:节点存在内存压力。
node.kubernetes.io/disk-pressure:节点存在磁盘压力。
node.kubernetes.io/network-unavailable:节点网络不可达。
node.kubernetes.io/unschedulable:节点不可调度。
node.cloudprovider.kubernetes.io/uninitialized:如果Kubelet启动时指定了一个外部的cloudprovider,它
将给当前节点添加一个Taint将其标记为不可用。在cloud-controller-manager的一个controller初始化这个 节点后,Kubelet将删除这个Taint。4.3.2 不可用多久才会被打上污点
/etc/kubernetes/manifests/kube-controller-manager.yaml 相关配置
- 1
- 添加这个 默认是40s, 表示40s 内一直不可用,就会被打上污点
- 2
- 5s会去探测一次节点是否可用
Caution
- 你的节点发生故障, pod需要等待40s+pod对污点的容忍时间tolerationSeconds
- 可以准备2个节点,将node1 关机, 查看
k get no看状态, 大概40s 才会看到 not_ready
4.4 pod默认容忍
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx:1.14.2
imagePullPolicy: IfNotPresent# 创建后
k get pod nginx2 -o yaml|grep tolerations: -iA 10
tolerations:
- effect: NoExecute
1 key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300- 1
- 节点没有ready时会打上这样的污点,在节点上的pod(被控制器管理的pod)默认会等待5m中才会被驱逐,重新调度
Caution
- 你可能会疑问, 出了问题, pod 5m后才会被重新调度, 是不是有点长了.
- 这个设置的原因是一般情况下节点是短暂的网络中断或临时故障,时间不会太长,这样做的目的是避免在节点暂时不可用的情况下频繁地驱逐和重建 Pod,以减少不必要的服务中断和资源浪费
4.5 pod容忍度操作命令
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
1 tolerationSeconds: 3600- 1
- 如果有这个设置,表示容忍这个节点3600s后,驱逐
Note
无需效果effect 匹配
4.6 问题答疑
指定有污点的nodeName的pod 会如何?
- 没有设置容忍的情况下,也会先创建pod,因为指定了nodeName就会跳过调度器,然后才会根据节点上污点的effect做相关行为
- 比如
- node1有 k=v:NoExecute, pod 设置nodeName=node1
- 通过describe pod 可以看到pod 创建 并Started , 后马上就被驱逐了(但是describe 看不到)
- 可以给pod 设置一个preStop sleep 20 这样可以看到…