1.kubernetes调度介绍
调度器通过 kubernetes 的 watch 机制来发现集群中新创建且尚未被调度到 Node 上的 Pod。调度器会将发现的每一个未调度的 Pod 调度到一个合适的 Node 上来运行。
kube-scheduler 是 Kubernetes 集群的默认调度器,并且是集群控制面的一部分。如果你真的希望或者有这方面的需求,kube-scheduler 在设计上是允许你自己写一个调度组件并替换原有的 kube-scheduler。
在做调度决定时需要考虑的因素包括:单独和整体的资源请求、硬件/软件/策略限制、亲和以及反亲和要求、数据局域性、负载间的干扰等等。
默认策略可以参考:https://kubernetes.io/zh/docs/concepts/scheduling/kube-scheduler/
2.nodename节点选择约束
nodeName 是节点选择约束的最简单方法,但一般不推荐。如果 nodeName 在 PodSpec 中指定了,则它优先于其他的节点选择方法。
使用 nodeName 来选择节点的一些限制:
如果指定的节点不存在。
如果指定的节点没有资源来容纳 pod,则pod 调度失败。
云环境中的节点名称并非总是可预测或稳定的。
3.nodeSelector 亲和
nodeSelector 是节点选择约束的最简单推荐形式。给选择的节点添加标签,通过标签来进行调度。
3.1.节点亲和
创建目录并编写资源清单
vi pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
执行并查看状态
kubectl apply -f pod.yaml
kubectl get pod -o wide
成功运行的原因为我们的结点上有ssd的标签
kubectl get nodes --show-labels
节点亲和性pod示例
kubectl delete -f pod.yaml
vi pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: #必须满足
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
- fc
刚才的实验发现nginx pod在server3上则我们
将3上的标签去掉在执行查看
kubectl label nodes server3 disktype-
kubectl apply -f pod.yaml
kubectl get pod -o wide
发现被调度到server2
kubectl label nodes server3 disktype=ssd
将标签加回去后再次编辑pod.yaml
kubectl delete -f pod.yaml
vi pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
- fc
preferredDuringSchedulingIgnoredDuringExecution: #倾向满足
- weight: 1
preference:
matchExpressions:
- key: role
operator: In
values:
- prod
执行后再次查看 再次被调度回到server3
kubectl apply -f pod.yaml
kubectl get pod -o wide
3.2示例
保留前面的nginx pod
pod亲和,mysql容器亲和nginx pod
注意使用的mysql镜像版本为 image: mysql:5.7
仓库里需要有。
vi pod1.yaml
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: env ###通过kubectl get pod --show-labels找到
operator: In
values:
- test ##同上
topologyKey: kubernetes.io/hostname
执行清单pod2.yaml,查看信息
kubectl apply -f pod1.yaml
kubectl get pod -o wide
pod反亲和
vi pod1.yaml
podAntiAffinity:
执行查看
我们可以看到mysql节点并不在nginx服务的同个节点上,实现服务与数据分离,被调度到server2。
4.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设置,会直接被逐出。
如Kubernetes集群主机,就是被设置了污点,因此一般部署pod时候不选择该节点为部署节点matser的污点 的信息为:
kubectl describe nodes server1 | grep Taints
Taints: node-role.kubernetes.io/master:NoSchedule
4.1添加污点
4.1.1 NoSchedule
kubectl taint node server3 k1=v1:NoSchedule
kubectl delete -f pod.yaml
kubectl apply -f pod.yaml
kubectl get pod -o wide
发现原本在server3运行的pod 运行不了了
4.1.2 .NoExecute
创建一个控制器
vi deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
# tolerations:
#- operator: "Exists"
添加NoExecute:
该选项意味着一旦 Taint 生效,如该节点内正在运行的 POD 没有对应 Tolerate 设置,会直接被逐出。被驱逐到其他node节点。
kubectl taint nodes server2 key=value:NoExecute
因为没有容忍及其他node所有pod全部pending
我们如果去掉server3的污点则会全部调度到srever3中
kubectl taint node server3 k1=v1:NoSchedule-
kubectl get pod -o wide
4.2添加容忍
本来server1是不加入集群的,我们现在设置让他加入集群中
我们来测试:
vi deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
selector:
matchLabels:
app: nginx
replicas: 30 #数量太小server1调度的几率小
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
tolerations:
- operator: "Exists" ##容忍万物
删除执行查看
kubectl delete -f deployment.yaml
kubectl apply -f deployment.yaml
kubectl get pod -o wide
发现有server1
4.3cordon、drain、delete
影响Pod调度的指令还有:cordon、drain、delete,后期创建的pod都不会被调度到该节点上,但操作的暴力程度不一样。
cordon 停止调度:
影响最小,只会将node调为SchedulingDisabled,新创建pod,不会被调度到该节点,节点原有pod不受影响,仍正常对外提供服务。
drain 驱逐节点:
首先驱逐node上的pod,在其他节点重新创建,然后将节点调为SchedulingDisabled。
delete 删除节点
最暴力的一个,首先驱逐node上的pod,在其他节点重新创建,然后,从master节点删除该node,master失去对其控制,如要恢复调度,需进入node节点,重启kubelet服务
vi deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
selector:
matchLabels:
app: nginx
replicas: 6
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
执行查看调度节点
kubectl apply -f deployment.yaml
kubectl get pod -o wide
4.3.1 cordon
关闭server3的集群调度
kubectl cordon server3
kubectl get pod -o wide
kubectl get node
全部被驱逐到server2
重新server3的调度
kubectl uncordon server3
kubectl get node
4.3.2 drain
kubectl drain server2 --ignore-daemonsets
server2里的东西全部被调度走别的节点
kubectl get node
kubectl uncordon server2
重启
4.3.3 delete
直接删除掉节点server3
kubectl delete node server3
将server3重新加入调度node节点
需要在server3上重启kubelet服务
server3:
systemctl restart kubelet
server1:
kubectl get node
5. 添加新的集群node
因为token只会存在23小时,所以需要重新创建
kubeadm token create
kubeadm token list
还需要token-cert-hash:
这个值不会变化,查出来即可
openssl x509 -pubky -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubinoutform der 2>/dev/null | \
openssl dgst -sha256 -hex | sed 's/^.* //'
然后用下述指令加入集群
kubeadm join 172.25.0.2:6443 --token ******** --discovery-token-ca-cert-hash sha256:*******************