Kubernetes Affinity 示例指南

Kubernetes Affinity 示例指南

Kubernetes (K8s) 调度程序通常使用基于资源可用性的简单规则将 pod 放置在节点上。这对许多用例来说都很好。但是,有时,您可能需要超越简单的基于资源的调度。

例如,如果你想在特定节点上调度 pod 怎么办?或者,如果您想避免在相同的节点上部署特定的 pod 怎么办?

这就是 Kubernetes 亲和性和 Kubernetes 反亲和性的用武之地。它们是先进的 K8s 调度技术,可以帮助您创建灵活的调度策略。

通常,亲和性使 Kubernetes 调度程序能够将 pod 放置在一组节点上,或者将 pod 放置在相对于其他 pod 的放置位置。要控制一组节点上的 pod 放置,用户需要使用节点亲和性规则。相反,pod 亲和性或 pod 反亲和性规则提供了控制 pod 相对于其他 pod 的位置的能力。

在本文中,为了帮助您开始使用 Kubernetes 亲和性,我们将仔细研究高级调度方法,深入研究不同类型的 K8s 亲和性,并提供一个节点亲和性演示,以便您可以动手 -使用 Kubernetes 高级调度。

Kubernetes 高级 Pod 调度技术

在我们进入 Kubernetes affinity 之前,让我们退后一步,回顾一下我们可用的不同自定义 pod 调度技术。在下表中,您将看到各种高级调度方法的细分,包括节点亲和性和 Pod 亲和/反亲和性。


image.png

K8s Taints and Tolerations

使用 Taints,节点可以控制 pod 的放置。Taints 允许节点定义哪些 pod 可以放置在它们上面以及哪些 pod 被排斥。

例如,假设您有一个具有特殊硬件的节点,并且希望调度程序仅部署需要特殊硬件的 pod。您可以对节点的 Taints 使用 Tolerations 来满足此要求。

需要特殊硬件的 Pod 必须为这些节点上的Taints 定义容忍度。使用 Toleration,节点将允许 Pod 在其上运行。

K8s 节点选择器

NodeSlector 是在节点上调度 pod 的最简单方法。它的工作原理是为节点定义一个标签,然后通过匹配 pod 规范中的标签将 pod 绑定到该节点。这是一种在某些情况下有效的简单方法。但是,它对于复杂的 pod 调度不够灵活。

节点亲和性

节点亲和性规则使用节点上的标签和 pod 规范文件中的标签选择器。节点无法控制放置。如果调度程序使用节点亲和性规则放置一个 pod,并且该规则稍后不再有效(例如,由于标签更改),则该 pod 将继续在该节点上运行。

节点亲和性有很多用例,包括将 pod 放置在具有特定 CPU/GPU 的一组节点上,以及将 pod 放置在特定可用性区域中的节点上。

[图片上传失败...(image-242d8-1684914517305)]

使用节点亲和性的 Kubernetes pod 调度示例。

有两种类型的节点亲和性规则:

  • 必需的
  • 首选

必须始终满足调度程序放置 Pod 所需的规则。使用首选规则,调度程序将尝试执行规则,但不保证执行。

Pod 亲和性和 Pod 反亲和性

Pod Affinity 和 Anti-Affinity 允许创建规则来控制 pod 相对于其他 pod 的放置位置。用户必须标记节点并在 pod 规范中使用标签选择器。

Pod Affinity/Anti-Affinity 允许 pod 指定对一组 pod 的亲和性(或反亲和性)。与 Node Affinity 一样,节点无法控制 pod 的放置。

关联规则基于标签工作。使用关联规则,如果新 pod 上的标签与另一个 pod 上的标签匹配,则调度程序可以将 pod 放置在与其他 pod 相同的节点上。

[图片上传失败...(image-31a21f-1684914517305)]

使用 Pod Affinity 的 Kubernetes pod 调度示例。

如果新 pod 上的标签与另一个 pod 上的标签匹配,则反亲和性规则告诉调度程序不要将新 pod 放在同一节点上。反亲和性允许您使 pod 彼此远离。反亲和性在以下情况下很有用:避免在同一节点上放置会干扰现有 pod 性能的 pod。

[图片上传失败...(image-a77b9f-1684914517305)]

使用 Pod Anti-Affinity 的 Kubernetes pod 调度示例。

与节点亲和性规则一样,Pod 亲和性规则也有“必需”和“首选”模式。在“Required”模式下,调度器必须满足一个规则才能放置 Pod。在“首选”模式下,不保证基于规则的调度。

节点亲和性演示

现在您了解了 Kubernetes 亲和性,让我们进入我们的节点亲和性演示。

在此演示中,我们将按照分步说明执行以下操作:

  • 通过标记集群中的一些节点来解释节点亲和性规则的工作原理
  • 在 pod 规范中使用节点亲和性规则创建部署
  • 查看 Pod 是否放置在具有给定标签的节点上。

首先让我们看看集群中的节点列表:

$ kubectl get nodes
                    NAME                                            STATUS   ROLES               AGE    VERSION
                    k8s-node-master-1   Ready    controlplane,etcd   723d   v1.15.12
                    k8s-node-master-2   Ready    controlplane,etcd   723d   v1.15.12
                    k8s-node-master-3   Ready    controlplane,etcd   723d   v1.15.12
                    k8s-node-worker-1   Ready    worker              723d   v1.15.12
                    k8s-node-worker-2   Ready    worker              723d   v1.15.12
                    k8s-node-worker-3   Ready    worker              723d   v1.15.12
                    k8s-node-worker-4   Ready    worker              723d   v1.15.12
                    

为node affinity demo 标记两个节点,这样pod 就可以通过affinity rule 放置在有标签的节点上:

$ kubectl label node k8s-node-worker-3 app=frontend
                    node/k8s-node-worker-3 labeled
                    
                    $ kubectl label node k8s-node-worker-4 app=frontend
                    node/k8s-node-worker-4 labeled                    
                    

接下来,为演示创建一个命名空间:

$ kubectl create ns test
                    namespace/test created                  
                    

接下来,在 pod 规范中创建以下具有节点亲和性的部署文件:

apiVersion: apps/v1
                    kind: Deployment
                    metadata:
                      name: node-affinity
                      namespace: test
                    spec:
                      replicas: 4
                      selector:
                        matchLabels:
                          run: nginx
                      template:
                        metadata:
                          labels:
                            run: nginx
                        spec:
                          containers:
                          - image: nginx
                            imagePullPolicy: Always
                            name: nginx
                          affinity:
                            Node affinity:
                              requiredDuringSchedulingIgnoredDuringExecution:
                                nodeSelectorTerms:
                                - matchExpressions:
                                  - key: app
                                    operator: In
                                    values:
                                    - frontend                                   
                    

现在,使用 YAML 文件创建部署:

$ kubectl create -f deployment-node-affinity.yml
                    deployment.apps/node-affinity created               
                    

接下来查看deployment是否创建成功:

$ kubectl get deploy -n test
                    NAME            READY   UP-TO-DATE   AVAILABLE   AGE
                    node-affinity   4/4     4            4           10s              
                    

接下来,获取创建的 pod 列表:

$ kubectl get pods -n test
                    NAME                             READY   STATUS    RESTARTS   AGE
                    node-affinity-7fd7f8f75f-dng7b   1/1     Running   0          30s
                    node-affinity-7fd7f8f75f-frsxz   1/1     Running   0          30s
                    node-affinity-7fd7f8f75f-nn6jl   1/1     Running   0          30s
                    node-affinity-7fd7f8f75f-wpc66   1/1     Running   0          30s            
                    

接下来,要检查 pod 亲和性规则是否有效,请获取节点上的 pod 列表,并确保这些 pod 放置在标签为 app=frontend 的节点上,即本例中的 worker3、worker4:

$ kubectl get pod -o=custom-columns=NODE:.spec.nodeName,NAME:.metadata.name -n test

                    NODE                                            NAME
                    k8s-node-worker-4   node-affinity-7fd7f8f75f-dng7b
                    k8s-node-worker-4   node-affinity-7fd7f8f75f-frsxz
                    k8s-node-worker-3   node-affinity-7fd7f8f75f-nn6jl
                    k8s-node-worker-3   node-affinity-7fd7f8f75f-wpc66          
                    

最后,清理演示资源:

$ kubectl delete ns test --cascade
                    namespace "test" deleted        
                    

Pod 亲和性和反亲和性演示

假设我们有一个用于 Web 应用程序的 Redis 缓存,我们需要运行三个 Redis 副本,但我们需要确保每个副本都运行在不同的节点上,我们在这里使用 pod 反亲和性。

使用 Pod 反亲和规则的 Redis 部署,使每个副本落在不同的节点上:

cat redis.yaml 

                    apiVersion: apps/v1
                    kind: Deployment
                    metadata:
                      name: redis-cache
                      namespace: test
                    spec:
                      selector:
                        matchLabels:
                          app: store
                      replicas: 3
                      template:
                        metadata:
                          labels:
                            app: store
                        spec:
                          affinity:
                            podAntiAffinity:
                              requiredDuringSchedulingIgnoredDuringExecution:
                              - labelSelector:
                                  matchExpressions:
                                  - key: app
                                    operator: In
                                    values:
                                    - store
                                topologyKey: "kubernetes.io/hostname"
                          containers:
                          - name: redis-server
                            image: redis:3.2-alpine                          
                    

使用上面的 yaml 文件创建部署:

kubectl create -f redis.yaml 
                    deployment.apps/redis-cache created      
                    

获取部署已启动

$ kubectl -n test get deploy

                    NAME          READY   UP-TO-DATE   AVAILABLE   AGE
                    redis-cache   3/3     3            3           11s   
                    

检查每个 pod 是否在不同的节点上运行:

$ kubectl get pod -o=custom-columns=NODE:.spec.nodeName,NAME:.metadata.name -n test

                    NODE                                            NAME
                    k8s-node-worker-3   redis-cache-67786cc786-bgxtp
                    k8s-node-worker-1   redis-cache-67786cc786-btppc
                    k8s-node-worker-2   redis-cache-67786cc786-dchf7  
                    

我们注意到每个 pod 都在不同的节点上运行。

接下来,假设我们有一个正在运行的 Web 服务器,我们需要确保每个 Web 服务器 Pod 与每个 Redis 缓存 Pod 位于同一位置,但与此同时,我们需要确保两个 Web 服务器 Pod 不会同时运行同一个节点,为了实现这一点,我们使用了 pod affinity 和 pod anti-affinity,如下所示。

使用亲和性和反亲和性规则创建部署文件:

cat web-server.yaml 
                    apiVersion: apps/v1
                    kind: Deployment
                    metadata:
                      name: web-server
                      namespace: test
                    spec:
                      selector:
                        matchLabels:
                          app: web-store
                      replicas: 3
                      template:
                        metadata:
                          labels:
                            app: web-store
                        spec:
                          affinity:
                            podAntiAffinity:
                              requiredDuringSchedulingIgnoredDuringExecution:
                              - labelSelector:
                                  matchExpressions:
                                  - key: app
                                    operator: In
                                    values:
                                    - web-store
                                topologyKey: "kubernetes.io/hostname"
                            podAffinity:
                              requiredDuringSchedulingIgnoredDuringExecution:
                              - labelSelector:
                                  matchExpressions:
                                  - key: app
                                    operator: In
                                    values:
                                    - store
                                topologyKey: "kubernetes.io/hostname"
                          containers:
                          - name: web-app
                            image: nginx:1.12-alpine                     
                    

创建部署:

kubectl create -f web-server.yaml 
                    deployment.apps/web-server created 
                    

列出 Pod 和节点,并检查它们是否按照规则的要求放置:

kubectl get pod -o=custom-columns=NODE:.spec.nodeName,NAME:.metadata.name -n test

                    NODE                                            NAME
                    k8s-node-worker-3   redis-cache-67786cc786-bgxtp
                    k8s-node-worker-1   redis-cache-67786cc786-btppc
                    k8s-node-worker-2   redis-cache-67786cc786-dchf7
                    k8s-node-worker-1   web-server-84b9456f9b-dhd9x
                    k8s-node-worker-3   web-server-84b9456f9b-lf6xs
                    k8s-node-worker-2   web-server-84b9456f9b-zbjq2                    
                    

我们注意到每个 web pod 都与一个 redis pod 位于同一位置,并且没有两个 web pod 在同一个节点上运行;这是通过使用 pod 亲和性和反亲和性规则完成的。

结论

亲和性和反亲和性提供了灵活的方式来在节点上调度 pod 或将 pod 相对于其他 pod 放置。您可以使用亲和性规则来优化工作节点上的 pod 放置,以满足性能、容错或其他复杂的调度要求。

你可能感兴趣的:(Kubernetes Affinity 示例指南)