0、简介

k8s对于pod的调度有如下几种:按node名称、按标签、节点亲和、pod亲和

1、使用nodeName指定节点

场景:
pod需要部署到指定节点。
方案:

[root@vmroot schedule-yamls]# cat schedule-deloyment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name:  scdl-d
spec:
  selector:
    matchLabels:
      app: scdl-d
  replicas: 3
  template:
    metadata:
      labels:
        app: scdl-d
    spec:
      nodeName: cloudk8sn1				#通过节点名称指定pod目标节点
      containers:
      - name:  scdl-d
        image:  alpine:latest
        command: ['sh', '-c', 'sleep 3600']
      restartPolicy: Always

全部pod都已调度到指定节点
在这里插入图片描述

2、标签选择

与直接选择节点相比,标签名称更有意义,且标签选择类似群组的功能,可以对多个节点打相同标签,集群节点变更时方便修改,不需要修改pod的yaml。
场景:
节点cloudk8sn1是ssd硬盘,其它节点是机械硬盘
要求:应用调度到ssd节点上
方案:

[root@vmroot schedule-yamls]# kubectl label node cloudk8sn1 disktype=ssd    #添加标签
[root@vmroot schedule-yamls]# kubectl label node cloudk8sn1 disktype-    #移除标签

在这里插入图片描述

部署pod,选择含disktype=ssd标签的节点。

[root@vmroot schedule-yamls]# cat schedule-deloyment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name:  scdl-d
spec:
  selector:
    matchLabels:
      app: scdl-d
  replicas: 3
  template:
    metadata:
      labels:
        app: scdl-d
    spec:
      nodeSelector:
        disktype: ssd		#这里指定标签名称
      containers:
      - name:  scdl-d
        image:  alpine:v1
        command: ['sh', '-c', 'sleep 3600']
      restartPolicy: Always

全部pod部署到了含disktype=ssd的节点上,如果有新ssd节点加入集群,只需为新节点打上disktype=ssd标签,不需要改yaml文件
在这里插入图片描述

3、亲和与反亲和

相对于节点标签选择,有以下优点:
● 支持多种匹配表达式,不只是全名称精确匹配
● 支持required必须满足和preferred倾向满足,不只是必须满足
● 匹配对象除了node标签还支持pod标签
● 分为亲和与反亲和

1–node亲和

属于节点标签选择的升级版,功能依旧是pod对打了标签node的一种选择决策
亲和性限制方式有以下两种:
①requiredDuringSchedulingIgnoredDuringExecution:必须满足(也叫硬亲和),效果与节点标签选择一样,pod不会调度到不满足条件的节点。且必须与nodeSelector同时满足
②preferredDuringSchedulingIgnoredDuringExecution:更倾向满足(也叫软亲和),pod如果没得选也会被调度到不满足条件的节点上(IgnoredDuringException表示忽略pod运行期间node标签变化导致亲和性不满足)

场景:
节点cloudk8sn1和cloudk8sn2都是固态硬盘,vmroot是机械硬盘,cloudk8sn2是ddr4的内存
要求1:应用必须部署到ssd硬盘的节点上(必须满足requiredDuringSchedulingIgnoredDuringExecution)
要求2:应用尽量部署到ddr4的节点上(倾向满足preferredDuringSchedulingIgnoredDuringExecution)
方案:

①为节点打标签

[root@vmroot schedule-yamls]# kubectl label nodes cloudk8sn1 disktype=ssd
[root@vmroot schedule-yamls]# kubectl label nodes cloudk8sn2 disktype=ssd
[root@vmroot schedule-yamls]# kubectl label nodes cloudk8sn2 memtype=ddr4

查看标签
在这里插入图片描述

②配置亲和性

[root@vmroot schedule-yamls]# cat schedule-deloyment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name:  scdl-d
spec:
  selector:
    matchLabels:
      app: scdl-d
  replicas: 10
  template:
    metadata:
      labels:
        app: scdl-d
    spec:
      affinity:			#从里开始写亲和
        nodeAffinity:	#节点亲和(根据实际情况也可以配置反亲和)
          requiredDuringSchedulingIgnoredDuringExecution:    #必须满足的亲和
            nodeSelectorTerms:		#可以写多个nodeSelectorTerms,其中一个满足即可
            - matchExpressions:    	#可以写多个matchExpressions,但必须全满足才行
              - key: disktype    	#标签的key
                operator: In	#匹配方式,还有NotIn、Exists、DoesNotExist、Gt 和 Lt 可选
                values:    
                - ssd    #标签的value,可以匹配多个
          preferredDuringSchedulingIgnoredDuringExecution:    #倾向的亲和
          - weight: 1               #取值范围1-100,当有多个倾向条件时按优先级匹配
            preference:
              matchExpressions:
              - key: memtype
                operator: In
                values:
                - ddr4
      containers:
      - name:  scdl-d
        image:  alpine:v1
        command: ['sh', '-c', 'sleep 3600']
      restartPolicy: Always

如果你同时指定了 nodeSelector 和 nodeAffinity,两者 必须都要满足, 才能将 Pod 调度到候选节点上。
如果你指定了多个与 nodeAffinity 类型关联的 nodeSelectorTerms, 只要其中一个 nodeSelectorTerms 满足的话,Pod 就可以被调度到节点上。
如果你指定了多个与同一 nodeSelectorTerms 关联的 matchExpressions, 则只有当所有 matchExpressions 都满足时 Pod 才可以被调度到节点上。

可以看到,由于节点软亲和的存在,更多的pod调度到了cloudk8sn2节点

在这里插入图片描述

2–pod亲和

属于node亲和的升级版,不再是pod选择含标签的node,而是选择含标签pod所在的node,比较损耗性能,用于pod对pod的约束
名称分别是podAffinity 和 podAntiAffinity,其它和node亲和一样

①场景1:

有个项目名为zyz,由前端web和后端java两个服务组成,客户位于香港。当前集群节点vmroot 和cloudk8sn1 在香港,cloudk8sn2在哈尔滨
要求1:项目必须部署到位于香港的节点vmroot或cloudk8sn1(node硬亲和或节点标签选择)
要求2:后端必须调度到有前端的节点,减少通讯损耗(pod硬亲和)
要求3:后端尽量不要调度到cloudk8sn1,因为该节点运行着一个大型的应用(pod软反亲和)
场景模拟:
为节点打标签

[root@vmroot schedule-yamls]# kubectl label nodes vmroot zone=hongkong
[root@vmroot schedule-yamls]# kubectl label nodes cloudk8sn1 zone=hongkong
[root@vmroot schedule-yamls]# kubectl taint node vmroot node-role.kubernetes.io/master-			#去除master污点

在cloudk8sn1节点部署一个含property=large标签的pod
在这里插入图片描述
方案:
1)写前端yaml,没用到亲和

[root@vmroot schedule-yamls]# cat zyz-web.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name:  zyz-web
spec:
  selector:
    matchLabels:
      appname: zyz-web
  replicas: 2
  template:
    metadata:
      labels:
        appname: zyz-web	#定义标签
    spec:
      nodeSelector:
        zone: hongkong		#节点标签选择
      containers:
      - name:  zyz-web
        image:  alpine:v1
        command: ['sh', '-c', 'sleep 3600']
      restartPolicy: Always
[root@vmroot schedule-yamls]# kubectl apply -f zyz-web.yaml

2)写后端yaml

[root@vmroot schedule-yamls]# cat zyz-java.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name:  zyz-java
spec:
  selector:
    matchLabels:
      appname: zyz-java
  replicas: 3
  template:
    metadata:
      labels:
        appname: zyz-java
    spec:
      affinity:		#从里开始写亲和
        podAffinity:	#pod亲和
          requiredDuringSchedulingIgnoredDuringExecution:		#必须调度到含appname=zyz-web标签的pod的节点上(pod的标签)
          - labelSelector:
              matchExpressions:
              - key: appname
                operator: In
                values:
                - zyz-web
            topologyKey: zone		#topologyKey字段表示:被调度的节点必须含有key为zone的标签(node的标签)
        podAntiAffinity:	#pod反亲和
          preferredDuringSchedulingIgnoredDuringExecution:		#尽量不要调度到含有property=large标签的pod的节点上(pod标签)
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: property
                  operator: In
                  values:
                  - large
              topologyKey: kubernetes.io/hostname    #这个字段必须写,没什么写的就写hostname,因为每个节点都有hostname这个标签
      containers:
      - name:  zyz-java
        image:  alpine:v1
        command: ['sh', '-c', 'sleep 3600']
      restartPolicy: Always
[root@vmroot schedule-yamls]# kubectl apply -f zyz-java.yaml

效果为:尽量调度到vmroot节点;绝不调度到couldk8sn2节点
注意:不能两个pod写相互硬亲和,这样pod都是pending状态
在这里插入图片描述
*对于topologyKey字段,经测试只要求节点含有指定的key,value可以为任意。官网示例的解释为“调度器必须将 Pod 调度到具有 topology.kubernetes.io/zone=V 标签的节点上”

②场景2:

对于场景①,可以把property=large这个标签打给cloudk8sn1然后用节点亲和,就不需要使用pod反亲和。接下来这个场景很好的体现了pod反亲和的用途
要求:
多个nginx部署到固态硬盘的节点上且尽量分散,达到高可用的效果
准备:
清除之前的环境(略),现在vmroot和cloudk8sn2有disk=ssd的标签
方案:

[root@vmroot schedule-yamls]# cat nginxha.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginxha
spec:
  selector:
    matchLabels:
      appname: nginxha
  replicas: 3
  template:
    metadata:
      labels:
        appname: nginxha
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: disk    #必须部署到ssd的node
                operator: In
                values:
                - ssd
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: appname
                  operator: In
                  values:
                  - nginxha    #用自己的label做pod反亲和,互相排斥,达到分散目的
              topologyKey: kubernetes.io/hostname
      containers:
      - name:  nginxha
        image:  alpine:v1
        command: ['sh', '-c', 'sleep 3600']
      restartPolicy: Always
[root@vmroot schedule-yamls]# kubectl apply -f nginxha.yaml

在这里插入图片描述

pod尽量在分散部署,且不会部署到cloudk8sn1,如果节点多效果更清晰

4、参考:

https://www.jianshu.com/p/61725f179223
https://zhuanlan.zhihu.com/p/405150555
https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node/

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐