大数跨境
0
0

Kubernetes 亲和性调度

Kubernetes 亲和性调度 开发运维devops
2025-11-24
3
导读:Kubernetes 亲和性调度

默认情况下创建Pod是根据Kubernetes scheduler的默认调度规则来进行调度,但有些时候,有些应用有一些特殊的需求。比如指定部署到对应的节点,多个Pod之间需要部署在不同的一个节点,需要互斥、Pod和Pod间互相交流比较频繁需要跑在一个节点,这里就需要用到Kubernetes里面的一个概念: 亲和性和反亲和性

亲和性分为节点亲和性nodeAffinity和Pod 亲和性podAffinity

在介绍亲和性之前,这里先介绍一下常用的调度方式: NodeSelector

在Kubernetes中label是一个非常重要的概念,用户可以通过label来管理集群中的资源,比如常见的service就是通过label去匹配Pod资源,而Pod的调度也可以根据节点的label继续调度

这里先查看一下默认的node节点labels

[root@k8s-01 ~]# kubectl get nodes --show-labelsNAME     STATUS   ROLES    AGE   VERSION   LABELSk8s-01   Ready       23d   v1.14.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-01,kubernetes.io/os=linuxk8s-02   Ready       23d   v1.14.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-02,kubernetes.io/os=linuxk8s-03   Ready       23d   v1.14.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-03,kubernetes.io/os=linuxk8s-04   Ready       23d   v1.14.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-04,kubernetes.io/os=linux

我们还可以手动添加node节点的标签

因为我之前并没有在标签上区分master和node,这里我使用标签来区分一下

[root@k8s-01 ~]# kubectl label nodes k8s-01 host=master-01node/k8s-01 labeled[root@k8s-01 ~]# kubectl label nodes k8s-02 host=master-02node/k8s-02 labeled[root@k8s-01 ~]# kubectl label nodes k8s-03 host=master-03node/k8s-03 labeled  #这里为了演示设置了3组不同的标签

接下来可以查看一下,下面就可以看到在标签中添加了一个名称为host=master的标签,每个节点的标签名称不同(当然也可以设置相同,都设置为host=master也可以)

[root@k8s-01 ~]# kubectl get nodes --show-labels |grep masterk8s-01   Ready       23d   v1.14.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,host=master-01,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-01,kubernetes.io/os=linuxk8s-02   Ready       23d   v1.14.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,host=master-02,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-02,kubernetes.io/os=linuxk8s-03   Ready       23d   v1.14.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,host=master-03,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-03,kubernetes.io/os=linux

这里使用一个busybox镜像,将pod绑定到k8s-01节点上

apiVersion: v1kind: Podmetadata:  labels:    app: web  name: testspec:  containers:  - command:    - sleep    - "3600"    image: busybox    name: busybox  nodeSelector:     #添加nodeselector,让Pod只匹配的node节点    host: master-01    #匹配node label标签为host=master-01的节点

这里我们就可以看到一个名称为test的pod调度到k8s-01节点,因为我k8s-01节点设置的就是master-01的名称

[root@k8s-01 test]# kubectl get pod -o wideNAME   READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATEStest   1/1     Running   0          35s   172.30.40.3   k8s-01   

我们我们设置的nodeSelector中写错了,那么pod会一直处于pending状态,因为没有合适的node节点,所以会一直处于等待状态

亲和性和反亲和性调度

亲和性调度可以分为软策略和硬策略两种方式

·软策略 如果当前node节点中没有满足要求的节点,Pod就会忽略,继续完成调度

·硬策略 如果当前node节点中没有满足条件的节点,就不断重试,直到满足条件位置

同时亲和性又分为nodeAffinitypodAffinity 节点亲和性和Pod亲和性

nodeAffinity

Node affinity 是 Kubernetes 1.2版本后引入的新特性,类似于nodeSelector,允许我们指定一些Pod在Node间调度的约束。支持两种形式:requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution,可以认为前一种是必须满足,如果不满足则不进行调度,后一种是倾向满足,不满足的情况下会调度的不符合条件的Node上

这里使用Nginx Deployment来进行调度管理

硬策略

简单的介绍一下就是不在标签hostname=k8s-04这台节点创建pod

apiVersion: apps/v1beta1kind: Deploymentmetadata:  name: affinity  labels:    app: affinityspec:  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

构建完可以查看到,没有在k8s-04节点进行运行

 

相关参数解释

·同时指定nodeSelector and nodeAffinity,pod必须都满足

·nodeAffinity有多个nodeSelectorTerms ,pod只需满足一个

·nodeSelectorTerms多个matchExpressions ,pod必须都满足

标签判断的操作符除了使用In之外,还可以使用NotInExistsDoesNotExistGtLt。如果指定多个nodeSelectorTerms,则只要满足其中一个条件,就会被调度到相应的节点上。如果指定多个matchExpressions,则所有的条件都必须满足才会调度到对应的节点。

软策略

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

apiVersion: apps/v1kind: Deploymentmetadata:  name: affinity-preferred  labels:    app: affinity-preferredspec:  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

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

nodeAffinity使用场景:

·将S1服务的所有Pod部署到指定的符合标签规则的主机上。

·将S1服务的所有Pod部署到除部分主机外的其他主机上。

总的来说,node亲和性与nodeSelector类似,是它的扩展。当然软硬策略也可以分开写

podAffinity

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

首先为了方便演示,我这里创建一个标签为app=web01的Deployment,将我们新建的Pod绑定到app=web01的节点上去

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

创建完成后,我们可以先查看一下新建的pod位于的节点和标签

已经看到有3个标签为app=web01的Pod分别运行在k8s0{1-3}的节点中,那么我们下面创建的Pod亲和力也应该分别处于和三个节点中

apiVersion: apps/v1kind: Deploymentmetadata:  name: nginx-test  labels:    app: nginxspec:  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 X上运行了一个或多个满足Y条件的Pod,那么这个Pod在Node应该运行在Pod X",因为Node没有命名空间,Pod有命名空间,这样就允许管理员在配置的时候指定这个亲和性策略适用于哪个命名空间,可以通过topologyKey来指定。topology是一个范围的概念,可以是一个Node、一个机柜、一个机房或者是一个区域(如北美、亚洲)等,实际上对应的还是Node上的标签。

podAffinity使用场景:

·将某一特定服务的pod部署在同一拓扑域中,不用指定具体的拓扑域。

·如果S1服务使用S2服务,为了减少它们之间的网络延迟(或其它原因),把S1服务的POD和S2服务的pod部署在同一拓扑域中。

这样就可以更好的解一下topologyKey参数

podAntiAffinity

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

podAntiAffinity使用场景:

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

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

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

pod反亲和性实际上只需要上pod亲和性中的podAffinity修改为podAntiAffinity就可以。还是以上面nginx举例,上面的nginx 3个pod节点已经运行在k8s-0{1-3}中,那么我们创建的反亲和性应该就让让它运行在k8s-04节点 (因为添加了硬策略,所以它没有选择其他节点的权利)

apiVersion: apps/v1beta1kind: Deploymentmetadata:  name: nginx-test-not  labels:    app: nginxspec:  replicas: 3  revisionHistoryLimit: 10  template:    metadata:      labels:        app: nginx    spec:      containers:      - name: nginx        image: nginx        ports:        - name: http          containerPort: 8080      affinity:        podAntiAffinity:  #修改为反亲和力,其他参数不变 (当然Deployment名称肯定需要修改)          requiredDuringSchedulingIgnoredDuringExecution:           - labelSelector:                matchExpressions:                  - key: app                       operator: In                values:                - web01                  topologyKey: kubernetes.io/hostname

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

 

【声明】内容源于网络
0
0
开发运维devops
10+老运维,devops相关文档精华。
内容 96
粉丝 0
开发运维devops 10+老运维,devops相关文档精华。
总阅读152
粉丝0
内容96