kubernetes调度
调度器
调度器通过 kubernetes 的 watch 机制来发现集群中新创建且尚未被调度到 Node 上的 Pod。调度器会将发现的每一个未调度的 Pod 调度到一个合适的 Node 上来运行。
kube-scheduler 是 Kubernetes 集群的默认调度器,并且是集群控制面的一部分。kube-scheduler 在设计上是允许你自己写一个调度组件并替换原有的 kube-scheduler。
在做调度决定时需要考虑的因素包括:单独和整体的资源请求、硬件/软件/策略限制、亲和以及反亲和要求、数据局域性、负载间的干扰等等。
k8s调度
1.NodeName
NodeName 是节点选择约束的最简单方法,它优先于其他的节点选择方法。
缺点
如果指定的节点不存在。
如果指定的节点没有资源来容纳 pod,则pod 调度失败。
云环境中的节点名称并非总是可预测或稳定的。
2.nodeSelector
nodeSelector 是节点选择约束的最简单推荐形式。
给选择的节点添加标签:
kubectl label nodes server2 disktype=ssd
3.亲和与反亲和
nodeSelector 提供了一种非常简单的方法来将 pod 约束到具有特定标签的节点上。亲和/反亲和功能极大地扩展了你可以表达约束的类型。
你可以发现规则是“软”/“偏好”,而不是硬性要求,因此,如果调度器无法满足该要求,仍然调度该 pod
你可以使用节点上的 pod 的标签来约束,而不是使用节点本身的标签,来允许哪些 pod 可以或者不可以被放置在一起。
4.节点亲和
requiredDuringSchedulingIgnoredDuringExecution #必须满足
preferredDuringSchedulingIgnoredDuringExecution #倾向满足
节点亲合
创建目录、编写资源清单
[root@server2 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
拉起容器并查看,发现pod节点处于pending状态,且不在任意node上运行
为server3添加标签后,查看pod节点状态,发现运行在server3上
kubectl label nodes server3 disktype=ssd
kubectl get pod -o wide
删除标签后不会消失,因为容器已经运行
kubectl label nodes server3 disktype-
kubectl get node --show-labels
节点亲和性pod示例
vim pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: node-affinity
spec:
containers:
- name: nginx
image: nginx
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: #必须满足
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- server3
- server4
preferredDuringSchedulingIgnoredDuringExecution: #倾向满足
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
先注释掉倾向满足
[root@server2 schedu]# kubectl apply -f pod1.yaml
[root@server2 schedu]# kubectl get pod -o wide
发现亲合到server4
打开倾向满足,删除节点,重新拉起容器,还在server4
删除pod1.yaml
为server3增加标签ssd并重新拉起,发现运行在有标签的server3上
pod 亲和性和反亲和性
podAffinity 主要解决POD可以和哪些POD部署在同一个拓扑域中的问题(拓扑域用主机标签实现,可以是单个主机,也可以是多个主机组成的cluster、zone等。)
podAntiAffinity主要解决POD不能和哪些POD部署在同一个拓扑域中的问题。它们处理的是Kubernetes集群内部POD和POD之间的关系。
Pod 间亲和与反亲和在与更高级别的集合(例如 ReplicaSets,StatefulSets,Deployments 等)一起使用时,它们可能更加有用。可以轻松配置一组应位于相同定义拓扑(例如,节点)中的工作负载。
亲合
[root@server2 schedu]# vim pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
---
apiVersion: v1
kind: Pod
metadata:
name: mysql
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
env:
- name: "MYSQL_ROOT_PASSWORD"
value: "westos"
affinity:
podAffinity: #亲合
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname
[root@server2 schedu]# kubectl apply -f pod2.yaml
拉起并查看,nginx与mysql运行在同一node上
反亲和
[root@server2 schedu]# vim pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
---
apiVersion: v1
kind: Pod
metadata:
name: mysql
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
env:
- name: "MYSQL_ROOT_PASSWORD"
value: "westos"
affinity:
podAntiAffinity: #反亲合
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname
[root@server2 schedu]# kubectl apply -f pod2.yaml
拉起并查看,nginx与mysql运行在不同node上
Taints污点与容忍
NodeAffinity节点亲和性,是Pod上定义的一种属性,使Pod能够按我们的要求调度到某个Node上.
Taints污点则恰恰相反,它可以让Node拒绝运行Pod,甚至驱逐Pod。
Taints(污点)是Node的一个属性,设置了Taints后,所以Kubernetes是不会将Pod调度到这个Node上的,于是Kubernetes就给Pod设置了个属性Tolerations(容忍),只要Pod能够容忍Node上的污点,那么Kubernetes就会忽略Node上的污点,就能够(不是必须)把Pod调度过去。
可以使用命令 kubectl taint 给节点增加一个 taint:
$ kubectl taint nodes node1 key=value:NoSchedule //创建
$ kubectl describe nodes server1 |grep Taints //查询
$ kubectl taint nodes node1 key:NoSchedule- //删除
其中[effect] 可取值: [ NoSchedule | PreferNoSchedule | NoExecute ]
NoSchedule:POD 不会被调度到标记为 taints 节点。
PreferNoSchedule:NoSchedule 的软策略版本。
NoExecute:该选项意味着一旦 Taint 生效,如该节点内正在运行的 POD 没有对应 Tolerate 设置,会直接被逐出。
server2为k8s调度端,默认不参加集群调度
测试
1:Nodename可以无视任何污点
编辑资源清单创建pod,采用nodename指定node节点
[root@server2 schedu]# vim pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeName: server2
拉起容器,查看节点所在node为server2
kubectl apply -f pod.yaml
kubectl get pod -o wide
server2作为master且设置了污点,但是nodename可以无视污点。
测试完成删除测试pod
为server2设置标签,使用标签方式测试污点
kubectl label nodes server2 roles=master
kubectl get nodes --show-labels
编辑资源清单,使用标签方式选择node
[root@server2 schedu]# vim pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
roles: master
[root@server2 schedu]# kubectl apply -f pod.yaml
[root@server2 schedu]# kubectl get pod -o wide
拉起容器,发现pod处于pending,不能成功
测试证明,标签选择无法覆盖污点。
添加容忍
[root@server2 schedu]# vim pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
roles: master
tolerations:
- operator: "Exists"
effect: "NoSchedule"
添加容忍,NoSchedule:POD 不会被调度到标记为 taints 节点。
kubectl taint nodes server3 key=value:NoSchedule
server3上存在污点
kubectl describe nodes server3|grep Taint
注释容忍,拉起容器,发现容器在server4端运行,说明污点生效。
[root@server2 schedu]# vim pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
# nodeSelector:
# roles: master
# tolerations:
# - operator: "Exists"
# effect: "NoSchedule"
删除pod.yaml后,打开容忍,通过标签选择server3
[root@server2 schedu]# vim pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
tolerations:
- operator: "Exists"
effect: "NoSchedule"
完成后取消NoSchedule的值
kubectl taint node server3 key:NoSchedule-
NoExecute:该选项意味着一旦 Taint 生效,如该节点内正在运行的 POD 没有对应 Tolerate 设置,会直接被逐出。被驱逐到其他node节点。
kubectl taint nodes server3 key=value:NoExecute
测试完成,取消NoExecute的值
kubectl taint nodes server3 key:NoExecute-
关闭server3的所有调度
kubectl cordon server3
kubectl get node
重新开启server3的调度
kubectl uncordon server3
kubectl get node
关闭server3的调度,但不关闭部分必要pod
kubectl drain server3
kubectl get node
删除node
kubectl delete node server3
server3重新加入k8s集群
[root@server3 ~]# systemctl restart kubelet.service
控制端查看,server3加入集群
删除node的步骤为:先驱逐pod,再删除node。
拓展
当有新的node想加入k8s集群中,我们就需要生成新的token,注意,每一次生成的token只有24小时有效期
在控制端上生成token