节点亲和性是节点和POD之间的关系,那些POD可以运行在那些节点上,那些POD不可以运行在那些节点上。POD亲和性是POD之间的关系,那些POD不能运行在同一个节点上,那些可以运行在同一个节点上。


requiredDuringSchedulingIgnoredDuringExecution:硬限制

preferredDuringSchedulingIgnoredDuringExecution:软限制

nodeAffinity:Pod愿意在某个节点上。

nodeAntiAffinity:Pod不愿意在某个节点上。

podAffinity:Pod愿意在一起(同样一个节点/机架)。

podAntiAffinity:Pod不愿意在一起。

topologySpreadConstraints:打散调度,不让相同Pod在同一个节点。


预选函数中SelectorSpreadPriority会自动做选择。


nodeSelector与nodeAffinity是与关系。



节点亲和性 nodeAffinity:

        根据匹配到的条目的权重相加,匹配到的越多亲和性越高。

必须要符合定义的要求:

apiVersion: v1
kind: Pod
metadata:
  name: node-affinity-required
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: myapp:v1
  affinity: 
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
        nodeSelectorTerms: # 节点选择条件,定义多个nodeSelectorTerms是“或”关系
        - matchExpressions: # 标签选择器,多个matchExpressions 是“或”关系
          - key: zone # 需要有zone这个标签存在,多个key是“与”关系
            operator: In # 基于集合的标签选择器类似in_array
            values: # 二者之一符合条件即可
            - foo
            - bar
      preferredDuringSchedulingIgnoredDuringExecution: # 软限制
      - preference: # 定义倾向性
          matchExpressions: # 标签选择
          - key: zone # 有这个标签名称
            operator: In # 集合类型的选择器
            values: # 有这些标签的节点运行在这些节点,如果没有再选择其他的节点
            - foo
            - bar
        weight: 60 # 权重
        
        # 先检查硬性限制,如果硬性限制有多节点符合条件,再检查软性限制

补充:

preferredDuringSchedulingIgnoreDuringExecution:软亲和性;不管节点上能否满足设定条件,Pod都可以被调度,只是Pod优先被调度到符合条件多的节点上。
- preference:# 与相应权重相关联的节点选择器项。
    matchExpressions:# 按节点标签列出的节点选择器要求列表
    - key:     # 键
      operator:# 表示键与一组值的关系。有效的运算符有:In、NotIn、Exist、DoesNotExsit。GT和LT
      values:  # 值;若operator为In或NotIn则值必须为非空;若operator为Exists或DoesNotExist则值必须为空;若operator为Gt或Lt则值必须有一个元素。
    matchFields:# 按节点字段列出的节点选择器要求列表
    - key:     # 键
      operator:# 表示键与一组值的关系。有效的运算符有:In、NotIn、Exist、DoesNotExsit。GT和LT
      values:  # 值;若operator为In或NotIn则值必须为非空;若operator为Exists或DoesNotExist则值必须为空;若operator为Gt或Lt则值必须有一个元素。
  weight:      # 权重,0~100的数值

不必完全符合定义的要求,符合最好:

apiVersion: v1
kind: Pod
metadata:
  name: node-affinity-preferred
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: myapp:v1
  affinity: 
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution: # 软亲和性
      - preference: # 定义倾向性
          matchExpressions: # 标签选择
          - key: zone # 有这个标签名称
            operator: In
            values: # 有这些标签的节点运行在这些节点,如果没有再选择其他的节点
            - foo
            - bar
        weight: 60 # 权重


Pod亲和性 podAffinity:

让后面的Pod跟着前一个Pod运行在同一个节点上,使用标签控制。

apiVersion: v1
kind: Pod
metadata:
  name: pod-first
  namespace: default
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: myapp:v1
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-second
  namespace: default
  labels:
    app: backend
    tier: db
spec:
  containers:
  - name: nginx
    image: nginx:v1
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions: 
          - key: app
            operator: In
            values: 
            - myapp  # 让后一个Pod运行在和第一个Pod相同的节点上
        topologyKey: kubernetes.io/hostname   #根据节点的主机名

上面的两个Pod会运行在同一个节点上。


反亲和性 podAntiAffinity:

让后面的Pod不能和前一个Pod运行在同一个节点上,根据标签来判定。

apiVersion: v1
kind: Pod
metadata:
  name: pod-first
  namespace: default
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: myapp:v1
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-second
  namespace: default
  labels:
    app: backend
    tier: db
spec:
  containers:
  - name: nginx
    image: nginx:v1
  affinity:
    podAntiAffinity:  # 使用的是 podAntiAffinity
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions: 
          - key: app
            operator: In
            values: 
            - myapp
        topologyKey: kubernetes.io/hostname

上面的两个Pod不会运行在同一个节点上。


方法二:节点上打上标签,根据节点标签来验证反亲和性。

节点打标签:

kubectl label nodes node1 zone=foo
kubectl label nodes node2 zone=foo

yaml:

apiVersion: v1
kind: Pod
metadata:
  name: pod-first
  namespace: default
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: myapp:v1
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-second
  namespace: default
  labels:
    app: backend
    tier: db
spec:
  containers:
  - name: nginx
    image: nginx:v1
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions: 
          - key: app
            operator: In
            values: 
            - myapp
        topologyKey: zone


字段选择matchFields:区别在于上面的选择的是label,这里选择的是字段。

nodeAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
    nodeSelectorTerms:
    - matchFields:
      - key: metadata.name # k8s资源中的字段
        operator: In
        values:
        - target-host-name

参考:

https://www.cnblogs.com/Smbands/p/10949478.html


打散调度topologySpreadConstraints:

apiVersion: apps/v1
kind: Deploymentmetadata:
  name: nginxspec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: kubernetes.io/hostname
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
        - matchLabels:
            app: nginx
      containers:
      - name: nginx
        image: nginx

将所有 nginx 的 Pod 严格均匀打散调度到不同节点上,不同节点上 nginx 的副本数量最多只能相差 1 个,如果有节点因其它因素无法调度更多的 Pod (比如资源不足),那么就让剩余的 nginx 副本 Pending

更多用法:

imroc.cc/k8s/ha/pod-split-up-scheduling/
kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/