Pod亲和性调度

霸气de小男生 提交于 2021-02-06 09:01:38

在K8S平台上,我们很少会直接创建一个Pod,在大多数情况下会通过RC,Deployment,DaemonSet,Job等控制器完成一组Pod副本的创建,调度及全生命周期的自动控制任务。

在k8s 1.9以前,在RC等对象被删除后,它们所创建的Pod副本都不会被删除;在k8s 1.9以后,这些Pod副本会被一并删除。

如果不希望这样做,可以通过kubectl命令的“--cascade=false”参数来取消这一默认特性:

kubectl delete replicaset my-reset  --cascade=false

NodeSelector:定向调度

在一些情况下,我们需要将pod调度到指定的一些Node上,可以通过Node的标签(Label)和Pod的nodeSelector属性相匹配。

  1. 首先通过kubectl label 命令给目标Node打上一些标签:

kubectl label nodes node-name label-key=label-vaule

kubectl  label nodes 172.20.103.2 test=jinguanhua

  1. 然后,在pod的定义中加上nodeSelector的设置:

kubectl create -f redis.yaml

apiVersion: v1

kind: deploy

metadata:

  name: redis-master

  labels:

    name: redis-master

spec:

  replicas: 1

  selector:

    name: redis-master

  template:

    metadata:

      labels:

        name: redis-master

    spec:

      containers:

      - name: master

        image: kubeguide/redis-master

        ports:

        - containerPort: 6379

      nodeSelector:

        test: jinguanhua

如果我们给多个node都定义了相同的标签,则scheduler会根据调度算法从这组Node中挑选一个可用的Node进行Pod调度。

通过基于Node标签的调度方式,我们可以把集群中具有不同特点的Node都贴上不同的标签,例如“role=test”,“role=backend”,“role=database”等标签,在部署应用时就可以根据应用的需求设置NodeSelector来进行制定Node范围的调度。

PS:如果我们指定了Pod的nodeSelector条件,但是在集群中不存在包含相应标签的Node,则即使在集群中还有其他可供使用的node,这个pod也无法被成功调度。


亲和性调度

亲和性调度功能包括 节点亲和性(NodeAffinity)和 Pod亲和性(PodAffinity)两个维度的设置。

节点亲和性(NodeAffinity)

NodeAffinity是node亲和性的调度策略,是用于替换NodeSelector的全新调度策略。目前有两种节点亲和性表达。

  1. RequiredDuringSchedulingIgnoredDuringExecution:必须满足指定的规则才可以调度pod到node上,相当于硬限制。

  2. PreferredDuringSchedulingIgnoredDuringExecution:强调优先满足指定规则,调度器会尝试调度pod到node上,但并不强求,相当于软限制。多个优先级规则还可以设置权重(weight)值,以定义执行的先后顺序。

IgnoredDuringExecution的意思是:如果一个pod所在的节点在pod运行期间标签发生了变更,不再符合该pod的节点亲和性需求,则系统将忽略node上label的变化,该pod能继续在该节点运行。

apiVersion: v1

kind: Pod

metadata:

  name: with-node-affinity

spec:

  affinity:

    nodeAffinity:

      requiredDuringSchedulingIgnoredDuringExecution:

        nodeSelectorTerms:

        - matchExpressions:

          - key: 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: gcr.io/google_containers/pause:2.0

从上面的配置中可以看到In操作符,NodeAffinity语法支持的操作符包括In,NotIn,Exists,DoesNotExist,Gt,Lt。虽然没有节点排斥功能,但是用NotIn和DoesNotExist就可以实现排斥的功能了。

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

  • 如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都得到满足,Pod才能最终运行到指定的Node上。

  • 如果nodeAffinity指定了多个nodeSelectorTerms,那么其中一个能够匹配成功即可。

  • 如果在nodeSelectorTerms中有多个matchExpressions,则一个节点必须满足所有matchExpressions才能运行该Pod。


Pod亲和性(PodAffinity)与互斥性(podAntiAffinity)调度策略

Pod间的亲和与互斥从Kubernetes 1.4版本开始引入。这一功能让用户从另一个角度来限制Pod所能运行的节点:根据在节点上正在运行的Pod的标签而不是节点的标签进行判断和调度,要求对节点和Pod两个条件进行匹配。这种规则可以描述为:如果在具有标签X的Node上运行了一个或者多个符合条件Y的Pod,那么Pod应该(如果是互斥的情况,那么就变成拒绝)运行在这个Node上。

这里X指的是一个集群中的节点、区域(zone)和地域(region)等概念,通过Kubernetes内置节点标签中的key来进行声明。这个key的名字为topologyKey,意为表达节点所属的topology范围。

◎ kubernetes.io/hostname

◎ kubernetes.io/arch

◎ kubernetes.io/os

◎ failure-domain.beta.kubernetes.io/zone

◎ failure-domain.beta.kubernetes.io/region

与节点不同的是,Pod是属于某个命名空间的,所以条件Y表达的是一个或者全部命名空间中的一个Label Selector。

[root@iZ2ze7mealklhmaorgtx5jZ pro]# kubectl get no  cn-beijing.172.17.13.102 --show-labels

NAME                       STATUS   ROLES    AGE    VERSION            LABELS

cn-beijing.172.17.13.102   Ready    <none>   574d   v1.16.6-aliyun.1   alibabacloud.com/nodepool-id=np019605d02c37420a9e201a4eba2391c7,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=ecs.sn1ne.xlarge,beta.kubernetes.io/os=linux,env=product,failure-domain.beta.kubernetes.io/region=cn-beijing,failure-domain.beta.kubernetes.io/zone=cn-beijing-c,kubernetes.io/arch=amd64,kubernetes.io/hostname=cn-beijing.172.17.13.102,kubernetes.io/os=linux

为了保证业务应用的高可用,有些客户会要求关键应用部署到多个机房,一个机房一旦出问题,其他机房正常工作,从而让应用保持不间断连续运行。类似这样的能力在云上如何实现呢?阿里云有Region(地域)和Zone(可用区)的概念。简单点理解,Region对应城市,例如“华东1”为杭州,“华北2”为北京等。Zone为Region下按照电力和网络设备等相互独立的的可用区,不同的可用区可能在一个物理机房中。同一个地域内的不同可用区之间内网是连通的,网络延迟很小。

和节点亲和相同,Pod亲和与互斥的条件设置也是requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution。

pod的亲和性被定义与PodSpec的affinity字段下的podAffinity子字段中

pod间的互斥性则被定义于同一层次的podAntiAffinity子字段中。

下面通过实例来说明pod间的亲和性和互斥性策略设置

1.参照目标Pod

首先,创建一个名为pod-flag的Pod,带有标签security=S1和app=nginx,后面的例子将使用pod-flag作为Pod亲和与互斥的目标Pod:

apiVersion: v1

kind: Pod

metadata:

  name: pod-flag

  labels:

    security: "S1"

    app: "nginx"

spec:

  containers:

  - name: nginx

    image: nginx

2.Pod的亲和性调度

下面创建第2个Pod来说明Pod的亲和性调度,这里定义的亲和标签是security=S1,对应上面的Pod“pod-flag”,topologyKey的值被设置为“kubernetes.io/hostname”:

apiVersion: v1

kind: Pod

metadata:

  name: pod-affinity

spec:

  affinity:

    podAffinity:

      requiredDuringSchedulingIgnoredDuringExecution:

      - labelSelector:

          matchExpressions:

          - key: security

            operator: In

            values:

            - S1

        topologyKey: kubernetes.io/hostname

  containers:

  - name: with-pod-affinity

    image: gcr.io/google_containers/pause:2.0

创建Pod之后,使用kubectl get pods -o wide命令可以看到,这两个Pod在同一个Node上运行。有兴趣的读者还可以测试一下,在创建这个Pod之前,删掉这个节点的kubernetes.io/hostname标签,重复上面的创建步骤,将会发现Pod一直处于Pending状态,这是因为找不到满足条件的Node了。

3.Pod的互斥性调度

创建第3个Pod,我们希望它不与目标Pod运行在同一个Node上:

apiVersion: v1

kind: Pod

metadata:

  name: anti-affinity

spec:

  affinity:

    podAffinity:

      requiredDuringSchedulingIgnoredDuringExecution:

      - labelSelector:

          matchExpressions:

          - key: security

            operator: In

            values:

            - S1

        topologyKey: failure-domain.beta.kubernetes.io/zone

    podAntiAffinity:

      requiredDuringSchedulingIgnoredDuringExecution:

      - labelSelector:

          matchExpressions:

          - key: app

            operator: In

            values:

            - nginx

        topologyKey: kubernetes.io/hostname

  containers:

  - name: anti-affinity

    image: gcr.io/google_containers/pause:2.0

这里要求这个新Pod与security=S1的Pod为同一个zone,但是不与app=nginx的Pod为同一个Node。创建Pod之后,同样用kubectl get pods -o wide来查看,会看到新的Pod被调度到了同一Zone内的不同Node上。

与节点亲和性类似,Pod亲和性的操作符也包括In、NotIn、Exists、DoesNotExist、Gt、Lt。

原则上,topologyKey可以使用任何合法的标签Key赋值,但是出于性能和安全方面的考虑,对topologyKey有如下限制。

◎ 在Pod亲和性和RequiredDuringScheduling的Pod互斥性的定义中,不允许使用空的topologyKey。

◎ 如果Admission controller包含了LimitPodHardAntiAffinityTopology,那么针对RequiredDuringScheduling的Pod互斥性定义就被限制为kubernetes.io/hostname,要使用自定义的topologyKey,就要改写或禁用该控制器。

◎ 在PreferredDuringScheduling类型的Pod互斥性定义中,空的topologyKey会被解释为kubernetes.io/hostname、failuredomain.beta.kubernetes.io/zone及failuredomain.beta.kubernetes.io/region的组合。

◎ 如果不是上述情况,就可以采用任意合法的topologyKey了。

PodAffinity规则设置的注意事项如下。

◎ 除了设置Label Selector和topologyKey,用户还可以指定Namespace列表来进行限制,同样,使用Label Selector对Namespace进行选择。Namespace的定义和Label Selector及topologyKey同级。省略Namespace的设置,表示使用定义了affinity/anti-affinity的Pod所在的Namespace。如果Namespace被设置为空值(""),则表示所有Namespace。

◎ 在所有关联requiredDuringSchedulingIgnoredDuringExecution的matchExpressions全都满足之后,系统才能将Pod调度到某个Node上。

image.png

image.png


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!