You need to enable JavaScript to run this app.
导航
NUMA 拓扑感知调度
最近更新时间:2024.12.05 15:37:45首次发布时间:2023.08.30 10:18:19

容器服务支持基于 Katalyst 增强 Kubernetes 资源管理能力,提升资源利用率,降低成本,提升负载的性能。

说明

邀测·申请试用】:该功能目前处于邀测阶段。如需使用,请提交申请。

使用场景

在搜广推、游戏、AI 分布式训练等业务场景下,用户对时延的敏感性较高,对容器在微拓扑级别的摆放方式存在要求。原生 Kubernetes 的微拓扑管理能力存在一些局限。因此容器服务基于 Katalyst 实现了 NUMA(Non-Uniform Memory Access,非统一内存访问架构)拓扑感知调度功能。

推荐使用拓扑感知调度功能的场景如下:

  • 运行开启 NUMA 的弹性裸金属服务器。
  • 计算密集性负载。
  • 在线业务负载。
  • 数据库类型业务场景。

使用说明

使用该功能时,有如下限制和须知事项:

  • 集群 Kubernetes 版本要求:
  • 依赖 VKE 的 scheduler-plugin 组件、katalyst 组件。
  • 依赖节点池 kubelet 自定义配置功能。
  • Pod 的 QoS 级别必须是 Guaranteed,且容器申请的 CPU 资源量是整数的情况下会进行绑核。
  • 完全兼容 Kubernetes 社区的拓扑管理策略

    说明

    VKE 当前在调度时仅支持 single-numa-node 策略,容器(Container)级别亲和。

  • single-numa-node 策略下,Pod 请求(Request)的 CPU 和设备(如 RDMA 或 GPU)的调度与分配,需要满足单个 NUMA Node 的约束,否则会调度失败。

前提条件

  • 已创建满足使用限制的集群。详细操作,请参见 创建集群
  • 集群中已安装 scheduler-plugin 组件。详细操作,请参见 scheduler-plugin 组件
  • 集群中存在自定义节点池,且节点池中节点数不为 0。详细操作,请参见 创建节点池

使用方法

步骤一:安装和配置必要组件

该功能依赖 VKE 的 scheduler-plugin 组件、katalyst 组件,因此需要安装和配置该两个组件。

  1. 登录 容器服务控制台
  2. 在左侧导航栏选择 集群,单击目标集群名称。
  3. 在集群管理页面左侧导航栏选择 组件管理
  4. 组件管理 页面的 调度 页签,安装和配置组件。
    • 找到 katalyst 组件,选择... > 安装,并勾选 拓扑感知调度 特性开关并勾选 CPU 资源管理类型。
      alt
    • 找到 scheduler-plugin 组件,单击 配置,开启 NUMA 拓扑感知调度
      alt

步骤二:开启节点池的拓扑感知能力

  1. 在集群管理页面左侧导航栏选择 节点池
  2. 在目标节点池 操作 列下单击 编辑
  3. 编辑节点池 页面,为节点池配置启用拓扑感知的 Label。
    • 为节点池配置启用拓扑感知的 Label,其中 Key 为vke.node.katalyst.deploy,Value 为true
    • 配置节点池的 kubelet 自定义参数,在节点池上开启拓扑感知能力。
      按如下图配置 kubelet 自定义参数。详细说明,请参见 配置节点池 kubelet 自定义参数
      alt

      注意

      您可以通过开启或关闭节点池的 节点标签及污点自动更新 功能,控制是否同步标签到节点池中的存量节点。关闭该功能时,可能导致存量节点上无法实现拓扑感知调度,请谨慎配置。

  4. 单击 确定,编辑完成节点池。

步骤三:创建工作负载

通过控制台创建

下文以创建无状态负载(Deployment)为例,更多工作负载相关操作,请参见 工作负载

说明

关于工作负载中使用的容器镜像,您可以参考镜像仓库的 推送和拉取镜像 文档内容,提前上传镜像到火山引擎镜像仓库中,也可以直接使用您自己准备的第三方镜像。

  1. 在集群管理页面左侧导航栏选择 工作负载 > 无状态负载,单击 创建无状态负载
  2. 创建无状态负载 页面按实际需求配置负载参数。
    本示例中部分参数按如下说明配置,其余参数的详细配置说明,请参见 创建无状态负载
    ③ 基本信息 步骤中 调度策略 模块下开启 节点亲和调度,并按如下图配置 选择器vke.node.katalyst.deploy In true
    alt
  3. 无状态负载创建成功后,单击负载名称进入详情页,然后单击 实例列表 页签,查看 Pod 实例的运行状态。
    alt
  4. 在集群管理页面左侧导航栏选择 节点池,找到已开启拓扑感知能力的目标节点池,单击名称。
  5. 节点池详情页节点列表 页签,单击节点名称进入 节点详情页
  6. 节点详情页Pod 列表 页签,查看是否有已创建的工作负载相关 Pod。
    如下图所示,表示已创建的工作负载相关 Pod 已被调度到开启拓扑感知能力的节点上。
    alt

通过 YAML 创建

下文以使用公网镜像创建 Pod 为例,演示拓扑感知调度情况。更多业务应用相关 Pod 或工作负载的介绍以及创建方法,请参见 工作负载

  1. 创建 Pod 的 YAML 文件。示例文件test-topo.yaml代码如下:
    apiVersion: v1
    kind: Pod
    metadata:
      name: test-topo  # Pod 名称。
      namespace: default  # Pod 所属命名空间。
    spec:
      affinity:  # Pod 亲和性调度。
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:  #  Pod 亲和性调度选择器。
              - key: vke.node.katalyst.deploy
                operator: In
                values:
                - "true"
      containers:  # Pod 的容器配置。
      - image: redis  # Pod 的容器镜像,可替换为您自己的容器镜像。若使用公网镜像,请确保您的集群能够访问公网。
        name: redis
        resources:
          limits:
            cpu: "63"
            memory: 10Gi
          requests:
            cpu: "63"
            memory: 10Gi
    
  2. 执行以下命令,创建 Pod。
    kubectl apply -f topo-pod.yaml
    
  3. 等待 3~5 分钟后,执行以下命令,查看 Pod 的状态,确保为 Running
    kubectl get pod -owide
    
    预期输出结果:
    NAME        READY   STATUS    RESTARTS   AGE     IP              NODE            NOMINATED NODE   READINESS GATES
    test-topo   1/1     Running   0          3m11s   192.168.16.24   192.168.16.18   <none>           <none>
    

步骤四:查看调度与分配结果

执行如下命令,查看 Pod 被调度到的节点对应的 CustomNodeResource 资源。

kubectl get kcnr -o yaml 192.168.16.18

说明

192.168.16.18替换为您自己节点的 IP 地址。

预期输出如下,Pod 已被调度到该节点,满足 single-numa-node 策略。

apiVersion: node.katalyst.kubewharf.io/v1alpha1
kind: CustomNodeResource
metadata:
  creationTimestamp: "2023-08-18T07:16:46Z"
  generation: 1
  labels:
    beta.kubernetes.io/arch: amd64
    beta.kubernetes.io/instance-type: ecs.ebmhfc2i.32xlarge
    beta.kubernetes.io/os: linux
    cluster.vke.volcengine.com/cluster-name: ccjev51m5kpqf********  # 集群 ID。
    cluster.vke.volcengine.com/machine-name: ncjfhjso70bf9********  # 节点 ID。
    cluster.vke.volcengine.com/machinepool-name: pcjfhjpc3bo2l********  # 节点所属节点池 ID。
    cluster.vke.volcengine.com/machinepool-type: machine-pool
    cluster.vke.volcengine.com/node-name: node-bhp929  # 节点池名称。
    failure-domain.beta.kubernetes.io/region: cn-beijing  # 节点池/节点所在地域。
    failure-domain.beta.kubernetes.io/zone: cn-beijing-a  # 节点池/节点所在可用区。
    kubernetes.io/arch: amd64
    kubernetes.io/hostname: 192.168.16.18  # 节点 IP 地址。
    kubernetes.io/os: linux
    node.kubernetes.io/instance-type: ecs.ebmhfc2i.32xlarge
    topology.kubernetes.io/region: cn-beijing  # 满足拓扑管理策略的地域。
    topology.kubernetes.io/zone: cn-beijing-a  # 满足拓扑管理策略的可用区。
    vke.node.katalyst.deploy: "true"  # 节点是否已开启拓扑感知能力。
  name: 192.168.16.18
  ownerReferences:
  - apiVersion: v1
    blockOwnerDeletion: true
    controller: true
    kind: Node
    name: 192.168.16.18
    uid: ccbaaecb-3e4a-486e-881b-6071********
  resourceVersion: "204363"
  uid: ff26814d-ee52-4c56-b346-6cfa52********
spec: {}
status:
  topologyPolicy: SingleNUMANodeContainerLevel  # 拓扑管理策略(此处为 single-numa-node)和资源粒度(此处为 container 级别)。
  topologyZone:
  - children:
    - name: "0"
      resources:
        allocatable:
          cpu: "61"
        capacity:
          cpu: "64"
      type: Numa
    name: "0"
    resources: {}
    type: Socket
  - children:
    - allocations:
      - consumer: default/test-topo/e0f06c84-d512-43f2-a34f-20c2********  # 被调度的 Pod 所属命名空间/名称/容器 ID。
        requests:
          cpu: "63"
      name: "1"
      resources:
        allocatable:
          cpu: "64"
        capacity:
          cpu: "64"
      type: Numa
    name: "1"
    resources: {}
    type: Socket