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

k8s gpu 调度开发 k8s如何调度docker_k8s gpu 调度开发


成功运行的原因为我们的结点上有ssd的标签

kubectl get nodes --show-labels

k8s gpu 调度开发 k8s如何调度docker_docker_02


节点亲和性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

k8s gpu 调度开发 k8s如何调度docker_docker_03

发现被调度到server2

k8s gpu 调度开发 k8s如何调度docker_运维_04

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

k8s gpu 调度开发 k8s如何调度docker_kubernetes_05

3.2示例

保留前面的nginx pod

pod亲和,mysql容器亲和nginx pod

注意使用的mysql镜像版本为 image: mysql:5.7

仓库里需要有。

k8s gpu 调度开发 k8s如何调度docker_docker_06

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

k8s gpu 调度开发 k8s如何调度docker_kubernetes_07


pod反亲和

vi pod1.yaml

 podAntiAffinity:

k8s gpu 调度开发 k8s如何调度docker_运维_08

执行查看

k8s gpu 调度开发 k8s如何调度docker_k8s gpu 调度开发_09

我们可以看到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

k8s gpu 调度开发 k8s如何调度docker_docker_10

发现原本在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

k8s gpu 调度开发 k8s如何调度docker_nginx_11

我们如果去掉server3的污点则会全部调度到srever3中

kubectl taint node server3 k1=v1:NoSchedule-
kubectl get pod -o wide

k8s gpu 调度开发 k8s如何调度docker_nginx_12

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

k8s gpu 调度开发 k8s如何调度docker_kubernetes_13


发现有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

k8s gpu 调度开发 k8s如何调度docker_k8s gpu 调度开发_14

4.3.1 cordon

关闭server3的集群调度

kubectl cordon server3
kubectl get pod -o wide
kubectl get node

k8s gpu 调度开发 k8s如何调度docker_nginx_15

k8s gpu 调度开发 k8s如何调度docker_运维_16

k8s gpu 调度开发 k8s如何调度docker_运维_17

全部被驱逐到server2
重新server3的调度

kubectl uncordon server3
kubectl get node

k8s gpu 调度开发 k8s如何调度docker_docker_18

4.3.2 drain

kubectl drain server2 --ignore-daemonsets

k8s gpu 调度开发 k8s如何调度docker_nginx_19


server2里的东西全部被调度走别的节点

kubectl get node

k8s gpu 调度开发 k8s如何调度docker_运维_20

kubectl uncordon server2 重启

4.3.3 delete

直接删除掉节点server3
kubectl delete node server3

k8s gpu 调度开发 k8s如何调度docker_docker_21

将server3重新加入调度node节点
需要在server3上重启kubelet服务

server3:
systemctl restart kubelet
server1:
kubectl get node

k8s gpu 调度开发 k8s如何调度docker_kubernetes_22

5. 添加新的集群node

因为token只会存在23小时,所以需要重新创建

kubeadm token create

kubeadm token list

k8s gpu 调度开发 k8s如何调度docker_运维_23

还需要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/^.* //'

k8s gpu 调度开发 k8s如何调度docker_docker_24

然后用下述指令加入集群

kubeadm join 172.25.0.2:6443 --token ******** --discovery-token-ca-cert-hash sha256:*******************

k8s gpu 调度开发 k8s如何调度docker_k8s gpu 调度开发_25