Kubernetes调度器亲和性

  • A+
所属分类:Kubernetes 容器技术

简介

一般情况下我们部署的 Pod 是通过集群的自动调度策略来选择节点的,默认情况下调度器考虑的是资源足够,并且负载尽量平均,但是有的时候我们需要能够更加细粒度的去控制 Pod 的调度。比如我们内部的一些服务 gitlab 之类的也是跑在Kubernetes集群上的,我们就不希望对外的一些服务和内部的服务跑在同一个节点上了,担心内部服务对外部的服务产生影响;但是有的时候我们的服务之间交流比较频繁,又希望能够将这两个服务的 Pod 调度到同一个的节点上。这就需要用到 Kubernetes 里面的一个概念:亲和性和反亲和性。

亲和性/反亲和性策略区别

node亲和性nodeAffinity

pod亲和性podAffinity

pod反亲和性podAntiAffinity


调度策略匹配标签 操作符拓扑域支持调度目标
nodeAffinitynodeIn, NotIn, Exists,DoesNotExist, Gt, Lt不支持决定pod部署在哪个node节点
podAffinityPODIn, NotIn, Exists,DoesNotExist支持决定pod可以和哪些pod部署在同一拓扑域
podAntiAffinityPODIn, NotIn, Exists,DoesNotExist支持pod不可以和哪些pod部署在同一拓扑域

什么是拓扑域?为什么node不支持?

podAffinity特性是Kubernetes 1.4后增加的,允许用户通过已经运行的Pod上的标签来决定调度策略,用文字描述就是“如果Node X上运行了一个或多个满足Y条件的Pod,那么这个Pod在Node应该运行在Pod X”,因为Node没有命名空间,Pod有命名空间,这样就允许管理员在配置的时候指定这个亲和性策略适用于哪个命名空间,可以通过topologyKey来指定。topology(拓扑域)是一个范围的概念,可以是一个Node、一个机柜、一个机房或者是一个区域(如北美、亚洲)等,实际上对应的还是Node上的标签。

键值运算关系

  • In:label 的值在某个列表中

  • NotIn:label 的值不在某个列表中

  • Gt:label 的值大于某个值

  • Lt:label 的值小于某个值

  • Exists:某个 label 存在

  • DoesNotExist:某个 label 不存在

软策略和硬策略区别

preferredDuringSchedulingIgnoredDuringExecution:软策略

软策略:没有满足要求的节点,Pod就会忽略,继续完成调度(不是必须,不满足的情况下会调度到其它不符合条件的node/pod)

requiredDuringSchedulingIgnoredDuringExecution:硬策略

硬策略:没有满足条件的节点,就不断重试,直到满足条件位置(必须满足,否则不进行调度)

示例:node硬策略

目标:pod不会被创建在标签hostname=k8s-04这台节点

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: affinity
  labels:
    app: affinity
spec:
  replicas: 3
  revisionHistoryLimit: 10
  template:
    metadata:
      labels:
        app: affinity
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - name: http
          containerPort: 80

      affinity:         #亲和性的调度设置
        nodeAffinity:   #策略为节点亲和性
          requiredDuringSchedulingIgnoredDuringExecution:      #亲和性的硬策略
            nodeSelectorTerms:   #这里不再使用nodeselector,使用这个参数可以进行相对简单的逻辑运算
            - matchExpressions:     #匹配表达式
              - key: kubernetes.io/hostname      #具体匹配规则(可以通过kubectl get node --show-labels找到相应规则)
                operator: NotIn  #不在,简单的来说就是不在k8s-04节点
                values:
                - k8s-04

示例:node软策略

目前我们有4个节点{1-4},但是我们希望pod不调度在k8s-01和k8s-02节点

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: affinity-preferred
  labels:
    app: affinity-preferred
spec:
  replicas: 3
  revisionHistoryLimit: 10
  template:
    metadata:
      labels:
        app: affinity-preferred
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - name: http
          containerPort: 80
      affinity:         #亲和性的调度设置
        nodeAffinity:   #策略为节点亲和性
          requiredDuringSchedulingIgnoredDuringExecution:  # 硬策略
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/hostname
                operator: NotIn
                values:
                - k8s-01
                - k8s-02
          preferredDuringSchedulingIgnoredDuringExecution:   #软策略
          - weight: 10    #权重, weight范围1-100。这个涉及调度器的优选打分过程
            preference:     #调度策略,而不是硬性的要求 (属于软策略的参数)
              matchExpressions:  #匹配表达式
                - key: kubernetes.io/hostname
                  operator: In
                  values:
                  - k8s-04
kubectl create -f pod.yaml && kubectl get pod -o wide && kubectl delete -f pod.yaml

反复测试,可以发现,因为加了软策略,所以并不是强制调度在K8s-04节点上,所以在03节点上也有。

示例:pod硬策略

创建一个标签为app=web01的Deployment

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: tomcat-test
  labels:
    app: web01
spec:
  replicas: 3
  revisionHistoryLimit: 10
  template:
    metadata:
      labels:
        app: web01
    spec:
      containers:
      - name: tomcat
        image: tomcat
        ports:
        - name: http
          containerPort: 8080

查看pod标签

kubectl get pod -o wide --show-labels
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: nginx-test
  labels:
    app: nginx
spec:
  replicas: 3
  revisionHistoryLimit: 10
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - name: http
          containerPort: 8080
      affinity:
        podAffinity:        #pod亲和力参数
          requiredDuringSchedulingIgnoredDuringExecution:   #硬策略 (在podAffinity中也可以添加软策略和硬策略)
          - labelSelector:    #匹配label标签 (Pod具有的label标签,而不是Node的标签)
              matchExpressions:     #匹配规则
              - key: app         #对应的标签
                operator: In
                values:
                - web01         #对应的标签
            topologyKey: kubernetes.io/hostname

现在我们将Pod调度在app=web01所在的节点上,因为我们加了top域kubernetes.io/hostname,也就是当我们app=web01在哪个节点上,我们创建的pod就会追随到那个节点上。但是如果我们将topologyKey修改为kubernetes.io/os那么,所有的Pod都会在所有的节点上运行. 因为kubernetes.io/os是在所有节点都有的一个策略。

查看node标签

kubectl get node -o wide --show-labels|grep os

示例:pod反亲和

podAntiAffinity反亲和性大致意思是比如一个节点运行了某个Pod,那么我们希望我们的Pod调度到其他节点上去,保证不会有相同业务的Pod来分享节点资源。

应用场景:

  • 将一个服务的POD分散在不同的主机或者拓扑域中,提高服务本身的稳定性。

  • 给POD对于一个节点的独占访问权限来保证资源隔离,保证不会有其它pod来分享节点资源。

  • 把可能会相互影响的服务的POD分散在不同的主机上。

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: nginx-test-not
  labels:
    app: nginx
spec:
  replicas: 3
  revisionHistoryLimit: 10
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - name: http
          containerPort: 8080
      affinity:
        podAntiAffinity:  #修改为反亲和力,其他参数不变
          requiredDuringSchedulingIgnoredDuringExecution: 
          - labelSelector:  
              matchExpressions:    
              - key: app       
                operator: In
                values:
                - web01      
            topologyKey: kubernetes.io/hostname

创建后,因为标签为app=web01的节点上已经有k8s-01..k8s-03占用,只有k8s-04没有。所以这里会强制在k8s-04节点创建Pod


YaLei

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: