K8S之运用亲和性设置Pod的调度约束

亲和性

Pod 的yaml文件里 spec 字段中包含一个 affinity 字段,使用一组亲和性调度规则,指定pod的调度约束。

bash 复制代码
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下的配置字段

bash 复制代码
kubectl explain  pods.spec.affinity.nodeAffinity
  • preferredDuringSchedulingIgnoredDuringExecution 表示有节点尽量满足这个位置定义的亲和性,这不是一个必须的条件,软亲和性
  • requiredDuringSchedulingIgnoredDuringExecution 表示必须有节点满足这个位置定义的亲和性,这是个硬性条件,硬亲和性

硬亲和实践

使用requiredDuringSchedulingIgnoredDuringExecution硬亲和性

Node节点硬亲和性选择匹配方式有2种:

  • matchFields: 匹配字段的
  • matchExpressions:匹配表达式的 (用的多)

对matchExpressions做进一步解读

matchExpressions------匹配表达式的写法:

bash 复制代码
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资源文件

bash 复制代码
vim pod-nodeaffinity-demo.yaml
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

创建资源

bash 复制代码
kubectl apply -f pod-nodeaffinity-demo.yaml

查看pod

bash 复制代码
kubectl get pods -o wide

status的状态是pending,上面说明没有完成调度,因为没有一个节点拥有zone的标签

值是foo或者bar,而且使用的是硬亲和性,必须满足条件才能完成调度

给k8s-node1节点打上标签zone=foo,再查看

bash 复制代码
kubectl label nodes k8s-node1 zone=foo
bash 复制代码
kubectl get pods -o wide

pod调度到了k8s-node1节点上

软亲和性实践

使用preferredDuringSchedulingIgnoredDuringExecution软亲和性

示例

创建pod资源文件

bash 复制代码
vim pod-nodeaffinity-demo-2.yaml
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调度的几率越大

创建资源

bash 复制代码
kubectl apply -f pod-nodeaffinity-demo-2.yaml

查看pod

bash 复制代码
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")

bash 复制代码
kubectl delete pod pod-node-affinity-demo-2 --force --grace-period=0

给k8s-node1和k8s-node2都打上标签

bash 复制代码
kubectl label nodes k8s-node1 zone1=foo1

kubectl label nodes k8s-node2 zone2=foo2

再创建资源

bash 复制代码
kubectl apply -f pod-nodeaffinity-demo-2.yaml

查看pod

bash 复制代码
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下的配置字段

bash 复制代码
kubectl explain pods.spec.affinity.podAffinity
  • requiredDuringSchedulingIgnoredDuringExecution 硬亲和性
  • preferredDuringSchedulingIgnoredDuringExecution 软亲和性

硬亲和实践

使用requiredDuringSchedulingIgnoredDuringExecution硬亲和性

bash 复制代码
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资源的标签查询

bash 复制代码
kubectl explain pods.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution.labelSelector 

字段配置:

  • matchExpressions:匹配表达式
  • matchLabels:匹配标签

示例1: 定义两个pod,第一个pod做为基准,第二个pod跟着它走

创建第一个pod资源文件

bash 复制代码
vim pod-required-affinity-demo-1.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: pod-first
  labels:
    app: myapp
spec:
    containers:
    - name: myapp
      image: ikubernetes/myapp:v1
      imagePullPolicy: IfNotPresent

创建第一个pod资源

bash 复制代码
kubectl apply -f pod-required-affinity-demo-1.yaml

创建第二个pod资源文件,让第二个pod和第一个pod做亲和性

bash 复制代码
vim pod-required-affinity-demo-2.yaml
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资源

bash 复制代码
kubectl apply -f pod-required-affinity-demo-2.yaml

查看pod

bash 复制代码
kubectl get pods -o wide

上面说明第一个pod调度到哪,第二个pod也调度到哪,这就是pod节点亲和性

示例2 :接着上面的实验,调整一下pod2 ,让 labelSelector满足 pod1的标签,但是topologyKey不满足pod1所在的node的特点

调整第二个pod资源文件

bash 复制代码
vim pod-required-affinity-demo-2.yaml
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资源

bash 复制代码
kubectl delete -f pod-required-affinity-demo-2.yaml

kubectl apply -f pod-required-affinity-demo-2.yaml

查看pod

bash 复制代码
kubectl get pods -o wide

上面说明 labelSelector和topologyKey必须同时满足才能找到要调度的节点

pod反亲和性

一切配置都是反着来。

例如 硬亲和性

解释说明

  • topologyKey:不去有位置拓扑的键的节点上(必填)
  • labelSelector:判断pod跟别的pod反亲和

示例1: 定义两个pod,第一个pod做为基准,第二个pod跟它调度节点相反

创建第一个pod资源文件

bash 复制代码
vim pod-required-anti-affinity-demo-1.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: pod-first
  labels:
    app1: myapp1
spec:
    containers:
    - name: myapp
      image: ikubernetes/myapp:v1
      imagePullPolicy: IfNotPresent

创建第一个pod资源

bash 复制代码
kubectl apply -f  pod-required-anti-affinity-demo-1.yaml

创建第二个pod资源文件

bash 复制代码
vim pod-required-anti-affinity-demo-2.yaml
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资源

bash 复制代码
kubectl apply -f pod-required-anti-affinity-demo-2.yaml

查看pod

bash 复制代码
kubectl get pods -o wide

显示两个pod不在一个node节点上,这就是pod节点反亲和性

示例2: 看 topologykey + labelSelector同时满足时,第二个pod的情况

给节点都打上"zone=foo" 标签

bash 复制代码
kubectl label nodes  k8s-node2  zone=foo

kubectl label nodes  k8s-node1  zone=foo

创建第一个pod资源文件

bash 复制代码
vim pod-first-required-anti-affinity-demo-1.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: pod-first
  labels:
    app3: myapp3
spec:
    containers:
    - name: myapp
      image: ikubernetes/myapp:v1
      imagePullPolicy: IfNotPresent

创建第一个pod资源

bash 复制代码
kubectl apply -f  pod-first-required-anti-affinity-demo-1.yaml

创建第二个pod资源文件

bash 复制代码
vim pod-second-required-anti-affinity-demo-1.yaml
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资源

bash 复制代码
kubectl apply -f pod-second-required-anti-affinity-demo-1.yaml

查看pod

bash 复制代码
kubectl get pods -o wide

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

相关推荐
later_rql38 分钟前
k8s-集群部署1
云原生·容器·kubernetes
weixin_453965003 小时前
[单master节点k8s部署]31.ceph分布式存储(二)
分布式·ceph·kubernetes
大G哥6 小时前
记一次K8S 环境应用nginx stable-alpine 解析内部域名失败排查思路
运维·nginx·云原生·容器·kubernetes
feng_xiaoshi6 小时前
【云原生】云原生架构的反模式
云原生·架构
妍妍的宝贝6 小时前
k8s 中微服务之 MetailLB 搭配 ingress-nginx 实现七层负载
nginx·微服务·kubernetes
大道归简7 小时前
Docker 命令从入门到入门:从 Windows 到容器的完美类比
windows·docker·容器
爱跑步的程序员~7 小时前
Docker
docker·容器
福大大架构师每日一题8 小时前
23.1 k8s监控中标签relabel的应用和原理
java·容器·kubernetes
程序那点事儿8 小时前
k8s 之动态创建pv失败(踩坑)
云原生·容器·kubernetes
疯狂的大狗8 小时前
docker进入正在运行的容器,exit后的比较
运维·docker·容器