从NodeSelector到NodeAffinity:探索Kubernetes节点亲和性的进化之路

简介: 从NodeSelector到NodeAffinity:探索Kubernetes节点亲和性的进化之路

往期精彩文章 :


在Kubernetes中,有时候我们需要更精确地控制Pod的调度,将其分配到集群中特定的节点上。kubernetes对Pod的调度规则,kubernetes提供了四大类调度方式:

  • 自动调度:运行在哪个节点上完全由Scheduler经过一系列的算法计算得出
  • 定向调度:NodeNameNodeSelector
  • 亲和性调度:NodeAffinityPodAffinityPodAntiAffinity
  • 污点(容忍)调度:TaintsToleration

本教程将向您介绍两种方法:使用定向调度和亲和性调度,以确保Pod只在我们指定的节点上运行。

定向调度

什么是NodeSelector

NodeSelector 是 Kubernetes 中一种用于调度 Pod 到特定节点的机制。通过在 Pod 的配置中定义 nodeSelector 字段,您可以为 Pod 指定一组键值对标签。这些标签将与集群中的节点标签进行匹配,以确定 Pod 应该被调度到哪个节点上运行。

具体而言,nodeSelector 允许您按照节点的标签选择性地将 Pod 调度到集群中。这种机制非常适用于具有特定硬件要求或运行特定环境的 Pod,以确保它们在正确的节点上运行。

NodeSelector基本用法

此 Pod 配置文件描述了一个拥有节点选择器 disktype: ssd 的 Pod。这表明该 Pod 将被调度到有 disktype=ssd 标签的节点。

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

以下通过案例演示的方式来阐述NodeSelector的基本用法:

  1. 列出你的集群中的节点, 包括这些节点上的标签,输出类似如下:
controlplane $ kubectl get node --show-labels
NAME           STATUS   ROLES           AGE   VERSION   LABELS
controlplane   Ready    control-plane   12h   v1.29.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=controlplane,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
node01         Ready    <none>          12h   v1.29.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node01,kubernetes.io/os=linux
  1. 从你的节点中选择一个,为它添加标签
kubectl label nodes node01 disktype=ssd
  1. 验证你选择的节点确实带有 disktype=ssd 标签:

  1. 创建一个将被调度到你选择的节点的Pod
kubectl create -f pod-nginx.yaml
  • pod-nginx.yaml文件的内容是上述yaml所示。
  • 创建成功后这个pod会调度到包含有disktype=ssd的标签中

执行成功后,验证Pod 确实运行在你选择的节点上:

controlplane $ kubectl get pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          11s   192.168.1.4   node01   <none>           <none>

我们还可以通过设置spec.nodeName参数将某个Pod 调度到特定的节点。演示yaml如下:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeName: foo-node # 调度 Pod 到特定的节点
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent

亲和性调度

kubernetes还提供了一种亲和性调度(Affinity)。它在NodeSelector的基础之上的进行了扩展,可以通过配置的形式,实现优先选择满足条件的Node进行调度,如果没有,也可以调度到不满足条件的节点上,使调度更加灵活。

Affinity主要分为三类:

  • nodeAffinity(node亲和性): 以node为目标,解决pod可以调度到哪些node的问题
  • podAffinity(pod亲和性) : 以pod为目标,解决pod可以和哪些已存在的pod部署在同一个拓扑域中的问题
  • podAntiAffinity(pod反亲和性) : 以pod为目标,解决pod不能和哪些已存在pod部署在同一个拓扑域中的问题

NodeAffinity

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

  1. RequiredDuringSchedulingIgnoredDuringExecution:必须满足制定的规则才可以调度pode到Node上。相当于硬限制。
  2. PreferredDuringSchedulingIgnoreDuringExecution:强调优先满足制定规则,调度器会尝试调度pod到Node上,但并不强求,相当于软限制。多个优先级规则还可以设置权重值,以定义执行的先后顺序。

首先来看一下NodeAffinity的可配置项:

pod.spec.affinity.nodeAffinity
  requiredDuringSchedulingIgnoredDuringExecution  #Node节点必须满足指定的所有规则才可以,相当于硬限制
    nodeSelectorTerms  #节点选择列表
      matchFields   #按节点字段列出的节点选择器要求列表
      matchExpressions   #按节点标签列出的节点选择器要求列表(推荐)
        key    #键
        values #值
        operat or #关系符 支持Exists, DoesNotExist, In, NotIn, Gt, Lt
  preferredDuringSchedulingIgnoredDuringExecution #优先调度到满足指定的规则的Node,相当于软限制 (倾向)
    preference   #一个节点选择器项,与相应的权重相关联
      matchFields   #按节点字段列出的节点选择器要求列表
      matchExpressions  # 按节点标签列出的节点选择器要求列表(推荐)
        key    #键
        values #值
        operator #关系符 支持In, NotIn, Exists, DoesNotExist, Gt, Lt
  weight #倾向权重,在范围1-100。

例如,下面这个Pod需要部署到不是disktype=ssd标签上的node上。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  affinity:
    nodeAffinity: #设置node亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
        nodeSelectorTerms:
        - matchExpressions: 
          - key: disktype
            operator: NotIn
            values: ["ssd"]

执行创建命令后,该pod会被调度标签disktype值中不包含ssd这个值的node上。

controlplane $ kubectl get pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          20s   192.168.0.4   controlplane   <none>           <none>
controlplane $ kubectl get node --show-labels
NAME           STATUS   ROLES           AGE   VERSION   LABELS
controlplane   Ready    control-plane   15h   v1.29.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=controlplane,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
node01         Ready    <none>          14h   v1.29.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=node01,kubernetes.io/os=linux

podAffinity

podAffinity 是 Kubernetes 中的一种调度机制,它允许您指定一组条件,以影响 Pod 之间的调度关系。具体而言,podAffinity 允许您在同一节点上调度具有相似属性或关系的 Pod,或者在不同节点上调度具有相关属性的 Pod。

podAffinity 同样通过 requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution两种方式来实现。

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

  1. 参照目标Pod

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

apiVersion: v1
kind: Pod
metadata:
  name: pod-flag
  labels:
    security: "S1"
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  1. Pod的亲和性调度

下面创建第 2 个 Pod 来说明 Pod 的亲和性调度,这里定义的亲和标签是security=S1 ,对应上面的 Pod pod-flag, topologyKey 的值被设置为 kubemetes.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: nginx

两个Pod创建成功后,使用kubectl get pods -o wide命令可以看到,这两个 Pod 处于同一个 Node之上运行 。  

controlplane $ kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
pod-affinity   1/1     Running   0          8s    192.168.1.5   node01   <none>           <none>
pod-flag       1/1     Running   0          94s   192.168.1.4   node01   <none>           <none>

在创建pod-affinity这个Pod 之前,删掉这个节点的kubemetes.io/hostname标签,重复上面的创建步骤,将会发现 Pod 会一直处于 Pending 状态,这是因为找不到满足条件的 Node 了。

controlplane $ kubectl label node node01 kubernetes.io/hostname-
node/node01 unlabeled
controlplane $ kubectl get pod
NAME           READY   STATUS    RESTARTS   AGE
pod-affinity   1/1     Running   0          4m49s
pod-flag       1/1     Running   0          6m15s
controlplane $ kubectl delete pod pod-affinity 
pod "pod-affinity" deleted
controlplane $ kubectl apply  -f pod-affinity.yaml 
pod/pod-affinity created
controlplane $ kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
pod-affinity   0/1     Pending   0          16s     <none>        <none>   <none>           <none>
pod-flag       1/1     Running   0          6m59s   192.168.1.4   node01   <none>           <none>
  1. 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: beta.kubernetes.io/arch
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
            - key: app
              operator: In
              values:
              - nginx
        topologyKey: kubernetes.io/hostname
  containers:
  - name: anti-affinity
    image: registry.aliyuncs.com/google_containers/pause:3.1

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

controlplane $ kubectl apply  -f anti-affinity.yaml 
pod/anti-affinity created
controlplane $ kubectl get pod -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
anti-affinity   1/1     Running   0          6s    192.168.0.6   controlplane   <none>           <none>
pod-affinity    1/1     Running   0          24m   192.168.1.6   node01         <none>           <none>
pod-flag        1/1     Running   0          31m   192.168.1.4   node01         <none>           <none>

CKA真题

  1. 真题截图

  1. 中文解析

切换 k8s 集群环境:kubectl config use-context k8s

Task:

创建一个 Pod,名字为 nginx-kusc00401,镜像地址是 nginx,调度到具有 disk=spinning 标签的节点上。

  1. 官方参考文档

指定Pod调度到某个Node

  1. 解题作答
  • 切换切换k8s集群环境
kubectl config use-context k8s
  • 创建Pod的资源对象
apiVersion: v1
kind: Pod
metadata:
  name: nginx-kusc00401
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    disk: spinning
  • 执行命令创建pod
kubectl apply -f nginx-kusc00401.yaml
相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
Kubernetes API 调度
k8s中节点无法启动Pod
【10月更文挑战第3天】
724 6
|
存储 Kubernetes Docker
Kubernetes节点资源耗尽状态的处理
Kubernetes节点资源耗尽状态的处理
|
Kubernetes API 网络安全
当node节点kubectl 命令无法连接到 Kubernetes API 服务器
当Node节点上的 `kubectl`无法连接到Kubernetes API服务器时,可以通过以上步骤逐步排查和解决问题。首先确保网络连接正常,验证 `kubeconfig`文件配置正确,检查API服务器和Node节点的状态,最后排除防火墙或网络策略的干扰,并通过重启服务恢复正常连接。通过这些措施,可以有效解决与Kubernetes API服务器通信的常见问题,从而保障集群的正常运行。
1190 17
|
Kubernetes Shell Windows
【Azure K8S | AKS】在AKS的节点中抓取目标POD的网络包方法分享
在AKS中遇到复杂网络问题时,可通过以下步骤进入特定POD抓取网络包进行分析:1. 使用`kubectl get pods`确认Pod所在Node;2. 通过`kubectl node-shell`登录Node;3. 使用`crictl ps`找到Pod的Container ID;4. 获取PID并使用`nsenter`进入Pod的网络空间;5. 在`/var/tmp`目录下使用`tcpdump`抓包。完成后按Ctrl+C停止抓包。
544 12
|
存储 Kubernetes 调度
在K8S中,⼀个pod的不同container能够分开被调动到不同的节点上吗?
在K8S中,⼀个pod的不同container能够分开被调动到不同的节点上吗?
|
Kubernetes 应用服务中间件 Linux
多Master节点的k8s集群部署
多Master节点的k8s集群部署
|
Kubernetes Unix Linux
k8s将节点容器运行时从Docker迁移到Containerd
k8s将节点容器运行时从Docker迁移到Containerd
|
8月前
|
人工智能 算法 调度
阿里云ACK托管集群Pro版共享GPU调度操作指南
本文介绍在阿里云ACK托管集群Pro版中,如何通过共享GPU调度实现显存与算力的精细化分配,涵盖前提条件、使用限制、节点池配置及任务部署全流程,提升GPU资源利用率,适用于AI训练与推理场景。
676 1
|
8月前
|
弹性计算 监控 调度
ACK One 注册集群云端节点池升级:IDC 集群一键接入云端 GPU 算力,接入效率提升 80%
ACK One注册集群节点池实现“一键接入”,免去手动编写脚本与GPU驱动安装,支持自动扩缩容与多场景调度,大幅提升K8s集群管理效率。
491 89
|
资源调度 Kubernetes 调度
从单集群到多集群的快速无损转型:ACK One 多集群应用分发
本文介绍如何利用阿里云的分布式云容器平台ACK One的多集群应用分发功能,结合云效CD能力,快速将单集群CD系统升级为多集群CD系统。通过增加分发策略(PropagationPolicy)和差异化策略(OverridePolicy),并修改单集群kubeconfig为舰队kubeconfig,可实现无损改造。该方案具备多地域多集群智能资源调度、重调度及故障迁移等能力,帮助用户提升业务效率与可靠性。

热门文章

最新文章

相关产品

  • 容器服务Kubernetes版
  • 推荐镜像

    更多