K8S之运用亲和性设置Pod的调度约束
Pod 的yaml文件里 spec 字段中包含一个 affinity 字段,使用一组亲和性调度规则,指定pod的调度约束。
kubectl explain pods.spec.affinity 
 

配置说明
- nodeAffinity: node节点亲和性,pod倾向于哪个node
 - podAffinity: pod亲和性,pod倾向于哪个pod
 - podAntiAffinity: pod的反亲和性,pod排斥于哪个pod
 
Node节点亲和性
Node节点亲和性 是针对 pod和node 的关系,Pod调度到node节点的时候匹配的条件
node节点亲和性调度字段:nodeAffinity
看nodeAffinity下的配置字段
kubectl explain  pods.spec.affinity.nodeAffinity
 

- preferredDuringSchedulingIgnoredDuringExecution 表示有节点尽量满足这个位置定义的亲和性,这不是一个必须的条件,软亲和性
 - requiredDuringSchedulingIgnoredDuringExecution 表示必须有节点满足这个位置定义的亲和性,这是个硬性条件,硬亲和性
 
硬亲和实践
使用requiredDuringSchedulingIgnoredDuringExecution硬亲和性
Node节点硬亲和性选择匹配方式有2种:
- matchFields: 匹配字段的
 - matchExpressions:匹配表达式的 (用的多)
 
对matchExpressions做进一步解读
matchExpressions——匹配表达式的写法:
kubectl explain pods.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms.matchExpressions
 

字段配置:
- key:匹配节点标签的KEY(必填)
 - operator:表示键与一组值的关系(必填),可选的枚举值如下: 
  
- In (包含)
 - NotIn(不包含)
 - Exists (存在)
 - DoesNotExist (不存在)
 - Gt (大于)
 - Lt (小于)
 
 - values:给定值
 
示例 :把pod调度到集群中 拥有zone标签 并且值是foo或者bar的node节点上
创建pod资源文件
vim pod-nodeaffinity-demo.yaml
 
apiVersion: v1
kind: Pod
metadata:
  name:  pod-node-affinity-demo
  namespace: default
spec:
  affinity:     # 设置亲和性调度规则
    nodeAffinity:  # 设置node亲和性
     requiredDuringSchedulingIgnoredDuringExecution: # 使用硬亲和性
       nodeSelectorTerms: # 配置节点选择器规则
       - matchExpressions: # 匹配表达式的
         - key: zone  # 节点标签的key
           operator: In # 使用表达式为包含
           values:  # 包含的值有(foo或者bar)
           - foo
           - bar
  containers:
  - name: myapp
    image: docker.io/ikubernetes/myapp:v1
    imagePullPolicy: IfNotPresent
 
创建资源
kubectl apply -f pod-nodeaffinity-demo.yaml
 
查看pod
kubectl get pods -o wide
 

status的状态是pending,上面说明没有完成调度,因为没有一个节点拥有zone的标签
值是foo或者bar,而且使用的是硬亲和性,必须满足条件才能完成调度
给k8s-node1节点打上标签zone=foo,再查看
kubectl label nodes k8s-node1 zone=foo
 
kubectl get pods -o wide
 

pod调度到了k8s-node1节点上
软亲和性实践
使用preferredDuringSchedulingIgnoredDuringExecution软亲和性
示例
创建pod资源文件
vim pod-nodeaffinity-demo-2.yaml
 
apiVersion: v1
kind: Pod
metadata:
  name: pod-node-affinity-demo-2
  namespace: default
spec:
  containers:
  - name: myapp
    image: docker.io/ikubernetes/myapp:v1
    imagePullPolicy: IfNotPresent
  affinity:         # 设置亲和性调度规则
    nodeAffinity:   # 设置node亲和性
      preferredDuringSchedulingIgnoredDuringExecution: # 使用软亲和性
      - preference:
          matchExpressions: # 匹配表达式的
          - key: zone1   # 节点标签的key
            operator: In # # 使用表达式为包含
            values: # 包含的值有(foo1或者bar1)
            - foo1
            - bar1
        weight: 10 # 匹配度权重
      - preference:
          matchExpressions:
          - key: zone2
            operator: In
            values:
            - foo2
            - bar2
        weight: 20  #  weight是相对权重,权重越高,pod调度的几率越大
 
创建资源
kubectl apply -f pod-nodeaffinity-demo-2.yaml
 
查看pod
kubectl get pods -o wide |grep pod-node-affinity-demo-2
 

上面说明软亲和性是可以运行这个pod的,尽管没有运行这个pod的节点定义的zone1标签
测试weight权重
先删除pod-node-affinity-demo-2
 (ps. 执行强制删除的命令,加上“–force --grace-period=0”)
kubectl delete pod pod-node-affinity-demo-2 --force --grace-period=0
 
给k8s-node1和k8s-node2都打上标签
kubectl label nodes k8s-node1 zone1=foo1
kubectl label nodes k8s-node2 zone2=foo2
 
再创建资源
kubectl apply -f pod-nodeaffinity-demo-2.yaml
 
查看pod
kubectl get pods -o wide
 

pod在定义node节点亲和性的时候,k8s-node1和k8s-node2都满足调度条件,但是k8s-node2具有的标签是zone2=foo2,pod在匹配zone2=foo2的权重高,那么pod就会优先调度到k8s-node2上
Pod节点亲和性和反亲和性
Pod节点亲和性 是针对 pod和pod 的关系

有两种表示形式
-  
podAffinity:pod和pod更倾向在一起,把相近的pod结合到相近的位置。
这样的话pod和pod之间更好通信。比方希望把nginx和tomcat都部署同一个地方的node节点上,可以提高通信效率; -  
podAntiAffinity:pod和pod不倾向在一起。如果部署两套程序,那么这两套程序更倾向于反亲和性,这样相互之间不会有影响。
 
运行方式
第一个pod随机选则一个节点,例如:节点A。做为 评判后续的pod 能否到达节点A上。到达 就称为pod亲和性,反之是反亲和性。
以节点名称为标准,这个节点名称相同的表示是同一个位置,节点名称不相同的表示不是一个位置。
pod亲和性
pod亲和性调度字段:podAffinity
看podAffinity下的配置字段
kubectl explain pods.spec.affinity.podAffinity
 

- requiredDuringSchedulingIgnoredDuringExecution 硬亲和性
 - preferredDuringSchedulingIgnoredDuringExecution 软亲和性
 
硬亲和实践
使用requiredDuringSchedulingIgnoredDuringExecution硬亲和性
kubectl explain pods.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution
 

解释说明
- topologyKey:位置拓扑的键,节点的标签(必填)
怎么判断是不是同一个位置,例如:
rack=rack1 使用rack的键是同一个位置
row=row1 使用row的键是同一个位置 - labelSelector:判断pod跟别的pod亲和,通过labelSelector选则一组能作为亲和对象的pod资源
 - namespace:指定匹配资源的命名空间,如果不指定namespaces,那么就是当前创建pod的名称空间
 - namespaceSelector: :指定匹配资源的命名空间集合,空选择器({})匹配所有命名空间。
 
对labelSelector进一步解析:
 labelSelector——对pod资源的标签查询
kubectl explain pods.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution.labelSelector 
 

字段配置:
- matchExpressions:匹配表达式
 - matchLabels:匹配标签
 
示例1: 定义两个pod,第一个pod做为基准,第二个pod跟着它走
创建第一个pod资源文件
vim pod-required-affinity-demo-1.yaml
 
apiVersion: v1
kind: Pod
metadata:
  name: pod-first
  labels:
    app: myapp
spec:
    containers:
    - name: myapp
      image: ikubernetes/myapp:v1
      imagePullPolicy: IfNotPresent
 
创建第一个pod资源
kubectl apply -f pod-required-affinity-demo-1.yaml
 
创建第二个pod资源文件,让第二个pod和第一个pod做亲和性
vim pod-required-affinity-demo-2.yaml
 
apiVersion: v1
kind: Pod
metadata:
  name: pod-second
  labels:
    app: backend
spec:
    containers:
    - name: busybox
      image: busybox:latest
      imagePullPolicy: IfNotPresent
      command: ["sh","-c","sleep 3600"]
    affinity:
      podAffinity:  #使用pod亲和性
         requiredDuringSchedulingIgnoredDuringExecution:  #使用硬亲和性
         - topologyKey: kubernetes.io/hostname # 设置位置拓扑的键
           labelSelector:  # 设置对pod资源的标签查询
              matchExpressions: # 用匹配表达式:找pod标签中key是app 值包含myapp的
              - {key: app, operator: In, values: ["myapp"]}
           
 
上面表示新创建的pod必须与拥有 “app=myapp” 标签的pod在一个节点上
创建第二个pod资源
kubectl apply -f pod-required-affinity-demo-2.yaml
 
查看pod
kubectl get pods -o wide
 

上面说明第一个pod调度到哪,第二个pod也调度到哪,这就是pod节点亲和性
示例2 :接着上面的实验,调整一下pod2 ,让 labelSelector满足 pod1的标签,但是topologyKey不满足pod1所在的node的特点
调整第二个pod资源文件
vim pod-required-affinity-demo-2.yaml
 
apiVersion: v1
kind: Pod
metadata:
  name: pod-second
  labels:
    app: backend
spec:
    containers:
    - name: busybox
      image: busybox:latest
      imagePullPolicy: IfNotPresent
      command: ["sh","-c","sleep 3600"]
    affinity:
      podAffinity:  #使用pod亲和性
         requiredDuringSchedulingIgnoredDuringExecution:  #使用硬亲和性
         - topologyKey: zone2 # 设置node1节点没有的标签key
           labelSelector:  
              matchExpressions: 
              - {key: app, operator: In, values: ["myapp"]}
           
 
重建第二个pod资源
kubectl delete -f pod-required-affinity-demo-2.yaml
kubectl apply -f pod-required-affinity-demo-2.yaml
 
查看pod
kubectl get pods -o wide
 

上面说明 labelSelector和topologyKey必须同时满足才能找到要调度的节点
pod反亲和性
一切配置都是反着来。
例如 硬亲和性
解释说明
- topologyKey:不去有位置拓扑的键的节点上(必填)
 - labelSelector:判断pod跟别的pod反亲和
 
示例1: 定义两个pod,第一个pod做为基准,第二个pod跟它调度节点相反
创建第一个pod资源文件
vim pod-required-anti-affinity-demo-1.yaml
 
apiVersion: v1
kind: Pod
metadata:
  name: pod-first
  labels:
    app1: myapp1
spec:
    containers:
    - name: myapp
      image: ikubernetes/myapp:v1
      imagePullPolicy: IfNotPresent
 
创建第一个pod资源
kubectl apply -f  pod-required-anti-affinity-demo-1.yaml
 
创建第二个pod资源文件
vim pod-required-anti-affinity-demo-2.yaml
 
apiVersion: v1
kind: Pod
metadata:
  name: pod-second
  labels:
    app: backend
spec:
    containers:
    - name: busybox
      image: busybox:latest
      imagePullPolicy: IfNotPresent
      command: ["sh","-c","sleep 3600"]
    affinity:
      podAntiAffinity:  #使用pod反亲和性
         requiredDuringSchedulingIgnoredDuringExecution:  #使用硬亲和性
         - topologyKey: kubernetes.io/hostname 
           labelSelector:   # 设置对pod资源的标签查询
              matchExpressions:  # 用匹配表达式:pod标签中key是app1 值包含myapp1的
              - {key: app1, operator: In, values: ["myapp1"]}         
 
创建第二个pod资源
kubectl apply -f pod-required-anti-affinity-demo-2.yaml
 
查看pod
kubectl get pods -o wide
 

显示两个pod不在一个node节点上,这就是pod节点反亲和性
示例2: 看 topologykey + labelSelector同时满足时,第二个pod的情况
给节点都打上“zone=foo” 标签
kubectl label nodes  k8s-node2  zone=foo
kubectl label nodes  k8s-node1  zone=foo
 
创建第一个pod资源文件
vim pod-first-required-anti-affinity-demo-1.yaml
 
apiVersion: v1
kind: Pod
metadata:
  name: pod-first
  labels:
    app3: myapp3
spec:
    containers:
    - name: myapp
      image: ikubernetes/myapp:v1
      imagePullPolicy: IfNotPresent
 
创建第一个pod资源
kubectl apply -f  pod-first-required-anti-affinity-demo-1.yaml
 
创建第二个pod资源文件
vim pod-second-required-anti-affinity-demo-1.yaml
 
apiVersion: v1
kind: Pod
metadata:
  name: pod-second
  labels:
    app: backend
    tier: db
spec:
    containers:
    - name: busybox
      image: busybox:latest
      imagePullPolicy: IfNotPresent
      command: ["sh","-c","sleep 3600"]
    affinity:
      podAntiAffinity:
         requiredDuringSchedulingIgnoredDuringExecution:
         - labelSelector:
              matchExpressions:
              - {key: app3 ,operator: In, values: ["myapp3"]}
           topologyKey:  zone
 
创建第二个pod资源
kubectl apply -f pod-second-required-anti-affinity-demo-1.yaml
 
查看pod
kubectl get pods -o wide
 

第二个pod是pending,因为两个节点是同一个位置,现在没有不是同一个位置的了,而且要求反亲和性,所以就会处于pending状态,如果在反亲和性这个位置把硬反亲和改成软反亲和,那么也会运行。