kubernetes调度之pod调度粘性

一:三种调度粘性

NodeSelector(定向调度)
NodeAffinity(Node亲和性)
PodAffinity(Pod亲和性)

通常情况下,使用的都是k8s默认的调度调度方式,但是在有些情况下,我们需要将pod运行在具有特点的标签的node上才能都运行,这个时候,pod的调度策略就不能使用k8s默认的调度策略了,这个时候,就需要指定调度策略,告诉k8s需要将pod调度到那些node(节点)上。

1.nodeSelector

常规情况下,会直接使用nodeSelector这种调度策略。labels(标签) 是k8s里面用来编标记资源的一种常用的方式,我们可以给node标记特殊的标签,然后nodeSelector会将pod调度到带有指定labels的node上的。
提供简单的pod部署限制,pod选择一个或多个node的label部署
给node添加label

kubectl label nodes <node-name> <label-key>=<label-value>

为pod添加nodeSelector机制

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    disktype: ssd

部署pod

[root@master ~]# kubectl create -f test.yaml
pod/nginx created

查看结果

[root@master ~]# kubectl get pod -A -o wide
NAMESPACE   NAME   READY   STATUS    RESTARTS   AGE     IP           NODE   NOMINATED NODE   READINESS GATES
default      nginx        0/1     ContainerCreating   0          37s     <none>     node-1   <none>   
 

从上面的执行结果可以看出,pod 通过默认的 default-scheduler 调度器到了node-1节点上。不过,这种调度方式属于强制性的。如果node02上的资源不足,那么pod的状态将会一直是pending状态。这就是nodeselector的用法了。

2.亲和性和反亲和性调度
k8s的默认调度流程实际上是经过了两个阶段predicates,priorities 。使用默认的调度流程的话,k8s会将pod调度到资源充裕的节点上,使用nodeselector的调度方法,又会将pod调度具有指定标签的pod上。然后在实际生产环境中,我们需要将pod调度到具有些label的一组node才能满足实际需求,这个时候就需要nodeAffinity、podAffinity以及 podAntiAffinity(pod 反亲和性)。

亲和性可以分为具体可以细分为硬和软两种亲和性
软亲和性:如果调度的时候,没有满足要求,也可以继续调度,即能满足最好,不能也无所谓
硬亲和性:是指调度的时候必须满足特定的要求,如果不满足,那么pod将不会被调度到当前node

requiredDuringSchedulingIgnoredDuringExecution #硬性强制
preferredDuringSchedulingIgnoredDuringExecution #软性配置

3.nodeAffinity 节点亲和性
节点亲和性主要是用来控制 pod 能部署在哪些节点上,以及不能部署在哪些节点上的。它可以进行一些简单的逻辑组合了,不只是简单的相等匹配。
preferredDuringSchedulingIgnoredDuringExecution
强调优先满足制定规则,调度器会尝试调度pod到Node上,但并不强求,相当于软限制。多个优先级规则还可以设置权重值,以定义执行的先后顺序。
接下来看一个示例,使用nodeAffinity控制 pod 的调度,如下例子

apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: beta.kubernetes.io/arch
            operator: In
            values:
            - amd64
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: disk-type
            operator: In
            values:
            - ssd
  containers:
  - name: with-node-affinity
    image: nginx        

设置label

[root@master ~]# kubectl label nodes node-2 disk-type=ssd
node/node-2 labeled

创建pod并查看运行结果

[root@master yaml]# kubectl get pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP   NODE     NOMINATED NODE   READINESS GATES
with-node-affinity   0/1     ContainerCreating   0   4m    <none>   node-2   <none>    <none>

NodeAffinity规则设置的注意事项如下:

如果同时定义了nodeSelector和nodeAffinity,name必须两个条件都得到满足,pod才能最终运行在指定的node上。
如果nodeAffinity指定了多个nodeSelectorTerms,那么其中一个能够匹配成功即可。
如果在nodeSelectorTerms中有多个matchExpressions,则一个节点必须满足所有matchExpressions才能运行该pod。
matchExpressions : 匹配表达式,这个标签可以指定一段,例如pod中定义的key为zone,operator为In(包含那些),values为 foo和bar。就是在node节点中包含foo和bar的标签中调度
现在kubernetes提供的操作符有下面的几种

In:label 的值在某个标签中
NotIn:label 的值不在某个标签中
Gt:label 的值大于某个值
Lt:label 的值小于某个值
Exists:某个 label 存在
DoesNotExist:某个 label 不存在

4.podAffinity pod亲和性
Pod的亲和性主要用来解决pod可以和哪些pod部署在同一个集群里面,即拓扑域(由node组成的集群)里面;而pod的反亲和性是为了解决pod不能和哪些pod部署在一起的问题,二者都是为了解决pod之间部署问题。需要注意的是,Pod 间亲和与反亲和需要大量的处理,这可能会显著减慢大规模集群中的调度,不建议在具有几百个节点的集群中使用,而且Pod 反亲和需要对节点进行一致的标记,即集群中的每个节点必须具有适当的标签能够匹配topologyKey。如果某些或所有节点缺少指定的topologyKey标签,可能会导致意外行为。

Pod亲和性场景,我们的k8s集群的节点分布在不同的区域或者不同的机房,当服务A和服务B要求部署在同一个区域或者同一机房的时候,我们就需要亲和性调度了。

labelSelector : 选择跟那组Pod亲和
namespaces : 选择哪个命名空间
topologyKey : 指定节点上的哪个键

pod亲和性调度需要各个相关的pod对象运行于"同一位置", 而反亲和性调度则要求他们不能运行于"同一位置";
这里指定“同一位置” 是通过 topologyKey 来定义的,topologyKey 对应的值是 node 上的一个标签名称,比如各别节点zone=A标签,各别节点有zone=B标签,pod affinity topologyKey定义为zone,那么调度pod的时候就会围绕着A拓扑,B拓扑来调度,而相同拓扑下的node就为“同一位置”。
如果基于各个节点kubernetes.io/hostname标签作为评判标准,那么很明显“同一位置”意味着同一节点,不同节点既为不同位置。

pod亲和性

apiVersion: v1
kind: Pod
metadata:
  name: pod-first
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: daocloud.io/library/nginx:latest
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-second
  labels:
    app: db
    tier: db
spec:
  containers:
  - name: busybox
    image: daocloud.io/library/busybox
    imagePullPolicy: IfNotPresent
    command: ["sh","-c","sleep 3600"]
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - {key: app, operator: In, values: ["myapp"]}
        topologyKey: kubernetes.io/hostname

查看结果

[root@master yaml]# kubectl get pod -o wide
NAME   READY   STATUS    RESTARTS   AGE     IP     NODE     NOMINATED NODE   READINESS GATES
pod-first            1/1     Running   0          10m     10.244.1.6   node-1   <none>           <none>
pod-second           1/1     Running   0          10m     10.244.1.7   node-1   <none>           <none>

pod反亲和性
Pod反亲和性场景,当应用服务A和数据库服务B要求尽量不要在同一台节点上的时候。

apiVersion: v1
kind: Pod
metadata:
  name: pod-first-1
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: daocloud.io/library/nginx:latest
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-second-2
  labels:
    app: backend
    tier: db
spec:
  containers:
  - name: busybox
    image: daocloud.io/library/busybox:latest
    imagePullPolicy: IfNotPresent
    command: ["sh","-c","sleep 3600"]
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - {key: app, operator: In, values: ["myapp"]}
        topologyKey: kubernetes.io/hostname

查看结果

[root@master yaml]# kubectl get pod -o wide
NAME                 READY   STATUS    RESTARTS   AGE     IP           NODE     NOMINATED NODE   READINESS GATES
pod-first-1          1/1     Running   0          7m28s   10.244.1.8   node-1   <none>           <none>
pod-second-2         1/1     Running   0          7m28s   10.244.2.6   node-2   <none>           <none>

二:污点(Taints)与容忍(tolerations)

对于nodeAffinity无论是硬策略还是软策略方式,都是调度 POD 到预期节点上,而Taints恰好与之相反,如果一个节点标记为 Taints ,除非 POD 也被标识为可以容忍污点节点,否则该 Taints 节点不会被调度pod。
比如用户希望把 Master 节点保留给 Kubernetes 系统组件使用,或者把一组具有特殊资源预留给某些 POD,则污点就很有用了,POD 不会再被调度到 taint 标记过的节点。

将节点设置为污点

[root@master yaml]# kubectl taint node node-2 key=value:NoSchedule
node/node-2 tainted

查看污点

[root@master yaml]# kubectl describe node node-1 | grep Taint
Taints: <none>

去除节点污点

[root@master yaml]# kubectl taint node node-2 key=value:NoSchedule-
node/node-2 untainted

污点分类
NoSchedule:新的不能容忍的pod不能再调度过来,但是之前运行在node节点中的Pod不受影响
NoExecute:新的不能容忍的pod不能调度过来,老的pod也会被驱逐
PreferNoScheduler:表示尽量不调度到污点节点中去

使用
如果仍然希望某个 POD 调度到 taint 节点上,则必须在 Spec 中做出Toleration定义,才能调度到该节点,举例如下:

[root@master yaml]# kubectl taint node node-2 key=value:NoSchedule
node/node-2 tainted
[root@master yaml]# cat b.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: sss
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: app
            operator: In
            values:
            - myapp
  containers:
  - name: with-node-affinity
    image: daocloud.io/library/nginx:latest
注意:node-2节点设置为污点,所以label定义到node-2,但是因为有污点所以调度失败,以下是新的yaml文件
[root@master yaml]# cat b.yaml
apiVersion: v1
kind: Pod
metadata:
  name: sss-1
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: app
            operator: In
            values:
            - myapp
  containers:
  - name: with-node-affinity
    image: daocloud.io/library/nginx:latest
  tolerations:
  - key: "key"
    operator: "Equal"
    value: "value"
    effect: "NoSchedule"

结果
旧的调度失败,新的调度成功

[root@master yaml]# kubectl get pod -o wide
NAME                 READY   STATUS    RESTARTS   AGE    IP            NODE     NOMINATED NODE   READINESS GATES
sss                  0/1     Pending   0          3m2s   <none>        <none>   <none>           <none>
sss-1                1/1     Running   0          7s     10.244.2.9    node-2   <none>           <none>

注意
tolerations: #添加容忍策略

  • key: “key1” #对应我们添加节点的变量名
    operator: “Equal” #操作符
    value: “value” #容忍的值 key1=value对应
    effect: NoExecute #添加容忍的规则,这里必须和我们标记的五点规则相同

operator值是Exists,则value属性可以忽略
operator值是Equal,则表示key与value之间的关系是等于
operator不指定,则默认为Equal

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐