<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Volcano on Volcano</title>
    <link>https://deploy-preview-499--volcano-sh.netlify.app/en/</link>
    <description>Recent content in Volcano on Volcano</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <copyright>&amp;copy;2025 Volcano</copyright>
    <lastBuildDate>Mon, 04 May 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="/en/" rel="self" type="application/rss+xml" />
    
    <item>
      <title>User Guide</title>
      <link>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/</link>
      <pubDate>Tue, 03 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/</guid>
      <description>&lt;p&gt;This section contains the User Guide for Volcano.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_vnpu/&#34;&gt;Ascend vNPU User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_capacity_plugin/&#34;&gt;Capacity Plugin User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_cdp_plugin/&#34;&gt;Cooldown Protection Plugin User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_extender/&#34;&gt;Extender User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_gpu_number/&#34;&gt;GPU Number User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_gpu_sharing/&#34;&gt;GPU Sharing User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_configure_scheduler/&#34;&gt;How to Configure Scheduler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_job_policy/&#34;&gt;Volcano Job Policy User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_job_ttl/&#34;&gt;Volcano Job Time to Live User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_enable_dra/&#34;&gt;Dynamic Resource Allocation (DRA) User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_tune_volcano_performance/&#34;&gt;How to Tune Volcano Performance in Large-Scale Scenarios&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_configure_priorityclass_for_job/&#34;&gt;How to configure priorityclass for job&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_mpi_plugin/&#34;&gt;MPI Plugin User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_numa_aware/&#34;&gt;NUMA Aware User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_network_topology_aware_scheduling/&#34;&gt;Network Topology Aware Scheduling User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_nodegroup_plugin/&#34;&gt;Nodegroup Plugin User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_pytorch_plugin/&#34;&gt;Pytorch Plugin User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_ray_plugin/&#34;&gt;Ray Plugin User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_resource_strategy_fit_plugin/&#34;&gt;Resource Strategy Fit Plugin User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_task_topology_plugin/&#34;&gt;Task Topology Plugin User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_hypernode_auto_discovery/&#34;&gt;HyperNode Auto Discovery User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_env_plugin/&#34;&gt;Volcano Job Plugin &amp;ndash; Env User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_ssh_plugin/&#34;&gt;Volcano Job Plugin &amp;ndash; SSH User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_svc_plugin/&#34;&gt;Volcano Job Plugin &amp;ndash; SVC User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_volcano_vgpu/&#34;&gt;Volcano vGPU User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_scheduling_gates_queue_admission/&#34;&gt;Scheduling Gates Queue Admission User Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Scheduling Gates Queue Admission User Guide</title>
      <link>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_scheduling_gates_queue_admission/</link>
      <pubDate>Mon, 04 May 2026 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_scheduling_gates_queue_admission/</guid>
      <description>

&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;

&lt;p&gt;This page describes how to enable and use the &lt;code&gt;SchedulingGatesQueueAdmission&lt;/code&gt; feature to prevent cluster autoscalers (such as &lt;a href=&#34;https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler&#34; target=&#34;_blank&#34;&gt;Cluster Autoscaler&lt;/a&gt; or &lt;a href=&#34;https://karpenter.sh/&#34; target=&#34;_blank&#34;&gt;Karpenter&lt;/a&gt;) from triggering unnecessary scale-ups when pods are waiting for Volcano queue capacity.&lt;/p&gt;

&lt;h2 id=&#34;problem&#34;&gt;Problem&lt;/h2&gt;

&lt;p&gt;Volcano marks pods as &lt;code&gt;Unschedulable&lt;/code&gt; for any allocation failure, whether it&amp;rsquo;s due to insufficient cluster resources (where autoscaling is appropriate) or queue capacity limits (where autoscaling is not needed). Cluster autoscalers cannot distinguish between these scenarios, causing unnecessary node scale-ups.&lt;/p&gt;

&lt;p&gt;The problem is described in detail in the &lt;a href=&#34;https://github.com/volcano-sh/volcano/blob/master/docs/design/scheduling-gates-queue-admission.md&#34; target=&#34;_blank&#34;&gt;design document&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;solution&#34;&gt;Solution&lt;/h2&gt;

&lt;p&gt;This feature uses Kubernetes &lt;a href=&#34;https://kubernetes.io/docs/concepts/scheduling-eviction/pod-scheduling-readiness/&#34; target=&#34;_blank&#34;&gt;&lt;code&gt;schedulingGates&lt;/code&gt;&lt;/a&gt; to hold pods until the queue has capacity. While gated, pods are invisible to autoscalers. The gate is removed only after the queue capacity check passes and if the pod then cannot be scheduled due to missing nodes, it is marked as Unschedulable, allowing autoscalers to respond correctly.&lt;/p&gt;

&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Volcano v1.15+ with the &lt;code&gt;SchedulingGatesQueueAdmission&lt;/code&gt; feature gate enabled.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;capacity&lt;/code&gt; plugin configured in the scheduler (the feature is implemented in the capacity plugin and &lt;a href=&#34;https://github.com/volcano-sh/volcano/issues/5271&#34; target=&#34;_blank&#34;&gt;will soon be integrated in &lt;code&gt;proportion&lt;/code&gt; as well&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;1-enable-the-feature-gate&#34;&gt;1. Enable the Feature Gate&lt;/h2&gt;

&lt;p&gt;The feature is Alpha and disabled by default. Enable it on both the &lt;strong&gt;scheduler&lt;/strong&gt; and &lt;strong&gt;webhook-manager&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&#34;using-helm&#34;&gt;Using Helm&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;helm install volcano volcano/volcano --namespace volcano-system --create-namespace \
  --set custom.scheduler_feature_gates=&amp;quot;SchedulingGatesQueueAdmission=true&amp;quot; \
  --set custom.admission_feature_gates=&amp;quot;SchedulingGatesQueueAdmission=true&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;using-kubectl-apply&#34;&gt;Using kubectl apply&lt;/h3&gt;

&lt;p&gt;Add the following flag to both the &lt;code&gt;volcano-scheduler&lt;/code&gt; and &lt;code&gt;volcano-admission&lt;/code&gt; deployments:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;--feature-gates=SchedulingGatesQueueAdmission=true
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Optionally, configure the number of async gate removal workers (default: &lt;code&gt;5&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;--gate-removal-worker-num=10
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These workers asynchronously process gate removals — each worker picks up a pod whose queue capacity check has passed and removes its scheduling gate, allowing the pod to proceed to scheduling. Increasing this number can help throughput when many pods are being ungated concurrently.&lt;/p&gt;

&lt;h2 id=&#34;2-configure-the-capacity-plugin&#34;&gt;2. Configure the Capacity Plugin&lt;/h2&gt;

&lt;p&gt;Ensure the &lt;code&gt;capacity&lt;/code&gt; plugin is enabled in your scheduler configuration. The reserved resource tracking that prevents race conditions between gate removal and pod allocation is implemented in this plugin.&lt;/p&gt;

&lt;p&gt;Example scheduler configuration:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;actions: &amp;quot;enqueue, allocate, backfill&amp;quot;
tiers:
- plugins:
  - name: priority
  - name: gang
- plugins:
  - name: predicates
  - name: capacity
  - name: nodeorder
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;3-opt-in-pods&#34;&gt;3. Opt-in Pods&lt;/h2&gt;

&lt;p&gt;The feature is opt-in per pod, and &lt;strong&gt;one can start using it by adding the following annotation to pods&lt;/strong&gt; that should use gate-controlled queue admission:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  annotations:
    # Opt-in annotation
    scheduling.volcano.sh/queue-allocation-gate: &amp;quot;true&amp;quot;
spec:
  schedulerName: volcano
  containers:
  - name: worker
    image: nginx
    resources:
      requests:
        cpu: &amp;quot;1&amp;quot;
        memory: &amp;quot;1Gi&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When this pod is created:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Volcano webhook injects a &lt;code&gt;scheduling.volcano.sh/queue-allocation-gate&lt;/code&gt; scheduling gate.&lt;/li&gt;
&lt;li&gt;The pod stays gated (invisible to autoscalers) until the queue has capacity.&lt;/li&gt;
&lt;li&gt;Once capacity is available, the scheduler removes the gate.&lt;/li&gt;
&lt;li&gt;If the pod can be placed on a node, it gets scheduled normally.&lt;/li&gt;
&lt;li&gt;If no node matches (e.g., needs a specific node type), it gets marked &lt;code&gt;Unschedulable&lt;/code&gt;, correctly triggering the autoscaler.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&#34;4-verify-the-feature-is-working&#34;&gt;4. Verify the Feature is Working&lt;/h2&gt;

&lt;p&gt;After creating an opted-in pod, verify the gate was injected by the mutation webhook:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl get pod my-pod -o jsonpath=&#39;{.spec.schedulingGates}&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Expected output (while waiting for queue capacity):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;[{&amp;quot;name&amp;quot;:&amp;quot;scheduling.volcano.sh/queue-allocation-gate&amp;quot;}]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once the queue has capacity and the scheduler removes the gate, the field will be empty:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl get pod my-pod -o jsonpath=&#39;{.spec.schedulingGates}&#39;
# empty output
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;interaction-with-other-scheduling-gates&#34;&gt;Interaction with other Scheduling Gates&lt;/h2&gt;

&lt;p&gt;If a pod has additional scheduling gates from other controllers (&lt;em&gt;e.g.&lt;/em&gt;, &lt;code&gt;example.com/my-gate&lt;/code&gt;), Volcano will not remove its gate until the pod has &lt;strong&gt;only the Volcano gate remaining&lt;/strong&gt;. This ensures Volcano does not interfere with other gate controllers and avoids reserving queue capacity for pods that are still blocked by external dependencies.&lt;/p&gt;

&lt;h2 id=&#34;limitations&#34;&gt;Limitations&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Once a pod&amp;rsquo;s gate is removed, it reserves queue capacity until it is scheduled or deleted. If the pod remains unschedulable (&lt;em&gt;e.g.&lt;/em&gt;, waiting for the autoscaler to add nodes), it continues to hold queue capacity, potentially blocking other pods. Additionally, the feature currently &lt;strong&gt;does not implement a timeout&lt;/strong&gt; for reserved capacity. Operators should be aware that pods that have been ungated but remain unschedulable can hold queue capacity indefinitely.&lt;/li&gt;
&lt;li&gt;The feature is &lt;strong&gt;only implemented in the &lt;code&gt;capacity&lt;/code&gt; plugin&lt;/strong&gt;. Users relying on the &lt;code&gt;proportion&lt;/code&gt; plugin for queue resource management will still face false autoscaler scale-ups, as the scheduling gates mechanism is not yet integrated with &lt;code&gt;proportion&lt;/code&gt;. Tracking issue: &lt;a href=&#34;https://github.com/volcano-sh/volcano/issues/5271&#34; target=&#34;_blank&#34;&gt;#5271&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;related&#34;&gt;Related&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/volcano-sh/volcano/blob/master/docs/design/scheduling-gates-queue-admission.md&#34; target=&#34;_blank&#34;&gt;Design document&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kubernetes.io/docs/concepts/scheduling-eviction/pod-scheduling-readiness/&#34; target=&#34;_blank&#34;&gt;Kubernetes Pod Scheduling Readiness&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Ascend vNPU User Guide</title>
      <link>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_vnpu/</link>
      <pubDate>Tue, 03 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_vnpu/</guid>
      <description>

&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Volcano supports &lt;strong&gt;two vNPU modes&lt;/strong&gt; for sharing Ascend devices:&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&#34;1-mindcluster-mode&#34;&gt;1. MindCluster mode&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;The initial version of &lt;a href=&#34;https://gitcode.com/Ascend/mind-cluster&#34; target=&#34;_blank&#34;&gt;MindCluster&lt;/a&gt;—the official Ascend cluster scheduling add-on—required custom modifications and recompilation of Volcano. Furthermore, it was limited to Volcano release1.7 and release1.9, which complicated its use and restricted access to newer Volcano features.&lt;/p&gt;

&lt;p&gt;To address this, we have integrated its core scheduling logic for Ascend vNPU into Volcano&amp;rsquo;s native device-share plugin, which is designed specifically for scheduling and sharing heterogeneous resources like GPUs and NPUs. This integration provides seamless access to vNPU capabilities through the procedure below, while maintaining full compatibility with the latest Volcano features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use case&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;vNPU cluster for Ascend 310 series&lt;br /&gt;
with support for more chip types to come&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&#34;2-hami-mode&#34;&gt;2. HAMi mode&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Description&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;This mode is developed by a third-party community &amp;lsquo;HAMi&amp;rsquo;, which is the developer of &lt;a href=&#34;./how_to_use_volcano_vgpu.md&#34;&gt;volcano-vgpu&lt;/a&gt; feature. It supports vNPU feature for both Ascend 310 and Ascend 910. It also supports managing heterogeneous Ascend cluster(Cluster with multiple Ascend types, i.e. 910A,910B2,910B3,310P)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use case&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;NPU and vNPU cluster for Ascend 910 series&lt;br /&gt;
NPU and vNPU cluster for Ascend 310 series&lt;br /&gt;
Heterogeneous Ascend cluster&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;

&lt;p&gt;To enable vNPU scheduling, the following components must be set up based on the selected mode:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Kubernetes &amp;gt;= 1.16&lt;br /&gt;
Volcano &amp;gt;= 1.14&lt;br /&gt;
&lt;a href=&#34;https://gitcode.com/Ascend/mind-cluster/tree/master/component/ascend-docker-runtime&#34; target=&#34;_blank&#34;&gt;ascend-docker-runtime&lt;/a&gt; (for HAMi Mode)&lt;/p&gt;

&lt;h3 id=&#34;install-volcano&#34;&gt;Install Volcano:&lt;/h3&gt;

&lt;p&gt;Follow instructions in Volcano Installer Guide&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow instructions in &lt;a href=&#34;https://github.com/volcano-sh/volcano?tab=readme-ov-file#quick-start-guide&#34; target=&#34;_blank&#34;&gt;Volcano Installer Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;install-ascend-device-plugin-and-third-party-components&#34;&gt;Install ascend-device-plugin and third-party components&lt;/h3&gt;

&lt;p&gt;In this step, you need to select different ascend-device-plugin based on the vNPU mode you selected. MindCluster mode requires additional components from Ascend to be installed.&lt;/p&gt;

&lt;hr /&gt;

&lt;h4 id=&#34;mindcluster-mode&#34;&gt;MindCluster Mode&lt;/h4&gt;

&lt;h5 id=&#34;install-third-party-components&#34;&gt;Install Third-Party Components&lt;/h5&gt;

&lt;p&gt;Follow the official &lt;a href=&#34;https://www.hiascend.com/document/detail/zh/mindcluster/72rc1/clustersched/dlug/mxdlug_start_006.html#ZH-CN_TOPIC_0000002470358262__section1837511531098&#34; target=&#34;_blank&#34;&gt;Ascend documentation&lt;/a&gt; to install the following components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NodeD&lt;/li&gt;
&lt;li&gt;Ascend Device Plugin&lt;/li&gt;
&lt;li&gt;Ascend Docker Runtime&lt;/li&gt;
&lt;li&gt;ClusterD&lt;/li&gt;
&lt;li&gt;Ascend Operator&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Skip the installation of &lt;code&gt;ascend-volcano&lt;/code&gt; mentioned in the document above, as we have already installed the native Volcano from the Volcano community in the &lt;strong&gt;Prerequisites&lt;/strong&gt; part.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Configuration Adjustment for Ascend Device Plugin:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When installing &lt;code&gt;ascend-device-plugin&lt;/code&gt;, you must set the &lt;code&gt;presetVirtualDevice&lt;/code&gt; parameter to &lt;code&gt;&amp;quot;false&amp;quot;&lt;/code&gt; in the &lt;code&gt;device-plugin-310P-volcano-v{version}.yaml&lt;/code&gt; file to enable dynamic virtualization of 310P:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;
...
args:
  [
    &amp;quot;device-plugin&amp;quot;,
    &amp;quot;-useAscendDocker=true&amp;quot;,
    &amp;quot;-volcanoType=true&amp;quot;,
    &amp;quot;-presetVirtualDevice=false&amp;quot;,
    &amp;quot;-logFile=/var/log/mindx-dl/devicePlugin/devicePlugin.log&amp;quot;,
    &amp;quot;-logLevel=0&amp;quot;,
  ]
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For detailed information, please consult the official &lt;a href=&#34;https://www.hiascend.com/document/detail/zh/mindcluster/72rc1/clustersched/dlug/cpaug_0020.html&#34; target=&#34;_blank&#34;&gt;Ascend MindCluster documentation.&lt;/a&gt;&lt;/p&gt;

&lt;h5 id=&#34;scheduler-config-update&#34;&gt;Scheduler Config Update&lt;/h5&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: ConfigMap
apiVersion: v1
metadata:
  name: volcano-scheduler-configmap
  namespace: volcano-system
data:
  volcano-scheduler.conf: |
    actions: &amp;quot;enqueue, allocate, backfill&amp;quot;
    tiers:
    - plugins:
      - name: predicates
      - name: deviceshare
        arguments:
          deviceshare.AscendMindClusterVNPUEnable: true   # enable ascend vnpu
    configurations:
    ...
    - name: init-params
      arguments: {&amp;quot;grace-over-time&amp;quot;:&amp;quot;900&amp;quot;,&amp;quot;presetVirtualDevice&amp;quot;:&amp;quot;false&amp;quot;}  # to enable dynamic virtualization, presetVirtualDevice need to be set false
&lt;/code&gt;&lt;/pre&gt;

&lt;hr /&gt;

&lt;h4 id=&#34;hami-mode&#34;&gt;HAMi mode&lt;/h4&gt;

&lt;h5 id=&#34;label-the-node-with-ascend-on&#34;&gt;Label the Node with &lt;code&gt;ascend=on&lt;/code&gt;&lt;/h5&gt;

&lt;pre&gt;&lt;code&gt;kubectl label node {ascend-node} ascend=on
&lt;/code&gt;&lt;/pre&gt;

&lt;h5 id=&#34;deploy-hami-scheduler-device-configmap&#34;&gt;Deploy &lt;code&gt;hami-scheduler-device&lt;/code&gt; ConfigMap&lt;/h5&gt;

&lt;pre&gt;&lt;code&gt;kubectl apply -f https://raw.githubusercontent.com/Project-HAMi/ascend-device-plugin/refs/heads/main/ascend-device-configmap.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;h5 id=&#34;deploy-ascend-device-plugin&#34;&gt;Deploy ascend-device-plugin&lt;/h5&gt;

&lt;pre&gt;&lt;code&gt;kubectl apply -f https://raw.githubusercontent.com/Project-HAMi/ascend-device-plugin/refs/heads/main/ascend-device-plugin.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For more information, refer to the &lt;a href=&#34;https://github.com/Project-HAMi/ascend-device-plugin&#34; target=&#34;_blank&#34;&gt;ascend-device-plugin documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h5 id=&#34;scheduler-config-update-1&#34;&gt;Scheduler Config Update&lt;/h5&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: ConfigMap
apiVersion: v1
metadata:
  name: volcano-scheduler-configmap
  namespace: volcano-system
data:
  volcano-scheduler.conf: |
    actions: &amp;quot;enqueue, allocate, backfill&amp;quot;
    tiers:
    - plugins:
      - name: predicates
      - name: deviceshare
        arguments:
          deviceshare.AscendHAMiVNPUEnable: true   # enable ascend vnpu
          deviceshare.SchedulePolicy: binpack  # scheduling policy. binpack / spread
          deviceshare.KnownGeometriesCMNamespace: kube-system
          deviceshare.KnownGeometriesCMName: hami-scheduler-device
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You may notice that, &amp;lsquo;volcano-vgpu&amp;rsquo; has its own GeometriesCMName and GeometriesCMNamespace, which means if you want to use both vNPU and vGPU in a same volcano cluster, you need to merge the configMap from both sides and set it here.&lt;/p&gt;

&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;

&lt;p&gt;Usage is different depending on the mode you selected&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&#34;mindcluster-mode-1&#34;&gt;MindCluster mode&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
  name: mindx-dls
  namespace: vnpu
  labels:
    ring-controller.atlas: ascend-310P
spec:
  minAvailable: 1
  schedulerName: volcano
  policies:
    - event: PodEvicted
      action: RestartJob
  plugins:
    ssh: []
    env: []
    svc: []
  maxRetry: 3
  queue: default
  tasks:
    - name: &amp;quot;default-test&amp;quot;
      replicas: 1
      template:
        metadata:
          labels:
            app: infers
            ring-controller.atlas: ascend-310P
            vnpu-dvpp: &amp;quot;null&amp;quot;
            vnpu-level: low
        spec:
          schedulerName: volcano
          containers:
            - name: resnet50infer
              image: swr.cn-south-1.myhuaweicloud.com/ascendhub/mindie:2.1.RC1-300I-Duo-py311-openeuler24.03-lts
              imagePullPolicy: IfNotPresent
              securityContext:
                privileged: false
              command: [&amp;quot;/bin/bash&amp;quot;, &amp;quot;-c&amp;quot;, &amp;quot;tail -f /dev/null&amp;quot;]
              resources:
                requests:
                  huawei.com/npu-core: 8
                limits:
                  huawei.com/npu-core: 8
          nodeSelector:
            host-arch: huawei-arm
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The supported Ascend chips and their &lt;code&gt;ResourceNames&lt;/code&gt; are shown in the following table:&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ChipName&lt;/th&gt;
&lt;th&gt;JobLabel and TaskLabel&lt;/th&gt;
&lt;th&gt;ResourceName&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;310P3&lt;/td&gt;
&lt;td&gt;ring-controller.atlas: ascend-310P&lt;/td&gt;
&lt;td&gt;huawei.com/npu-core&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Description of Labels in the Virtualization Task YAML&lt;/strong&gt;&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Key&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Value&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;vnpu-level&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;low&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low configuration (default). Selects the lowest-configuration &amp;ldquo;virtualized instance template.&amp;rdquo;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;high&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Performance-first. When cluster resources are sufficient, the scheduler will choose the highest-configured virtualized instance template possible. When most physical NPUs in the cluster are already in use and only a few AI Cores remain on each device, the scheduler will allocate templates that match the remaining AI Core count rather than forcing high-profile templates. For details, refer to the table below.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;vnpu-dvpp&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;yes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The Pod uses DVPP.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;no&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The Pod does not use DVPP.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;null&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Default value. DVPP usage is not considered.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ring-controller.atlas&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;ascend-310P&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Indicates that the task uses products from the Atlas inference series.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Effect of DVPP and Level Configurations&lt;/strong&gt;&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Product Model&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Requested AI Core Count&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;vnpu-dvpp&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;vnpu-level&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Downgrade&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Selected Template&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Atlas Inference Series (8 AI Cores)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any value&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vir01&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;low&lt;/code&gt; / other values&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vir02_1c&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;high&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vir02&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;high&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vir02_1c&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;yes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;low&lt;/code&gt; / other values&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vir04_4c_dvpp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;no&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;low&lt;/code&gt; / other values&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vir04_3c_ndvpp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;low&lt;/code&gt; / other values&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vir04_3c&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;yes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;high&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vir04_4c_dvpp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;no&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;high&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vir04_3c_ndvpp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;high&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vir04&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;high&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;&lt;code&gt;vir04_3c&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;8 or multiples of 8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Any value&lt;/td&gt;
&lt;td&gt;Any value&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Notice&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;chip virtualization (non-full card usage)&lt;/strong&gt;, the value of &lt;code&gt;vnpu-dvpp&lt;/code&gt; must strictly match the corresponding value listed in the above table.
Any other values will cause the task to fail to be dispatched.&lt;/p&gt;

&lt;p&gt;For detailed information, please consult the official &lt;a href=&#34;https://www.hiascend.com/document/detail/zh/mindcluster/72rc1/clustersched/dlug/cpaug_0020.html&#34; target=&#34;_blank&#34;&gt;Ascend MindCluster documentation.&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&#34;hami-mode-1&#34;&gt;HAMi mode&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: v1
kind: Pod
metadata:
  name: ascend-pod
spec:
  schedulerName: volcano
  containers:
    - name: ubuntu-container
      image: swr.cn-south-1.myhuaweicloud.com/ascendhub/ascend-pytorch:24.0.RC1-A2-1.11.0-ubuntu20.04
      command: [&amp;quot;sleep&amp;quot;]
      args: [&amp;quot;100000&amp;quot;]
      resources:
        limits:
          huawei.com/Ascend310P: &amp;quot;1&amp;quot;
          huawei.com/Ascend310P-memory: &amp;quot;4096&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The supported Ascend chips and their &lt;code&gt;ResourceNames&lt;/code&gt; are shown in the following table:&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ChipName&lt;/th&gt;
&lt;th&gt;ResourceName&lt;/th&gt;
&lt;th&gt;ResourceMemoryName&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;910A&lt;/td&gt;
&lt;td&gt;huawei.com/Ascend910A&lt;/td&gt;
&lt;td&gt;huawei.com/Ascend910A-memory&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;910B2&lt;/td&gt;
&lt;td&gt;huawei.com/Ascend910B2&lt;/td&gt;
&lt;td&gt;huawei.com/Ascend910B2-memory&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;910B3&lt;/td&gt;
&lt;td&gt;huawei.com/Ascend910B3&lt;/td&gt;
&lt;td&gt;huawei.com/Ascend910B3-memory&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;910B4&lt;/td&gt;
&lt;td&gt;huawei.com/Ascend910B4&lt;/td&gt;
&lt;td&gt;huawei.com/Ascend910B4-memory&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;910B4-1&lt;/td&gt;
&lt;td&gt;huawei.com/Ascend910B4-1&lt;/td&gt;
&lt;td&gt;huawei.com/Ascend910B4-1-memory&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;310P3&lt;/td&gt;
&lt;td&gt;huawei.com/Ascend310P&lt;/td&gt;
&lt;td&gt;huawei.com/Ascend310P-memory&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;h4 id=&#34;hami-vnpu-scene-memory-allocation-restrictions&#34;&gt;Hami vNPU scene memory allocation restrictions&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When a Pod requests a single vNPU device, the memory can be configured to any value, and the memory request of the job will automatically align with the closest sharding strategy&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Example: Single card memory is 65536, virtualization templates are &lt;sup&gt;1&lt;/sup&gt;&amp;frasl;&lt;sub&gt;4&lt;/sub&gt; (16384), &lt;sup&gt;1&lt;/sup&gt;&amp;frasl;&lt;sub&gt;2&lt;/sub&gt; (32768)&lt;/li&gt;
&lt;li&gt;Pod requests 1 vNPU device and requests 1024 memory, so the actual allocated memory is 16384&lt;/li&gt;
&lt;li&gt;Pod requests 1 vNPU device with a requested memory of 20480, resulting in an actual allocated memory of 32768&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;When a Pod requests multiple vNPU devices, the memory resource request can be left unspecified or filled with the maximum value, The memory allocated to Pod is the actual memory of the entire card&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Capacity Plugin User Guide</title>
      <link>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_capacity_plugin/</link>
      <pubDate>Tue, 03 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_capacity_plugin/</guid>
      <description>

&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Capacity plugin is a replacement of proportion plugin, but instead of dividing the queue&amp;rsquo;s deserved resources by weight, it realizes elastic queue capacity management i.e., queue&amp;rsquo;s resource borrowing and lending mechanism by specifying the amount of deserved resources for each dimension resource of the queue.&lt;/p&gt;

&lt;p&gt;A queue can use the idle resources of other queues, and when other queues submit jobs, they can reclaim the resources that have been lent, and the amount of reclaimed resources is the amount of queue&amp;rsquo;s deserved resources. For more detail,  please see &lt;a href=&#34;../design/capacity-scheduling.md&#34;&gt;Capacity scheduling design&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;environment-setup&#34;&gt;Environment setup&lt;/h2&gt;

&lt;h3 id=&#34;install-volcano&#34;&gt;Install volcano&lt;/h3&gt;

&lt;p&gt;Refer to &lt;a href=&#34;https://github.com/volcano-sh/volcano/blob/master/installer/README.md&#34; target=&#34;_blank&#34;&gt;Install Guide&lt;/a&gt; to install volcano.&lt;/p&gt;

&lt;p&gt;After installed, update the scheduler configuration:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;kubectl edit cm -n volcano-system volcano-scheduler-configmap
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Please make sure&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reclaim action is enabled.&lt;/li&gt;
&lt;li&gt;capacity plugin is enabled and proportion plugin is removed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note:  capacity and proportion plugin are in conflict, the two plugins cannot be used together.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: ConfigMap
apiVersion: v1
metadata:
  name: volcano-scheduler-configmap
  namespace: volcano-system
data:
  volcano-scheduler.conf: |
    actions: &amp;quot;enqueue, allocate, backfill, reclaim&amp;quot; # add reclaim action.
    tiers:
    - plugins:
      - name: priority
      - name: gang
        enablePreemptable: false
      - name: conformance
    - plugins:
      - name: drf
        enablePreemptable: false
      - name: predicates
      - name: capacity # add this field and remove proportion plugin.
      - name: nodeorder
      - name: binpack
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;config-queue-s-deserved-resources&#34;&gt;Config queue&amp;rsquo;s deserved resources&lt;/h2&gt;

&lt;p&gt;Assume there are two nodes and two queues named queue1 and queue2 in your kubernetes cluster, and each node has 4 CPU and 16Gi memory, then there will be total 8 CPU and 32Gi memory in your cluster.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;allocatable:
  cpu: &amp;quot;4&amp;quot;
  memory: 16Gi
  pods: &amp;quot;110&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;config queue1&amp;rsquo;s deserved field with 2 cpu and 8Gi memory.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: scheduling.volcano.sh/v1beta1
kind: Queue
metadata:
  name: queue1
spec:
  reclaimable: true
  deserved: # set the deserved field.
    cpu: 2
    memory: 8Gi
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;config queue2&amp;rsquo;s deserved field with 6 cpu and 24Gi memory.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: scheduling.volcano.sh/v1beta1
kind: Queue
metadata:
  name: queue2
spec:
  reclaimable: true
  deserved: # set the deserved field.
    cpu: 6
    memory: 24Gi
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;submit-pods-to-each-queue&#34;&gt;Submit pods to each queue&lt;/h2&gt;

&lt;p&gt;First, submit a deployment named demo-1 to queue1 with replicas=8 and each pod requests 1 cpu and 4Gi memory, because queue2 is idle, so queue1 can use the whole clusters&amp;rsquo; resources, and you can see that 8 pods are in Running state.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-1
spec:
  selector:
    matchLabels:
      app: demo-1
  replicas: 8
  template:
    metadata:
      labels:
        app: demo-1
      annotations:
        scheduling.volcano.sh/queue-name: &amp;quot;queue1&amp;quot; # set the queue
    spec:
      schedulerName: volcano
      containers:
      - name: nginx
        image: nginx:1.14.2
        resources:
          requests:
            cpu: 1
            memory: 4Gi
        ports:
        - containerPort: 80
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Expected result:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl get po                                                                                             
NAME                      READY   STATUS    RESTARTS   AGE
demo-1-7bc649f544-2wjg7   1/1     Running   0          5s
demo-1-7bc649f544-cvsmr   1/1     Running   0          5s
demo-1-7bc649f544-j5lzp   1/1     Running   0          5s
demo-1-7bc649f544-jvlbx   1/1     Running   0          5s
demo-1-7bc649f544-mzgg2   1/1     Running   0          5s
demo-1-7bc649f544-ntrs2   1/1     Running   0          5s
demo-1-7bc649f544-nv424   1/1     Running   0          5s
demo-1-7bc649f544-zd6d9   1/1     Running   0          5s
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then submit a deployment named demo-2 to queue2 with replicas=8 and each pod requests 1 cpu and 4Gi memory.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-2
spec:
  selector:
    matchLabels:
      app: demo-2
  replicas: 8
  template:
    metadata:
      labels:
        app: demo-2
      annotations:
        scheduling.volcano.sh/queue-name: &amp;quot;queue2&amp;quot; # set the queue
    spec:
      schedulerName: volcano
      containers:
      - name: nginx
        image: nginx:1.14.2
        resources:
          requests:
            cpu: 1
            memory: 4Gi
        ports:
        - containerPort: 80
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Because queue1 occupied queue2&amp;rsquo;s resources, so queue2 will reclaim its deserved resources with 6 cpu and 24Gi memory. And each pod of demo-2 request 1 cpu and 4Gi memory, so there will be 6 Pods in Running state of demo-2,  and demo-1&amp;rsquo;s pods will be evicted.&lt;/p&gt;

&lt;p&gt;Finally, you can see that there are 2 Running pods in demo-1(belongs to queue1), and 6 Running pods in demo-2(belongs to queue2), which meets queue&amp;rsquo;s deserved resources respectively.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl get po                                                                                             
NAME                      READY   STATUS    RESTARTS   AGE
demo-1-7bc649f544-4vvdv   0/1     Pending   0          37s
demo-1-7bc649f544-c6mds   0/1     Pending   0          37s
demo-1-7bc649f544-j5lzp   1/1     Running   0          14m
demo-1-7bc649f544-mzgg2   1/1     Running   0          14m
demo-1-7bc649f544-pqdgk   0/1     Pending   0          37s
demo-1-7bc649f544-tx6wp   0/1     Pending   0          37s
demo-1-7bc649f544-wmshq   0/1     Pending   0          37s
demo-1-7bc649f544-wrhrr   0/1     Pending   0          37s
demo-2-6dfb86c49b-2jvgm   0/1     Pending   0          37s
demo-2-6dfb86c49b-dnjzv   1/1     Running   0          37s
demo-2-6dfb86c49b-fzvmp   1/1     Running   0          37s
demo-2-6dfb86c49b-jlf69   1/1     Running   0          37s
demo-2-6dfb86c49b-k62f7   1/1     Running   0          37s
demo-2-6dfb86c49b-k9b9v   1/1     Running   0          37s
demo-2-6dfb86c49b-rpzvg   0/1     Pending   0          37s
demo-2-6dfb86c49b-zch7w   1/1     Running   0          37s
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Cooldown Protection Plugin User Guide</title>
      <link>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_cdp_plugin/</link>
      <pubDate>Tue, 03 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_cdp_plugin/</guid>
      <description>

&lt;h2 id=&#34;background&#34;&gt;Background&lt;/h2&gt;

&lt;p&gt;When we need to enable elastic training or serving, preemptible job&amp;rsquo;s pods can be preempted or back to running repeatedly, if no cooldown protection set, these pods can be preempted again after they just started for a short time, this may cause service stability dropped.
So we add &amp;ldquo;cdp&amp;rdquo; plugin to ensure preemptible job&amp;rsquo;s pods can run for at least some time set by user.&lt;/p&gt;

&lt;h2 id=&#34;environment-setup&#34;&gt;Environment setup&lt;/h2&gt;

&lt;h3 id=&#34;install-volcano&#34;&gt;Install volcano&lt;/h3&gt;

&lt;p&gt;Refer to &lt;a href=&#34;https://github.com/volcano-sh/volcano/blob/master/installer/README.md&#34; target=&#34;_blank&#34;&gt;Install Guide&lt;/a&gt; to install volcano.&lt;/p&gt;

&lt;h3 id=&#34;update-scheduler-configmap&#34;&gt;Update scheduler configmap&lt;/h3&gt;

&lt;p&gt;After installed, update the scheduler configuration:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;kubectl edit configmap -n volcano-system volcano-scheduler-configmap
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Register &lt;code&gt;cdp&lt;/code&gt; plugin in configmap while enable &lt;code&gt;preempt&lt;/code&gt; action&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: ConfigMap
apiVersion: v1
metadata:
  name: volcano-scheduler-configmap
  namespace: volcano-system
data:
  volcano-scheduler.conf: |
    actions: &amp;quot;enqueue, allocate, preempt, backfill&amp;quot;
    tiers:
    - plugins:
      - name: priority
      - name: gang
      - name: conformance
      - name: cdp
    - plugins:
      - name: drf
      - name: predicates
      - name: task-topology
        arguments:
          task-topology.weight: 10
      - name: proportion
      - name: nodeorder
      - name: binpack
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;running-jobs&#34;&gt;Running Jobs&lt;/h3&gt;

&lt;p&gt;Take a simple volcano job as sample.&lt;/p&gt;

&lt;p&gt;original job yaml is as below, which has &amp;ldquo;ps&amp;rdquo; and &amp;ldquo;worker&amp;rdquo; task&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
  name: test-job
spec:
  minAvailable: 3
  schedulerName: volcano
  priorityClassName: high-priority
  plugins:
    ssh: []
    env: []
    svc: []
  maxRetry: 5
  queue: default
  volumes:
    - mountPath: &amp;quot;/myinput&amp;quot;
    - mountPath: &amp;quot;/myoutput&amp;quot;
      volumeClaimName: &amp;quot;testvolumeclaimname&amp;quot;
      volumeClaim:
        accessModes: [ &amp;quot;ReadWriteOnce&amp;quot; ]
        storageClassName: &amp;quot;my-storage-class&amp;quot;
        resources:
          requests:
            storage: 1Gi
  tasks:
    - replicas: 6
      name: &amp;quot;worker&amp;quot;
      template:
        metadata:
          name: worker
        spec:
          containers:
            - image: nginx
              imagePullPolicy: IfNotPresent
              name: nginx
              resources:
                requests:
                  cpu: &amp;quot;1&amp;quot;
          restartPolicy: OnFailure
    - replicas: 2
      name: &amp;quot;ps&amp;quot;
      template:
        metadata:
          name: ps
        spec:
          containers:
            - image: nginx
              imagePullPolicy: IfNotPresent
              name: nginx
              resources:
                requests:
                  cpu: &amp;quot;1&amp;quot;
          restartPolicy: OnFailure

&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;edit-yaml-of-vcjob&#34;&gt;Edit yaml of vcjob&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;add annotations in volcano job in format below.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;volcano.sh/preemptable&lt;/code&gt; annotation indicates that job or task is preemptable&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;volcano.sh/cooldown-time&lt;/code&gt; annotation indicates cooldown time for the entire job or dedicated task. Value for the annotation indicates cooldown time, valid time units are &amp;ldquo;ns&amp;rdquo;, &amp;ldquo;us&amp;rdquo; (or &amp;ldquo;µs&amp;rdquo;), &amp;ldquo;ms&amp;rdquo;, &amp;ldquo;s&amp;rdquo;, &amp;ldquo;m&amp;rdquo;, &amp;ldquo;h&amp;rdquo;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;    volcano.sh/preemptable: &amp;quot;true&amp;quot;
    volcano.sh/cooldown-time: &amp;quot;600s&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add annotation to entire job, then &amp;ldquo;ps&amp;rdquo; and &amp;ldquo;worker&amp;rdquo; task can be preempted and all have cooldown time support.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
  name: test-job
  annotations:
    volcano.sh/preemptable: &amp;quot;true&amp;quot;
    volcano.sh/cooldown-time: &amp;quot;600s&amp;quot;
spec:
  ... # below keep the same
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Example 2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add annotation to dedicated task, as shown below, only &amp;ldquo;worker&amp;rdquo; can be preempted and have cooldown time support.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
  name: test-job
spec:
  minAvailable: 3
  schedulerName: volcano
  priorityClassName: high-priority
  plugins:
    ssh: []
    env: []
    svc: []
  maxRetry: 5
  queue: default
  volumes:
    - mountPath: &amp;quot;/myinput&amp;quot;
    - mountPath: &amp;quot;/myoutput&amp;quot;
      volumeClaimName: &amp;quot;testvolumeclaimname&amp;quot;
      volumeClaim:
        accessModes: [ &amp;quot;ReadWriteOnce&amp;quot; ]
        storageClassName: &amp;quot;my-storage-class&amp;quot;
        resources:
          requests:
            storage: 1Gi
  tasks:
    - replicas: 6
      name: &amp;quot;worker&amp;quot;
      template:
        metadata:
          name: worker
          annotations:     # add annotation in tasks
            volcano.sh/preemptable: &amp;quot;true&amp;quot;
            volcano.sh/cooldown-time: &amp;quot;600s&amp;quot;
        spec:
          containers:
            - image: nginx
              imagePullPolicy: IfNotPresent
              name: nginx
              resources:
                requests:
                  cpu: &amp;quot;1&amp;quot;
          restartPolicy: OnFailure
    - replicas: 2
      name: &amp;quot;ps&amp;quot;
      template:
        metadata:
          name: ps
        spec:
          containers:
            - image: nginx
              imagePullPolicy: IfNotPresent
              name: nginx
              resources:
                requests:
                  cpu: &amp;quot;1&amp;quot;
          restartPolicy: OnFailure

&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Extender User Guide</title>
      <link>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_extender/</link>
      <pubDate>Tue, 03 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_extender/</guid>
      <description>

&lt;h3 id=&#34;install-volcano&#34;&gt;Install volcano&lt;/h3&gt;

&lt;h4 id=&#34;1-install-from-source&#34;&gt;1. Install from source&lt;/h4&gt;

&lt;p&gt;Refer to &lt;a href=&#34;https://github.com/volcano-sh/volcano/blob/master/installer/README.md&#34; target=&#34;_blank&#34;&gt;Install Guide&lt;/a&gt; to install volcano.&lt;/p&gt;

&lt;h4 id=&#34;2-deploy-extender&#34;&gt;2. Deploy extender&lt;/h4&gt;

&lt;p&gt;Deploy extender into kubernetes cluster. Extender needs to expose domain name or IP address and verbs that can be provided.&lt;/p&gt;

&lt;h4 id=&#34;3-update-volcano-configuration&#34;&gt;3. Update Volcano configuration&lt;/h4&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;kubectl edit cm -n volcano-system volcano-scheduler-configmap
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Users can view the meaning of the parameters through the &lt;a href=&#34;https://github.com/volcano-sh/volcano/blob/master/docs/design/extender.md&#34; target=&#34;_blank&#34;&gt;documentation&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: ConfigMap
apiVersion: v1
metadata:
  name: volcano-scheduler-configmap
  namespace: volcano-system
data:
  volcano-scheduler.conf: |
    actions: &amp;quot;reclaim, allocate, backfill, preempt&amp;quot;
    tiers:
    - plugins:
      - name: priority
      - name: gang
      - name: conformance
    - plugins:
      - name: drf
      - name: predicates
      - name: extender
        arguments:
          extender.urlPrefix: http://127.0.0.1:8713
          extender.httpTimeout: 100ms
          extender.onSessionOpenVerb: onSessionOpen
          extender.onSessionCloseVerb: onSessionClose
          extender.predicateVerb: predicate
          extender.prioritizeVerb: prioritize
          extender.preemptableVerb: preemptable
          extender.reclaimableVerb: reclaimable
          extender.queueOverusedVerb: queueOverused
          extender.jobEnqueueableVerb: jobEnqueueable
          extender.ignorable: true
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;verify-extender-is-working&#34;&gt;Verify Extender is working&lt;/h3&gt;

&lt;p&gt;The user can see in the log something like : &amp;lsquo;Initialize extender plugin with configuration : {your configuration}&amp;rsquo;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>GPU Number User guide</title>
      <link>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_gpu_number/</link>
      <pubDate>Tue, 03 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_gpu_number/</guid>
      <description>

&lt;h2 id=&#34;important-note&#34;&gt;Important Note&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; GPU Number is deprecated in volcano v1.9, recommended to use the Volcano VGPU feature, which is provided by HAMI project, click &lt;a href=&#34;https://github.com/Project-HAMi/volcano-vgpu-device-plugin&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;environment-setup&#34;&gt;Environment setup&lt;/h2&gt;

&lt;h3 id=&#34;install-volcano&#34;&gt;Install volcano&lt;/h3&gt;

&lt;h4 id=&#34;1-install-from-source&#34;&gt;1. Install from source&lt;/h4&gt;

&lt;p&gt;Refer to &lt;a href=&#34;https://github.com/volcano-sh/volcano/blob/master/installer/README.md&#34; target=&#34;_blank&#34;&gt;Install Guide&lt;/a&gt; to install volcano.&lt;/p&gt;

&lt;p&gt;After installed, update the scheduler configuration:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;kubectl edit cm -n volcano-system volcano-scheduler-configmap
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For volcano v1.8.2+(v1.8.2 excluded), use the following configMap&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: ConfigMap
apiVersion: v1
metadata:
  name: volcano-scheduler-configmap
  namespace: volcano-system
data:
  volcano-scheduler.conf: |
    actions: &amp;quot;enqueue, allocate, backfill&amp;quot;
    tiers:
    - plugins:
      - name: priority
      - name: gang
      - name: conformance
    - plugins:
      - name: drf
      - name: deviceshare
        arguments:
          deviceshare.GPUNumberEnable: true # enable gpu number
      - name: predicates
      - name: proportion
      - name: nodeorder
      - name: binpack
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For volcano v1.8.2-(v1.8.2 included), use the following configMap&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: ConfigMap
apiVersion: v1
metadata:
  name: volcano-scheduler-configmap
  namespace: volcano-system
data:
  volcano-scheduler.conf: |
    actions: &amp;quot;enqueue, allocate, backfill&amp;quot;
    tiers:
    - plugins:
      - name: priority
      - name: gang
      - name: conformance
    - plugins:
      - name: drf
      - name: predicates
        arguments:
          predicate.GPUNumberEnable: true # enable gpu number
      - name: proportion
      - name: nodeorder
      - name: binpack
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;2-install-from-release-package&#34;&gt;2. Install from release package.&lt;/h4&gt;

&lt;p&gt;Same as above, after installed, update the scheduler configuration in &lt;code&gt;volcano-scheduler-configmap&lt;/code&gt; configmap.&lt;/p&gt;

&lt;h3 id=&#34;install-volcano-device-plugin&#34;&gt;Install Volcano device plugin&lt;/h3&gt;

&lt;p&gt;Please refer to &lt;a href=&#34;https://github.com/volcano-sh/devices/blob/master/README.md#quick-start&#34; target=&#34;_blank&#34;&gt;volcano device plugin&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remember to config volcano device plugin to support gpu-number, users need to config volcano device plugin &amp;ndash;gpu-strategy=number. For more information &lt;a href=&#34;https://github.com/volcano-sh/devices/blob/master/doc/config.md&#34; target=&#34;_blank&#34;&gt;volcano device plugin configuration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;verify-environment-is-ready&#34;&gt;Verify environment is ready&lt;/h3&gt;

&lt;p&gt;Check the node status, it is ok  &lt;code&gt;volcano.sh/gpu-number&lt;/code&gt; is included in the allocatable resources.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl get node {node name} -oyaml
...
Capacity:
  attachable-volumes-gce-pd:  127
  cpu:                        2
  ephemeral-storage:          98868448Ki
  hugepages-1Gi:              0
  hugepages-2Mi:              0
  memory:                     7632596Ki
  pods:                       110
  volcano.sh/gpu-memory:      0
  volcano.sh/gpu-number:      1
Allocatable:
  attachable-volumes-gce-pd:  127
  cpu:                        1930m
  ephemeral-storage:          47093746742
  hugepages-1Gi:              0
  hugepages-2Mi:              0
  memory:                     5752532Ki
  pods:                       110
  volcano.sh/gpu-memory:      0
  volcano.sh/gpu-number:      1
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;running-jobs-with-multiple-gpu-cards&#34;&gt;Running Jobs With Multiple GPU Cards&lt;/h3&gt;

&lt;p&gt;Jobs can have multiple exclusive NVIDIA GPUs cards via defining container level resource requirements &lt;code&gt;volcano.sh/gpu-number&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ cat &amp;lt;&amp;lt;EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod1
spec:
  containers:
    - name: cuda-container
      image: nvidia/cuda:9.0-devel
      command: [&amp;quot;sleep&amp;quot;]
      args: [&amp;quot;100000&amp;quot;]
      resources:
        limits:
          volcano.sh/gpu-number: 1 # requesting 1 gpu cards
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If the above pods claim multiple gpu cards, you can see each of them has exclusive gpu cards:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl exec -ti  gpu-pod1 env
...
NVIDIA_VISIBLE_DEVICES=0
VOLCANO_GPU_ALLOCATED=1
...
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;understanding-how-multiple-gpu-cards-requirement-works&#34;&gt;Understanding How Multiple GPU Cards Requirement Works&lt;/h3&gt;

&lt;p&gt;The main architecture is similar as the previous, but the gpu-index results of each pod will be a list of gpu cards index.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://deploy-preview-499--volcano-sh.netlify.app/img/gpu-virtualization/gpu-number.png&#34; alt=&#34;gpu_number&#34; /&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;create a pod with &lt;code&gt;volcano.sh/gpu-number&lt;/code&gt; resource request,&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;volcano scheduler predicates and allocate gpu cards to the pod. Add the below annotation&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;annotations:
volcano.sh/gpu-index: &amp;quot;0&amp;quot;
volcano.sh/predicate-time: &amp;quot;159376446655083530&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;kubelet watches the pod bound to itself, and calls allocate API to set env before running the container.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;env:
NVIDIA_VISIBLE_DEVICES: &amp;quot;0&amp;quot; # GPU card index
VOLCANO_GPU_ALLOCATED: &amp;quot;1&amp;quot; # GPU number allocated
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>GPU Sharing User guide</title>
      <link>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_gpu_sharing/</link>
      <pubDate>Tue, 03 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_gpu_sharing/</guid>
      <description>

&lt;h2 id=&#34;important-note&#34;&gt;Important Note&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;  GPU sharing is deprecated in volcano v1.9, recommended to use the Volcano VGPU feature, which is provided by HAMI project, click &lt;a href=&#34;https://github.com/Project-HAMi/volcano-vgpu-device-plugin&#34; target=&#34;_blank&#34;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;environment-setup&#34;&gt;Environment setup&lt;/h2&gt;

&lt;h3 id=&#34;install-volcano&#34;&gt;Install volcano&lt;/h3&gt;

&lt;h4 id=&#34;1-install-from-source&#34;&gt;1. Install from source&lt;/h4&gt;

&lt;p&gt;Refer to &lt;a href=&#34;https://github.com/volcano-sh/volcano/blob/master/installer/README.md&#34; target=&#34;_blank&#34;&gt;Install Guide&lt;/a&gt; to install volcano.&lt;/p&gt;

&lt;p&gt;After installed, update the scheduler configuration:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;kubectl edit cm -n volcano-system volcano-scheduler-configmap
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For volcano v1.8.2+(v1.8.2 excluded), use the following configMap&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: ConfigMap
apiVersion: v1
metadata:
  name: volcano-scheduler-configmap
  namespace: volcano-system
data:
  volcano-scheduler.conf: |
    actions: &amp;quot;enqueue, allocate, backfill&amp;quot;
    tiers:
    - plugins:
      - name: priority
      - name: gang
      - name: conformance
    - plugins:
      - name: drf
      - name: deviceshare
        arguments:
          deviceshare.GPUSharingEnable: true # enable gpu sharing
      - name: predicates
      - name: proportion
      - name: nodeorder
      - name: binpack
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For volcano v1.8.2-(v1.8.2 included), use the following configMap&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: ConfigMap
apiVersion: v1
metadata:
  name: volcano-scheduler-configmap
  namespace: volcano-system
data:
  volcano-scheduler.conf: |
    actions: &amp;quot;enqueue, allocate, backfill&amp;quot;
    tiers:
    - plugins:
      - name: priority
      - name: gang
      - name: conformance
    - plugins:
      - name: drf
      - name: predicates
        arguments:
          predicate.GPUSharingEnable: true # enable gpu sharing
      - name: proportion
      - name: nodeorder
      - name: binpack
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;2-install-from-release-package&#34;&gt;2. Install from release package&lt;/h4&gt;

&lt;p&gt;Same as above, after installed, update the scheduler configuration in &lt;code&gt;volcano-scheduler-configmap&lt;/code&gt; configmap.&lt;/p&gt;

&lt;h3 id=&#34;install-volcano-device-plugin&#34;&gt;Install Volcano device plugin&lt;/h3&gt;

&lt;p&gt;Please refer to &lt;a href=&#34;https://github.com/volcano-sh/devices/blob/master/README.md#quick-start&#34; target=&#34;_blank&#34;&gt;volcano device plugin&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By default volcano device plugin supports shared GPUs, users do not need to config volcano device plugin. Default setting is the same as setting &amp;ndash;gpu-strategy=share. For more information &lt;a href=&#34;https://github.com/volcano-sh/devices/blob/master/doc/config.md&#34; target=&#34;_blank&#34;&gt;volcano device plugin configuration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;verify-environment-is-ready&#34;&gt;Verify environment is ready&lt;/h3&gt;

&lt;p&gt;Check the node status, it is ok if &lt;code&gt;volcano.sh/gpu-memory&lt;/code&gt; and &lt;code&gt;volcano.sh/gpu-number&lt;/code&gt; are included in the allocatable resources.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl get node {node name} -oyaml
...
status:
  addresses:
  - address: 172.17.0.3
    type: InternalIP
  - address: volcano-control-plane
    type: Hostname
  allocatable:
    cpu: &amp;quot;4&amp;quot;
    ephemeral-storage: 123722704Ki
    hugepages-1Gi: &amp;quot;0&amp;quot;
    hugepages-2Mi: &amp;quot;0&amp;quot;
    memory: 8174332Ki
    pods: &amp;quot;110&amp;quot;
    volcano.sh/gpu-memory: &amp;quot;89424&amp;quot;
    volcano.sh/gpu-number: &amp;quot;8&amp;quot;    # GPU resource
  capacity:
    cpu: &amp;quot;4&amp;quot;
    ephemeral-storage: 123722704Ki
    hugepages-1Gi: &amp;quot;0&amp;quot;
    hugepages-2Mi: &amp;quot;0&amp;quot;
    memory: 8174332Ki
    pods: &amp;quot;110&amp;quot;
    volcano.sh/gpu-memory: &amp;quot;89424&amp;quot;
    volcano.sh/gpu-number: &amp;quot;8&amp;quot;   # GPU resource
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;running-gpu-sharing-jobs&#34;&gt;Running GPU Sharing Jobs&lt;/h3&gt;

&lt;p&gt;NVIDIA GPUs can now be shared via container level resource requirements using the resource name &lt;code&gt;volcano.sh/gpu-memory&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ cat &amp;lt;&amp;lt;EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod1
spec:
  schedulerName: volcano
  containers:
    - name: cuda-container
      image: nvidia/cuda:9.0-devel
      command: [&amp;quot;sleep&amp;quot;]
      args: [&amp;quot;100000&amp;quot;]
      resources:
        limits:
          volcano.sh/gpu-memory: 1024 # requesting 1024MB GPU memory
EOF

$ cat &amp;lt;&amp;lt;EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod2
spec:
  schedulerName: volcano
  containers:
    - name: cuda-container
      image: nvidia/cuda:9.0-devel
      command: [&amp;quot;sleep&amp;quot;]
      args: [&amp;quot;100000&amp;quot;]
      resources:
        limits:
          volcano.sh/gpu-memory: 1024 # requesting 1024MB GPU memory
EOF
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If only the above pods are claiming gpu resource in a cluster, you can see the pods sharing one gpu card:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl exec -ti  gpu-pod1 env
...
VOLCANO_GPU_MEMORY_TOTAL=11178
VOLCANO_GPU_ALLOCATED=1024
NVIDIA_VISIBLE_DEVICES=0
...

$ kubectl exec -ti  gpu-pod1 env
...
VOLCANO_GPU_MEMORY_TOTAL=11178
VOLCANO_GPU_ALLOCATED=1024
NVIDIA_VISIBLE_DEVICES=0
...
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;understanding-how-gpu-sharing-works&#34;&gt;Understanding how GPU sharing works&lt;/h3&gt;

&lt;p&gt;The GPU sharing workflow is depicted as below:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://deploy-preview-499--volcano-sh.netlify.app/img/gpu-virtualization/gpu-share-flow.png&#34; alt=&#34;gpu_sharing&#34; /&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;create a pod with &lt;code&gt;volcano.sh/gpu-memory&lt;/code&gt; resource request,&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;volcano scheduler predicates and allocate gpu resource for the pod. Adding the below annotation&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;annotations:
volcano.sh/gpu-index: &amp;quot;0&amp;quot;
volcano.sh/predicate-time: &amp;quot;1593764466550835304&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;kubelet watches the pod bound to itself, and call allocate API to set env before running the container.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;env:
NVIDIA_VISIBLE_DEVICES: &amp;quot;0&amp;quot; # GPU card index
VOLCANO_GPU_ALLOCATED: &amp;quot;1024&amp;quot; # GPU allocated
VOLCANO_GPU_MEMORY_TOTAL: &amp;quot;11178&amp;quot; # GPU memory of the card
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>How to configure priorityclass for job</title>
      <link>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_configure_priorityclass_for_job/</link>
      <pubDate>Tue, 03 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_configure_priorityclass_for_job/</guid>
      <description>

&lt;h2 id=&#34;background&#34;&gt;Background&lt;/h2&gt;

&lt;p&gt;When a user creates a job, if there is no &lt;code&gt;PriorityClassName&lt;/code&gt; specified in the template of the task, the task will use the &lt;code&gt;PriorityClassName&lt;/code&gt; specified by the job. The user can specify &lt;code&gt;PriorityClassName&lt;/code&gt; in each task&amp;rsquo;s template to override the configuration of job, so that priority can be configured separately for each task.&lt;/p&gt;

&lt;h2 id=&#34;key-points&#34;&gt;Key Points&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If the task does not specify &lt;code&gt;PriorityClassName&lt;/code&gt; but the job does, the task will use the job&amp;rsquo;s PriorityClass, and the &lt;code&gt;PreemptionPolicy&lt;/code&gt; and priority value will also be the same as the job.&lt;/li&gt;
&lt;li&gt;When user needs to allow task in job to preempt other tasks if the resources are insufficient, a separate &lt;code&gt;PriorityClassName&lt;/code&gt; must be set in the task&amp;rsquo;s template, and &lt;strong&gt;it is important to note that if there are multiple tasks that need to be set to different priorities, then user need to set the &lt;code&gt;PriorityClassName&lt;/code&gt; for all of them&lt;/strong&gt;, otherwise the task that does not specify &lt;code&gt;PriorityClassName&lt;/code&gt; will use the PriorityClass of the job it belongs to.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;example&#34;&gt;Example&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: job-priority
value: 1
preemptionPolicy: Never
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: task-priority
value: 10
---
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
  name: job
spec:
  schedulerName: volcano
  priorityClassName: job-priority
  minAvailable: 1
  tasks:
    - replicas: 1
      name: preempt-task
      template:
        spec:
          priorityClassName: task-priority # The priorityclass is specified individually for this task
          containers:
            - image: alpine
              command: [&amp;quot;/bin/sh&amp;quot;, &amp;quot;-c&amp;quot;, &amp;quot;sleep 1000&amp;quot;]
              name: preempt
              resources:
                requests:
                  cpu: 1
    - replicas: 1
      name: non-preempt-task # This task does not specify PriorityClassName, so it will use the &amp;quot;job-priority&amp;quot; priorityclass specified by job
      template:
        spec:
          containers:
            - image: alpine
              command: [&amp;quot;/bin/sh&amp;quot;, &amp;quot;-c&amp;quot;, &amp;quot;sleep 1000&amp;quot;]
              name: non-preempt
              resources:
                requests:
                  cpu: 1
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>How to Configure Scheduler</title>
      <link>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_configure_scheduler/</link>
      <pubDate>Tue, 03 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_configure_scheduler/</guid>
      <description>

&lt;h2 id=&#34;requirements&#34;&gt;Requirements&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Before reading the guidance, please make sure you are aware of basic concepts such as &lt;code&gt;action&lt;/code&gt; &lt;code&gt;plugin&lt;/code&gt; &lt;code&gt;session&lt;/code&gt; &lt;code&gt;tier&lt;/code&gt;
&lt;code&gt;volcano job&lt;/code&gt; &lt;code&gt;podgroup&lt;/code&gt; &lt;code&gt;queue&lt;/code&gt; and so on. If they are still strange to you, please refer to &lt;a href=&#34;https://volcano.sh/en/docs/&#34; target=&#34;_blank&#34;&gt;Volcano Docs&lt;/a&gt;
for more details.&lt;/li&gt;
&lt;li&gt;Before reading the guidance, please make sure you have general understanding of Volcano scheduling workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;background&#34;&gt;Background&lt;/h2&gt;

&lt;p&gt;In order to adjust the scheduling process and algorithms to different scenarios, Volcano allows users to configure actions
and plugins for volcano scheduler. The scheduling pipeline consists of a series of actions. The plugins implement the algorithms,
which will be called in actions as registered session functions. As what you can see in the configmap &lt;code&gt;volcano-scheduler-configmap&lt;/code&gt;,
plugins are divided into 2 tiers by default. It may confuse some users. Besides, it is necessary to provide a guidance about
how to configure volcano scheduler.&lt;/p&gt;

&lt;h2 id=&#34;key-points&#34;&gt;Key Points&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;All the configurations are configured in the configmap &lt;code&gt;volcano-scheduler-configmap&lt;/code&gt;, which is under the namespace &lt;code&gt;volcano-system&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The configuration is made up of 2 parts: &lt;code&gt;actions&lt;/code&gt; and &lt;code&gt;tiers&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;actions&lt;/code&gt; defines the scheduling pipeline. They will be executed in order in each session.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tiers&lt;/code&gt; divides the plugins into several categories. All the functions defined in the plugins will be registered when
a session is open and called when actions are executed.&lt;/li&gt;
&lt;li&gt;In some scenarios, users may configure different plugins which registers the same functions. It will depend on the business
requirement to decide how to combine these functions. That&amp;rsquo;s why &lt;code&gt;tier&lt;/code&gt; is required.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;actions&#34;&gt;Actions&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Action&lt;/code&gt; implements the main logic of scheduling.&lt;/li&gt;
&lt;li&gt;Volcano allow users to make self-defined actions.&lt;/li&gt;
&lt;li&gt;Volcano provides 7 built-in actions until April 2022. The details are as follows.&lt;/li&gt;
&lt;/ul&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Required&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;enqueue&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Judge whether the idle resource in the cluster can satisfy the basic demand of a workload. If yes, set the podgroup of the workload to be &lt;code&gt;inqueue&lt;/code&gt;, otherwise keep the podgroup &lt;code&gt;pending&lt;/code&gt;. Notice that the default value for parameter &lt;code&gt;overcommit-factor&lt;/code&gt; is &lt;code&gt;1.2&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;allocate&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Try to allocate resource to workloads whose corresponding podgroup status is &lt;code&gt;inqueue&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;backfill&lt;/td&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;td&gt;Try to allocate resource to workloads whose pods are &lt;code&gt;BestEffort&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;preempt&lt;/td&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;td&gt;Recognise workloads with high priority. Try to evict pods with low priority and allocate the resource to them.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;reclaim&lt;/td&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;td&gt;Pick out queues whose resources have been borrowed by other queues and reclaim them back.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;elect&lt;/td&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;td&gt;Select a workload satisfying some conditions. It is designed to work with resource reservation for target workload. Will deprecated at future releases.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;reserve&lt;/td&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;td&gt;Select a series of nodes and reserve resource. It is designed to work with resource reservation for target workload. Will deprecated at future releases.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&#34;tiers-and-plugins&#34;&gt;Tiers and Plugins&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Plugin&lt;/code&gt; provides implementation details about scheduling algorithms by registering a series of functions. These functions
will be called during actions are executed.&lt;/li&gt;
&lt;li&gt;In general, a plugin mainly consists of 3 functions: &lt;code&gt;Name&lt;/code&gt; &lt;code&gt;OnSessionOpen&lt;/code&gt; &lt;code&gt;OnSessionClose&lt;/code&gt;. &lt;code&gt;Name&lt;/code&gt; provides the name of the
plugin. &lt;code&gt;OnSessionOpen&lt;/code&gt; executes some operations when a session starts and register some functions about scheduling details.
&lt;code&gt;OnSessionClose&lt;/code&gt; clean up some resource when a session finishes.&lt;/li&gt;
&lt;li&gt;Some plugins provide arguments for users to match their custom scenarios.&lt;/li&gt;
&lt;li&gt;Different plugins may register same functions with different logic. Please make sure they can work together when configuring
plugins.&lt;/li&gt;
&lt;li&gt;Volcano provides 15 built-in plugins until April 2022. The details are as follows.&lt;/li&gt;
&lt;/ul&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Arguments&lt;/th&gt;
&lt;th&gt;Registered Functions&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;binpack&lt;/td&gt;
&lt;td&gt;* binpack.weight&lt;br/&gt; * binpack.cpu&lt;br/&gt; * binpack.memory&lt;br/&gt; * binpack.resources&lt;/td&gt;
&lt;td&gt;* nodeOrderFn&lt;/td&gt;
&lt;td&gt;Try to bind pods to nodes with high resource usage to reduce fragmentation.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;conformance&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;* preemptableFn&lt;br/&gt; * reclaimableFn&lt;/td&gt;
&lt;td&gt;Skip critical pods and not evict them.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;drf&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;* preemptableFn&lt;br/&gt; * queueOrderFn&lt;br/&gt; * reclaimFn&lt;br/&gt; * jobOrderFn&lt;br/&gt; * namespaceOrderFn&lt;/td&gt;
&lt;td&gt;Provide fair resource shares for all queues.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;extender&lt;/td&gt;
&lt;td&gt;* extender.urlPrefix&lt;br/&gt; * extender.httpTimeout&lt;br/&gt; * extender.onSessionOpenVerb&lt;br/&gt; * extender.onSessionCloseVerb&lt;br/&gt; * extender.predicateVerb&lt;br/&gt; * extender.prioritizeVerb&lt;br/&gt; * extender.preemptableVerb&lt;br/&gt; * extender.reclaimableVerb&lt;br/&gt; * extender.queueOverusedVerb&lt;br/&gt; * extender.jobEnqueueableVerb&lt;br/&gt; * extender.ignorable&lt;/td&gt;
&lt;td&gt;* predicateFn&lt;br/&gt; * batchNodeOrderFn&lt;br/&gt; * preemptableFn&lt;br/&gt; * reclaimableFn&lt;br/&gt; * jobEnqueueableFn&lt;br/&gt; * overusedFn&lt;/td&gt;
&lt;td&gt;Add outer http server to execute custom actions.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;gang&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;* jobValidFn&lt;br/&gt; * reclaimableFn&lt;br/&gt; * preemptableFn&lt;br/&gt; * jobOrderFn&lt;br/&gt; * JobReadyFn&lt;br/&gt; * jobPipelineFn&lt;br/&gt; * jobStarvingFn&lt;/td&gt;
&lt;td&gt;Consider the minimal resource requirement or member number for a workload when allocate resource to it.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;nodeorder&lt;/td&gt;
&lt;td&gt;* nodeaffinity.weight&lt;br/&gt; * podaffinity.weight&lt;br/&gt; * leastrequested.weight&lt;br/&gt; * balancedresource.weight&lt;br/&gt; * mostrequested.weight&lt;br/&gt; * tainttoleration.weight&lt;br/&gt; * imagelocality.weight&lt;/td&gt;
&lt;td&gt;* nodeOrderFn&lt;br/&gt; * batchNodeOrderFn&lt;/td&gt;
&lt;td&gt;Sort all nodes in custom way.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;numaaware&lt;/td&gt;
&lt;td&gt;* weight&lt;/td&gt;
&lt;td&gt;* predicateFn&lt;br/&gt; * batchNodeOrderFn&lt;/td&gt;
&lt;td&gt;Consider CPU Numa as a key factor when binding a pod to a node.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;overcommit&lt;/td&gt;
&lt;td&gt;* overcommit-factor&lt;/td&gt;
&lt;td&gt;* jobEnqueueableFn&lt;br/&gt; * jobEnqueuedFn&lt;/td&gt;
&lt;td&gt;Set the available resource as the given times of the whole resource of the cluster.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;predicate&lt;/td&gt;
&lt;td&gt;* predicate.GPUSharingEnable&lt;br/&gt; * predicate.CacheEnable&lt;br/&gt; * predicate.ProportionalEnable&lt;br/&gt; * predicate.resources&lt;br/&gt; * predicate.resources.nvidia.com/gpu.cpu&lt;br/&gt; * predicate.resources.nvidia.com/gpu.memory&lt;/td&gt;
&lt;td&gt;* predicateFn&lt;br/&gt;&lt;/td&gt;
&lt;td&gt;Add custom functions about how to filter nodes for pods.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;priority&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;* taskOrderFn&lt;br/&gt; * jobOrderFn&lt;br/&gt; * preemptableFn&lt;br/&gt; * jobStarvingFn&lt;/td&gt;
&lt;td&gt;Defines priority for workloads.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;proportion&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;* queueOrderFn&lt;br/&gt; * reclaimableFn&lt;br/&gt; * overusedFn&lt;br/&gt; * allocatableFn&lt;br/&gt; * jobEnqueueableFn&lt;br/&gt;&lt;/td&gt;
&lt;td&gt;Divide the whole resources of the cluster to all queues as proportion according to queues&amp;rsquo; configurations&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;reservation&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;* targetJobFn&lt;br/&gt; * reservedNodesFn&lt;/td&gt;
&lt;td&gt;Sort nodes as resource usage and lock parts for target workload as reservation.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;sla&lt;/td&gt;
&lt;td&gt;* sla-waiting-time&lt;/td&gt;
&lt;td&gt;* jobOrderFn&lt;br/&gt; * jobEnqueueableFn&lt;br/&gt; * JobPipelinedFn&lt;/td&gt;
&lt;td&gt;Sort workloads according to the SLA settings.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;task-topology&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;* taskOrderFn&lt;br/&gt; * nodeOrderFn&lt;/td&gt;
&lt;td&gt;Bind pods with different roles to nodes according to the given policy.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;tdm&lt;/td&gt;
&lt;td&gt;* tdm.revocable-zone.rz1&lt;br/&gt; * tdm.revocable-zone.rz2&lt;br/&gt; * tdm.evict.period&lt;/td&gt;
&lt;td&gt;* predicateFn&lt;br/&gt; * nodeOrderFn&lt;br/&gt; * preemptableFn&lt;br/&gt; * victimTasksFn&lt;br/&gt; * jobOrderFn&lt;br/&gt; * jobPipelinedFn&lt;br/&gt; * jobStarvingFn&lt;/td&gt;
&lt;td&gt;Enable part of nodes to be in the charge of K8s and other clusters in different period.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&#34;examples&#34;&gt;Examples&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;# default configuration for scheduler
actions: &amp;quot;enqueue, allocate, backfill&amp;quot;
tiers:
- plugins:
  - name: priority
  - name: gang
  - name: conformance
- plugins:
  - name: overcommit
  - name: drf
  - name: predicates
  - name: proportion
  - name: nodeorder
  - name: binpack
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;note&#34;&gt;Note:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;According to the default configuration, the scheduling process works as follows at a session. The scheduler will run the
following pipeline regularly. The period is &lt;code&gt;1s&lt;/code&gt; by default.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-mermaid&#34;&gt;graph LR
1(Start) --&amp;gt; 2(OpenSession) --&amp;gt; 3(enqueue) --&amp;gt; 4(allocate) --&amp;gt; 5(backfill) --&amp;gt; 6(CloseSession) --&amp;gt; 7(End)
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;All the functions in the configured plugins will be registered when executing &lt;code&gt;OpenSession&lt;/code&gt; and called when executing
the configured actions. For example, &lt;code&gt;jobEnqueueable&lt;/code&gt; function, which is registered in &lt;code&gt;overcommit&lt;/code&gt; plugin and called at
&lt;code&gt;enqueue&lt;/code&gt; action, aims to judge whether the idle resource of the cluster can satisfy the minimal demand of a workload.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Both &lt;code&gt;overcommit&lt;/code&gt; and &lt;code&gt;proportion&lt;/code&gt; plugin have registered function &lt;code&gt;jobEnqueueableFn&lt;/code&gt;, which will be called in the function
&lt;code&gt;JobEnqueueable&lt;/code&gt;. Besides, &lt;code&gt;overcommit&lt;/code&gt; and &lt;code&gt;proportion&lt;/code&gt; are in the same tier. According to the implementation of &lt;code&gt;JobEnqueueable&lt;/code&gt;,
it will get through all the plugins in different tiers in order. If any &lt;code&gt;jobEnqueueableFn&lt;/code&gt; returns a value belows &lt;code&gt;0&lt;/code&gt;, it
stops executing the &lt;code&gt;jobEnqueueableFn&lt;/code&gt; registered in the following plugins and returns &lt;code&gt;false&lt;/code&gt;. Namely, if the &lt;code&gt;jobEnqueueableFn&lt;/code&gt;
registered in &lt;code&gt;overcommit&lt;/code&gt; returns a value belows &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;jobEnqueueableFn&lt;/code&gt;, which is called in &lt;code&gt;enqueue&lt;/code&gt; action, will return
&lt;code&gt;false&lt;/code&gt; and never call the &lt;code&gt;jobEnqueueableFn&lt;/code&gt; registered in the &lt;code&gt;proportion&lt;/code&gt; plugin.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;faq&#34;&gt;FAQ&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;How can I decide which plugins should be grouped into a tier? How many tiers should I set for my business?
&amp;gt; In most scenarios, users should not concern about how to divide plugins to different tiers. It&amp;rsquo;s OK to configure all
plugins within a single tier. Only on condition that it is related with &lt;strong&gt;eviction&lt;/strong&gt; will you need to think of how to organize
the plugins in different tiers. For example, when enable &lt;code&gt;reclaim&lt;/code&gt; action, the scheduler will try to collect a set of victims.
In order to reduce the influence to users&amp;rsquo; business, it is reasonable to pick out victims as less as possible. Then you can
configure the plugins evicting the least pods in the first tier. And configure other plugins with eviction at the second tier.
If the first tier can pick out victims, it will not call the functions registered in the plugins, which is configured at
the second tier.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>How to Enable Dynamic Resource Allocation (DRA) in Volcano Scheduler</title>
      <link>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_enable_dra/</link>
      <pubDate>Tue, 03 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_enable_dra/</guid>
      <description>

&lt;p&gt;This document describes the steps required to enable Dynamic Resource Allocation (DRA) support in the Volcano scheduler.&lt;/p&gt;

&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;Before proceeding with the configuration steps, ensure your cluster meets the following prerequisites:&lt;/p&gt;

&lt;h3 id=&#34;configure-cluster-nodes-containerd&#34;&gt;Configure Cluster Nodes (Containerd)&lt;/h3&gt;

&lt;p&gt;For nodes running containerd as the container runtime, you must enable the Container Device Interface (CDI) feature.
This is crucial for containerd to properly interact with DRA drivers and inject dynamic resources into Pods.&lt;/p&gt;

&lt;p&gt;Modify the containerd configuration file on each node (typically /etc/containerd/config.toml) to ensure the following setting is present:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-toml&#34;&gt;# Enable CDI as described in
# https://tags.cncf.io/container-device-interface#containerd-configuration
[plugins.&amp;quot;io.containerd.grpc.v1.cri&amp;quot;]
  enable_cdi = true
  cdi_spec_dirs = [&amp;quot;/etc/cdi&amp;quot;, &amp;quot;/var/run/cdi&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After modifying the configuration, restart the containerd service on each node for the changes to take effect. For example: &lt;code&gt;sudo systemctl restart containerd&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you are using other container runtimes, please refer to: &lt;a href=&#34;https://github.com/cncf-tags/container-device-interface?tab=readme-ov-file#how-to-configure-cdi&#34; target=&#34;_blank&#34;&gt;how-to-configure-cdi&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;1-configure-kube-apiserver&#34;&gt;1. Configure Kube-apiserver&lt;/h2&gt;

&lt;p&gt;DRA-related APIs are k8s built-in resources instead of CRD resources, and these resources are not registered by default in v1.32,
so you need to set the startup parameters of kube-apiserver to manually register DRA-related APIs, add or ensure the following flag is present in your kube-apiserver manifest or configuration:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;--runtime-config=resource.k8s.io/v1beta1=true
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;2-install-volcano-with-dra-feature-gates-enabled&#34;&gt;2. Install Volcano With DRA feature gates enabled&lt;/h2&gt;

&lt;p&gt;When installing Volcano, you need to enable the DRA related feature gates, e.g., &lt;code&gt;DynamicResourceAllocation&lt;/code&gt; must be enabled when you need to use DRA,
you can also choose to enable the &lt;code&gt;DRAAdminAccess&lt;/code&gt; feature gate to manage devices as your need.&lt;/p&gt;

&lt;p&gt;When you are using helm to install Volcano, you can use following command to install Volcano with DRA feature gates enabled:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;helm install volcano volcano/volcano --namespace volcano-system --create-namespace \
  --set custom.scheduler_feature_gates=&amp;quot;DynamicResourceAllocation=true&amp;quot; \
  # Add other necessary Helm values for your installation
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you directly use &lt;code&gt;kubectl apply -f&lt;/code&gt; to install Volcano, you need to add or ensure the following flag is present in your volcano-scheduler manifest:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;--feature-gates=DynamicResourceAllocation=true
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;3-configure-volcano-scheduler-plugins&#34;&gt;3. Configure Volcano Scheduler Plugins&lt;/h2&gt;

&lt;p&gt;After installing Volcano, you need to configure the Volcano scheduler&amp;rsquo;s plugin configuration to enable the DRA plugin within the predicates plugin arguments.&lt;/p&gt;

&lt;p&gt;Locate your Volcano scheduler configuration (A ConfigMap contains the configuration). Find the predicates plugin configuration and add or modify its arguments to enable DRA plugin.&lt;/p&gt;

&lt;p&gt;An example snippet of the scheduler configuration (within the volcano-scheduler.conf key of the ConfigMap) might look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;actions: &amp;quot;enqueue, allocate, backfill&amp;quot;
tiers:
- plugins:
  - name: priority
  - name: gang
- plugins:
  - name: drf
  - name: predicates
    arguments:
      predicate.DynamicResourceAllocationEnable: true
  - name: proportion
  - name: nodeorder
  - name: binpack
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;4-deploy-a-dra-driver&#34;&gt;4. Deploy a DRA Driver&lt;/h2&gt;

&lt;p&gt;To utilize Dynamic Resource Allocation, you need to deploy a DRA driver in your cluster. The driver is responsible for managing the lifecycle of dynamic resources.
For example, you can refer to the &lt;a href=&#34;https://github.com/kubernetes-sigs/dra-example-driver&#34; target=&#34;_blank&#34;&gt;kubernetes-sigs/dra-example-driver&lt;/a&gt; to deploy a example DRA driver for testing.&lt;/p&gt;

&lt;p&gt;For some DRA Drivers which have already been used in actual production, you can refer to:
- &lt;a href=&#34;https://github.com/NVIDIA/k8s-dra-driver-gpu&#34; target=&#34;_blank&#34;&gt;NVIDIA/k8s-dra-driver-gpu&lt;/a&gt;
- &lt;a href=&#34;https://github.com/intel/intel-resource-drivers-for-kubernetes&#34; target=&#34;_blank&#34;&gt;intel/intel-resource-drivers-for-kubernetes&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How to Tune Volcano Performance in Large-Scale Scenarios</title>
      <link>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_tune_volcano_performance/</link>
      <pubDate>Tue, 03 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_tune_volcano_performance/</guid>
      <description>

&lt;blockquote&gt;
&lt;p&gt;This article originates from the &amp;ldquo;Volcano Large-Scale Performance Testing and Tuning&amp;rdquo; project of the Open Source Promotion Plan (OSPP), organized by the Chinese Academy of Sciences. All experimental data and analysis have been published in the author&amp;rsquo;s blog series (@Freshwlnd).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&#34;1-introduction&#34;&gt;1. Introduction&lt;/h2&gt;

&lt;h3 id=&#34;1-1-background-and-objectives&#34;&gt;1.1 Background and Objectives&lt;/h3&gt;

&lt;p&gt;Volcano is a mainstream cloud-native batch processing system widely used in AI, big data, and HPC scenarios. This project aims to systematically reproduce and identify performance bottlenecks in Volcano under a load of tens of thousands of pods through large-scale performance testing, ultimately producing a practical tuning guide and proposing future architectural optimization directions.&lt;/p&gt;

&lt;h3 id=&#34;1-2-summary-of-overall-conclusions&#34;&gt;1.2 Summary of Overall Conclusions&lt;/h3&gt;

&lt;p&gt;Through systematic experiments, we have reached the following core conclusions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Scenario-Dependent Performance&lt;/strong&gt;: Volcano&amp;rsquo;s performance is highly dependent on the scheduling scenario. &lt;strong&gt;When Gang Scheduling is enabled, its performance far exceeds that of other schedulers&lt;/strong&gt;, highlighting its core advantages in batch processing and AI scenarios. Under the general scenario where Gang is not enabled, due to the additional overhead it brings to the Job management function designed for complex scenarios, there is still some room for optimization.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Webhook as the Main Bottleneck&lt;/strong&gt;: In large-scale, resource-constrained clusters, the default Webhook configuration (10s timeout) is the direct cause of large-scale pod creation failures. Additionally, the overhead introduced by the Webhook validation chain itself is a significant performance factor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optimal Value for Controller Worker Threads&lt;/strong&gt;: The &lt;code&gt;--worker-threads&lt;/code&gt; parameter is not a case of &amp;ldquo;the higher, the better.&amp;rdquo; An improper configuration can degrade performance by saturating computing resources or exacerbating API-Server contention, exhibiting a &amp;ldquo;V-shaped&amp;rdquo; performance curve.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API-Server Contention between CREATE/SCHEDULE&lt;/strong&gt;: In high-concurrency scenarios, concurrent write operations to the K8s API-Server/ETCD by the Controller (CREATE) and Scheduler (SCHEDULE) lead to queuing/retries and a macroscopic phenomenon of &amp;ldquo;stair-step stalls&amp;rdquo; where they appear to execute alternately. Meanwhile, blindly increasing the &lt;code&gt;CREATE&lt;/code&gt; rate may actually prolong the overall scheduling time.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&#34;2-test-and-monitoring-environment-description&#34;&gt;2. Test and Monitoring Environment Description&lt;/h2&gt;

&lt;p&gt;The core of this testing was to extend the open-source &lt;code&gt;kube-scheduling-perf&lt;/code&gt; framework to simulate large-scale pod scheduling scenarios in a local Kind cluster. We have conducted a detailed source code analysis of this testing framework and written a blog series titled &amp;ldquo;Cloud-Native Batch Scheduling in Practice: Volcano Monitoring and Performance Testing,&amp;rdquo; available on the author&amp;rsquo;s blog (@Freshwlnd).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Testing Framework&lt;/strong&gt;: The &lt;code&gt;wzshiming/kube-scheduling-perf&lt;/code&gt; project uses a Makefile for automated orchestration, enabling one-click cluster setup, execution of multi-scenario benchmarks, monitoring data collection, and results archiving.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Collection&lt;/strong&gt;: The framework uses &lt;code&gt;audit-exporter&lt;/code&gt; to accurately capture timestamps of &lt;code&gt;Pod Creation&lt;/code&gt; and &lt;code&gt;Pod Schedule&lt;/code&gt; events from the &lt;code&gt;kube-apiserver&lt;/code&gt; audit logs (&lt;code&gt;audit.log&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Core Metrics&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;X-axis&lt;/strong&gt;: Test run time (seconds).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Y-axis&lt;/strong&gt;: Cumulative number of Pods that have completed &lt;code&gt;CREATE&lt;/code&gt; or &lt;code&gt;SCHEDULE&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Curve Slope&lt;/strong&gt;: Represents instantaneous throughput (Pods per second), a key performance metric.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Illustrative Example&lt;/strong&gt;:&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://deploy-preview-499--volcano-sh.netlify.app/img/performance-tuning/cumulative-pod-counts-alternating-stair-step.png&#34; alt=&#34;Illustrative Example&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;3-performance-phenomena&#34;&gt;3. Performance Phenomena&lt;/h2&gt;

&lt;h3 id=&#34;3-1-core-performance-phenomena&#34;&gt;3.1 Core Performance Phenomena&lt;/h3&gt;

&lt;p&gt;In summary, we observed the following performance characteristics during our tests.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When Gang Scheduling was not enabled, we observed unique performance characteristics in Volcano:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Throughput and Stair-Step Stalls&lt;/strong&gt;: The &lt;code&gt;CREATED&lt;/code&gt; and &lt;code&gt;SCHEDULED&lt;/code&gt; curves exhibit a distinct stair-step pattern, with alternating periods of &amp;ldquo;surges&amp;rdquo; and &amp;ldquo;stalls.&amp;rdquo;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Large-Scale Pod Creation Failures&lt;/strong&gt;: In some cases, when the number of pods within a single job is very large (e.g., 20 Jobs × 500 Pods), fewer than 2,000 pods were successfully created under the default configuration.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&#34;https://deploy-preview-499--volcano-sh.netlify.app/img/performance-tuning/stair-step-stall-phenomenon.png&#34; alt=&#34;CREATE/SCHEDULE Stall Phenomenon&#34; /&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Enabling Gang Scheduling is Volcano&amp;rsquo;s core use case. In this scenario:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Superior Performance&lt;/strong&gt;: Volcano significantly outperforms other schedulers, thanks to its efficient PodGroup management and Gang scheduling algorithm.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Necessary Overhead&lt;/strong&gt;: Although all schedulers experience longer total runtimes with Gang Scheduling due to more complex computations, Volcano&amp;rsquo;s architecture maintains the highest efficiency. This validates the necessity and sophistication of its job management features. It is essential to provide adequate resources for Volcano in production environments to leverage its full capabilities.&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;3-2-analysis-of-specific-performance-phenomena&#34;&gt;3.2 Analysis of Specific Performance Phenomena&lt;/h3&gt;

&lt;p&gt;With a total of 10k pods, we adjusted the number of jobs and the number of pods per job, both with and without Gang Scheduling enabled. We focused primarily on the non-Gang Scheduling scenario.&lt;/p&gt;

&lt;h4 id=&#34;test-environment-description&#34;&gt;Test Environment Description&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Test Environment Configuration&lt;/strong&gt;:
- &lt;strong&gt;Hardware&lt;/strong&gt;: Intel Xeon Gold 6230 @ 2.10GHz, 8-core CPU, 15GB RAM, 79GB Storage
- &lt;strong&gt;Software&lt;/strong&gt;: Docker 27.5.1, Kubernetes 1.32.2 (Kind cluster), kubectl v1.33.2
- &lt;strong&gt;Test Scale&lt;/strong&gt;: A single test result occupied 1.3GB-2.7GB of storage, totaling 15GB of test data.
- &lt;strong&gt;Comparative Verification&lt;/strong&gt;: Comparative tests were conducted in a high-configuration environment (24-core CPU, 96GB RAM) to verify the impact of hardware resources on the results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test Methodology&lt;/strong&gt;:
- Extended tests were based on the open-source &lt;code&gt;kube-scheduling-perf&lt;/code&gt; framework.
- &lt;code&gt;audit-exporter&lt;/code&gt; was used to accurately capture &lt;code&gt;Pod Creation&lt;/code&gt; and &lt;code&gt;Pod Schedule&lt;/code&gt; events from &lt;code&gt;kube-apiserver&lt;/code&gt; audit logs.
- Validation analysis was performed by comparing results with the video from the KubeCon Europe 2025 tech talk &amp;ldquo;A Comparative Analysis of Kueue, Volcano, and YuniKorn - Wei Huang, Apple &amp;amp; Shiming Zhang, DaoCloud&amp;rdquo;.&lt;/p&gt;

&lt;h4 id=&#34;test-results-analysis&#34;&gt;Test Results Analysis&lt;/h4&gt;

&lt;p&gt;Without Gang Scheduling, we observed Volcano&amp;rsquo;s unique performance characteristics across four typical benchmark combinations (all with a total of 10,000 pods):&lt;/p&gt;

&lt;h5 id=&#34;benchmark-1-10-000-jobs-1-pod-job&#34;&gt;Benchmark 1: 10,000 Jobs × 1 Pod/Job&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Observation&lt;/strong&gt;: The &lt;code&gt;CREATE&lt;/code&gt; and &lt;code&gt;SCHEDULE&lt;/code&gt; curves almost completely overlapped, and the overall slope (throughput) was lower compared to scenarios with fewer Jobs, mainly due to the overhead of complex job management features. The results were the same in both low and high-resource environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;: In this scenario, the processing overhead of the Job objects themselves is substantial, making the &lt;strong&gt;pod creation (CREATE) phase the absolute performance bottleneck&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&#34;benchmark-2-500-jobs-20-pods-job&#34;&gt;Benchmark 2: 500 Jobs × 20 Pods/Job&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Observation&lt;/strong&gt;: The &lt;code&gt;SCHEDULED&lt;/code&gt; curve significantly lagged behind the &lt;code&gt;CREATED&lt;/code&gt; curve, and both curves showed the clearest &lt;strong&gt;stair-step stall&lt;/strong&gt; pattern. Volcano exhibited periodic surges in both CREATED and SCHEDULE phases, indicating intermittent stalls in the controller. The results were the same in both low and high-resource environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;: The scheduling (SCHEDULE) phase became the bottleneck, and the resource contention between the Controller and Scheduler was most prominent.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&#34;benchmark-3-4-20-jobs-500-pods-job-1-job-10-000-pods-job&#34;&gt;Benchmark 3 &amp;amp; 4: 20 Jobs × 500 Pods/Job &amp;amp; 1 Job × 10,000 Pods/Job&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Observation&lt;/strong&gt;: The &lt;code&gt;CREATED&lt;/code&gt; curve rose rapidly at the beginning and then flattened, while the &lt;code&gt;SCHEDULED&lt;/code&gt; curve grew slowly and linearly, with a huge gap between them. The stair-step stall pattern in the &lt;code&gt;CREATED&lt;/code&gt; curve disappeared. In our resource-limited local test environment (8-core, 16GB), a large number of pod creation failures were observed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;: When the total number of jobs is small and the number of pods per job is extremely large, the Controller can create pods very quickly, making the &lt;strong&gt;scheduling (SCHEDULE) phase the absolute performance bottleneck&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Finding&lt;/strong&gt;: In all four cases, Volcano&amp;rsquo;s total scheduling time was roughly proportional to the number of Jobs, indicating that its performance bottleneck is primarily caused by Job processing.&lt;/p&gt;

&lt;h2 id=&#34;4-performance-bottleneck-hypotheses-and-verification&#34;&gt;4. Performance Bottleneck Hypotheses and Verification&lt;/h2&gt;

&lt;h3 id=&#34;4-1-hypothesis-1-webhook-is-a-performance-bottleneck&#34;&gt;4.1 Hypothesis 1: Webhook is a Performance Bottleneck&lt;/h3&gt;

&lt;h4 id=&#34;4-1-1-verification-timeout-issue&#34;&gt;4.1.1 Verification (Timeout Issue)&lt;/h4&gt;

&lt;p&gt;By analyzing &lt;code&gt;audit.log&lt;/code&gt;, we found that a large number of pod creation failures were due to an insufficient Webhook &lt;code&gt;timeoutSeconds&lt;/code&gt; (10s). The evidence includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pod Creation Failure Rate&lt;/strong&gt;: 98.7% of pod creation requests failed due to timeouts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Log Evidence&lt;/strong&gt;: 4.9GB of audit logs recorded a massive number of timeout errors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timeout Configuration&lt;/strong&gt;: The webhook timeout was set to 10 seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Specifically, we analyzed the 4.9GB audit log with the following commands:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# Count the number of errors
grep -c &amp;quot;context deadline exceeded&amp;quot; kube-apiserver-audit.volcano.log
# Output: 520120

# Count the number of Webhook calls
grep -c &amp;quot;validatepod.volcano.sh&amp;quot; kube-apiserver-audit.volcano.log
# Output: 515531

# Count the number of successful/failed pod creations
grep -c &amp;quot;ResponseComplete.*pods.*create.*Success&amp;quot; kube-apiserver-audit.volcano.log
# Output: 712
grep -c &amp;quot;ResponseComplete.*pods.*create.*Failure&amp;quot; kube-apiserver-audit.volcano.log
# Output: 520518
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Analyzing the error messages in the logs revealed a consistent pattern:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{
  &amp;quot;status&amp;quot;: &amp;quot;Failure&amp;quot;,
  &amp;quot;message&amp;quot;: &amp;quot;Internal error occurred: failed calling webhook \&amp;quot;validatepod.volcano.sh\&amp;quot;: failed to call webhook: Post \&amp;quot;https://volcano-admission-service.volcano-system.svc:443/pods/validate?timeout=10s\&amp;quot;: context deadline exceeded&amp;quot;,
  &amp;quot;reason&amp;quot;: &amp;quot;InternalError&amp;quot;,
  &amp;quot;code&amp;quot;: 500
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The statistical summary is as follows:&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;th&gt;Percentage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total Pod Creation Requests&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;526,767&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Successful Creations&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;712&lt;/td&gt;
&lt;td&gt;0.13%&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Failed Creations&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;520,518&lt;/td&gt;
&lt;td&gt;98.7%&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Webhook Timeout Errors&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;520,120&lt;/td&gt;
&lt;td&gt;98.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;Experimental Design&lt;/strong&gt;: To verify this hypothesis, we increased the webhook timeout from 10 seconds to 30 seconds:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# Batch modify the timeout in all webhook configuration files
sed -i &#39;s/timeoutSeconds: 10/timeoutSeconds: 30/g&#39; schedulers/volcano/admission-service-*.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Verification Result&lt;/strong&gt;: After increasing the timeout to 30s, the number of pod creations returned to normal. In benchmark 3 and 4, the number of created pods recovered from &amp;ldquo;less than 1000&amp;rdquo; to the normal state of &amp;ldquo;10,000&amp;rdquo;, and the pod creation success rate increased from 1.3% to nearly 100%.&lt;/p&gt;

&lt;p&gt;Before fix:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://deploy-preview-499--volcano-sh.netlify.app/img/performance-tuning/pod-creation-failure-phenomenon.png&#34; alt=&#34;Pod creation failure phenomenon in extreme cases due to Webhook timeout&#34; /&gt;&lt;/p&gt;

&lt;p&gt;After fix:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://deploy-preview-499--volcano-sh.netlify.app/img/performance-tuning/pod-creation-restored-after-webhook-timeout.png&#34; alt=&#34;Pod Creation Restored After Fixing Webhook Timeout&#34; /&gt;&lt;/p&gt;

&lt;h4 id=&#34;4-1-2-verification-inherent-overhead&#34;&gt;4.1.2 Verification (Inherent Overhead)&lt;/h4&gt;

&lt;p&gt;Even after resolving the timeout issue, the complex validation process of the Webhook (TLS, network transport) itself introduces overhead. Specifically, Volcano&amp;rsquo;s Webhook system includes multiple components, and each pod creation request must pass through:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Mutating Webhook&lt;/strong&gt;: Modifies Pod configuration (e.g., adding fields like &lt;code&gt;maxRetry&lt;/code&gt;, &lt;code&gt;minAvailable&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validating Webhook&lt;/strong&gt;: Validates the legality of the Pod configuration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Admission Service&lt;/strong&gt;: The service that handles Webhook requests.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TLS Certificate Validation&lt;/strong&gt;: Ensures the security of Webhook calls.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Common Webhook configurations include:&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Configuration Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mutating&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;volcano-admission-service-jobs-mutate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modifies Job configuration, adds fields like &lt;code&gt;maxRetry&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mutating&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;volcano-admission-service-podgroups-mutate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modifies PodGroup configuration.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mutating&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;volcano-admission-service-pods-mutate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modifies Pod configuration.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mutating&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;volcano-admission-service-queues-mutate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modifies Queue configuration.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Validating&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;volcano-admission-service-jobs-validate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Validates Job configuration legality.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Validating&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;volcano-admission-service-pods-validate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Validates Pod configuration legality.&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Validating&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;volcano-admission-service-queues-validate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Validates Queue configuration legality.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Considering the development trends of modern Kubernetes versions, some Webhook functionalities could potentially be replaced by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Strengthening Controller Validation&lt;/strong&gt;: Moving necessary validation logic (e.g., null pointer checks) into the Volcano Controller Manager to support disabling webhooks in simpler scenarios.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Using CRD Validation Rules&lt;/strong&gt;: Using the Common Expression Language (CEL) for K8s admission control to validate CRD values (using the K8s v1.29 [stable] &lt;code&gt;x-kubernetes-validations&lt;/code&gt; extension), thereby replacing parts of the Validating Webhook with Kubernetes&amp;rsquo; native CRD validation capabilities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-configured Templates&lt;/strong&gt;: Reducing runtime modification needs by pre-configuring Job templates.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Verification Result&lt;/strong&gt;: Comparative experiments showed that disabling the Webhook led to a significant performance improvement. Pod creation/scheduling speed increased noticeably, and overall scheduler performance improved. While the Webhook system provides important validation and modification functions, its processing overhead becomes a bottleneck in large-scale pod creation scenarios. Taking the &lt;code&gt;10000 Jobs x 1 Pod&lt;/code&gt; scenario as an example, the &lt;strong&gt;overall scheduling time was reduced from about 250 seconds to about 180 seconds, a throughput increase of nearly 30%&lt;/strong&gt;, which is a significant improvement.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://deploy-preview-499--volcano-sh.netlify.app/img/performance-tuning/before-optimization-webhook-enabled.png&#34; alt=&#34;Before Optimization (Webhook Enabled)&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://deploy-preview-499--volcano-sh.netlify.app/img/performance-tuning/after-optimization-webhook-disabled.png&#34; alt=&#34;After Optimization (Webhook Disabled)&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;4-2-hypothesis-2-controller-worker-threads-need-tuning&#34;&gt;4.2 Hypothesis 2: Controller Worker Threads Need Tuning&lt;/h3&gt;

&lt;p&gt;After analyzing the Controller source code, we found that the &lt;code&gt;--worker-threads&lt;/code&gt; parameter (default 50) determines the number of Jobs that can be processed concurrently. Further experiments revealed that this value is not a case of &amp;ldquo;the more, the better&amp;rdquo;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Too Few Threads&lt;/strong&gt;: Fails to fully utilize computing resources, with I/O waits becoming the bottleneck.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Too Many Threads&lt;/strong&gt;: Exacerbates CPU and API-Server contention, leading to a performance decrease.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verification&lt;/strong&gt;: By conducting multiple experiments with different values for the &lt;code&gt;--worker-threads&lt;/code&gt; parameter of &lt;code&gt;volcano-controller-manager&lt;/code&gt;, we observed a &amp;ldquo;V-shaped&amp;rdquo; performance curve. Too few threads underutilize the CPU; too many threads increase resource contention.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;4-2-1-source-code-analysis-of-controller-creation-logic&#34;&gt;4.2.1 Source Code Analysis of Controller Creation Logic&lt;/h4&gt;

&lt;h5 id=&#34;origin-of-worker-goroutines&#34;&gt;Origin of Worker Goroutines&lt;/h5&gt;

&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;// cmd/controller-manager/app/server.go:134-139
func startControllers(config *rest.Config, opt *options.ServerOption) func(ctx context.Context) {
    ...
    controllerOpt.WorkerNum = opt.WorkerThreads
    ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;--worker-threads&lt;/code&gt; parameter defaults to &lt;strong&gt;50&lt;/strong&gt; (if not specified) and determines the number of goroutines that the JobController uses to concurrently process &lt;strong&gt;Job requests&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Note&lt;/strong&gt;: These worker threads determine the parallelism for &lt;em&gt;Jobs&lt;/em&gt;, not &lt;em&gt;Pods&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5 id=&#34;hashing-and-queues&#34;&gt;Hashing and Queues&lt;/h5&gt;

&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;// pkg/controllers/job/job_controller.go:318-333
func (cc *jobcontroller) belongsToThisRoutine(key string, count uint32) bool {
    val := cc.genHash(key)
    return val % cc.workers == count
}

func (cc *jobcontroller) getWorkerQueue(key string) workqueue.TypedRateLimitingInterface[any] {
	val := cc.genHash(key)
	queue := cc.queueList[val%cc.workers]
	return queue
}

// genHash source code
func (cc *jobcontroller) genHash(key string) uint32 {
    hashVal := fnv.New32() // FNV-1a non-cryptographic hash
    hashVal.Write([]byte(key))
    return hashVal.Sum32()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;FNV (Fowler–Noll–Vo) is a fast, low-collision non-cryptographic hash function that serves as a &lt;strong&gt;consistent hashing&lt;/strong&gt; mechanism in Volcano:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Serializing Single-Job Operations&lt;/strong&gt;: It ensures that the same JobKey is always routed to the same worker, preventing race conditions (like version conflicts or duplicate pod creation) that could arise from multiple goroutines modifying the same Job state concurrently.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Load Balancing&lt;/strong&gt;: It distributes different Jobs evenly across the &lt;code&gt;workers&lt;/code&gt; queues, improving parallelism.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;❓ What if &amp;ldquo;same Job → same goroutine&amp;rdquo; is not guaranteed?
*   Multiple goroutines could enter the state machine for the same Job simultaneously, causing &lt;strong&gt;Status conflicts&lt;/strong&gt; (retries due to ResourceVersion mismatch, optimistic lock failures).
*   Duplicate creation of Pods / PodGroups, leading to &lt;strong&gt;resource leaks&lt;/strong&gt; and &lt;strong&gt;Gang Scheduling failures&lt;/strong&gt;.
*   Without this mechanism, a global lock or fine-grained optimistic retries would be necessary, which would be less efficient.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5 id=&#34;podgroup-creation&#34;&gt;PodGroup Creation&lt;/h5&gt;

&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;// pkg/controllers/job/job_controller_actions.go:190-214
func (cc *jobcontroller) createOrUpdatePodGroup(job *batch.Job) error {
    ...
    pg := &amp;amp;scheduling.PodGroup{ ... }
    vcClient.SchedulingV1beta1().PodGroups(...).Create(..., pg, ...)
    ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A PodGroup is created with a single API call, and each Job has only one PodGroup. The creation itself is relatively simple (it&amp;rsquo;s just a logical unit) and is unlikely to be a major bottleneck:
* A PodGroup is essentially a CRD object (with a Spec &amp;amp; Metadata of only a few dozen bytes, as defined in &lt;code&gt;pkg/controllers/job/job_controller_actions.go&lt;/code&gt;). The creation process is just a single write operation from kube-apiserver to etcd.
* It does not involve scheduling decisions, node communication, or resource calculations. It returns immediately upon success without subsequent long-running processes.&lt;/p&gt;

&lt;p&gt;However, it&amp;rsquo;s worth noting that if &lt;code&gt;MinMember&lt;/code&gt; is set too high or Queue resources are insufficient, the scheduler may still block Job startup in a &lt;strong&gt;later stage&lt;/strong&gt; because the PodGroup conditions are not met. This is a scheduling issue, not a CREATE issue.&lt;/p&gt;

&lt;h5 id=&#34;pod-creation&#34;&gt;Pod Creation&lt;/h5&gt;

&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;// pkg/controllers/job/job_controller_actions.go
func (cc *jobcontroller) syncJob(jobInfo *apis.JobInfo, updateStatus state.UpdateStatusFn) error {
    ...
    waitCreationGroup := sync.WaitGroup{}
    ...
	var podToCreateEachTask []*v1.Pod
	for _, ts := range job.Spec.Tasks {
        for i := 0; i &amp;lt; int(ts.Replicas); i++ {           // Collect pods to be created
            ...
            newPod := createJobPod(job, tc, ts.TopologyPolicy, i, jobForwarding)
            ...
            podToCreateEachTask = append(podToCreateEachTask, newPod)
            waitCreationGroup.Add(1)
            ...
        }
        podToCreate[ts.Name] = podToCreateEachTask
    }
    ...
	for taskName, podToCreateEachTask := range podToCreate {
        ...
        go func(taskName string, podToCreateEachTask []*v1.Pod) {
            ...
            for _, pod := range podToCreateEachTask {
                go func(pod *v1.Pod) {
                    defer waitCreationGroup.Done()
                    kubeClient.CoreV1().Pods(...).Create(...)
                }(pod)
            }
            ...
        }(taskName, podToCreateEachTask)
    }
    ...
    waitCreationGroup.Wait()  // ⬅ Blocking: does not return until the entire batch is complete
    ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Observation&lt;/strong&gt;: All pods within a Job must be created in the same batch. The &lt;code&gt;Wait()&lt;/code&gt; call blocks the worker goroutine from servicing other Jobs, becoming a performance bottleneck.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unlike PodGroups, Pods are native K8s objects with many complex fields. They require more default field population and take longer to write to etcd, making them a more likely bottleneck.&lt;/p&gt;

&lt;h4 id=&#34;4-2-2-experimental-design-for-worker-thread-optimization&#34;&gt;4.2.2 Experimental Design for Worker Thread Optimization&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Experiment Setup&lt;/strong&gt;:
- &lt;strong&gt;Worker Threads&lt;/strong&gt;: 1, 5, 10, 25, 50, 100, 150, 200, 400, 600
- &lt;strong&gt;Job and Pod Combinations&lt;/strong&gt;: 10000×1, 5000×2, 2000×5, 1000×10, 500×20, 200×50, 100×100, 50×200, 20×500, 1×10000
- &lt;strong&gt;Metrics&lt;/strong&gt;: Time from test start to the completion of the last &lt;code&gt;CREATE&lt;/code&gt; and &lt;code&gt;SCHEDULE&lt;/code&gt; event.&lt;/p&gt;

&lt;h4 id=&#34;4-2-3-analysis-of-experimental-results&#34;&gt;4.2.3 Analysis of Experimental Results&lt;/h4&gt;

&lt;p&gt;The experiments led to two key conclusions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Impact of Increasing Job Count with the Same Number of Worker Threads&lt;/strong&gt;:
- With a fixed number of worker threads, as the number of Jobs increased, the &lt;code&gt;CREATE&lt;/code&gt; time generally increased.
- This confirms that a higher number of Jobs leads to a larger computational load on the Controller. Furthermore, the &lt;code&gt;CREATE&lt;/code&gt; requests are fragmented into smaller pieces, exacerbating contention with &lt;code&gt;SCHEDULE&lt;/code&gt; requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Impact of Increasing Worker Threads with the Same Job Count&lt;/strong&gt;:
- With a fixed number of Jobs, as the number of Controller worker threads increased, the &lt;code&gt;CREATE&lt;/code&gt; time showed a distinct &lt;strong&gt;&amp;ldquo;V-shaped&amp;rdquo; curve&lt;/strong&gt;: it first decreased, then increased.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analysis of the V-Shaped Performance Curve&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Too Few Threads (Left Side of the V)&lt;/strong&gt;: Fails to fully utilize computing resources, with I/O waits becoming the bottleneck.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The bottleneck is in API-Server communication and remote etcd I/O.&lt;/li&gt;
&lt;li&gt;Computing resources are underutilized. A small number of threads quickly finish their computations, send &lt;code&gt;CREATE&lt;/code&gt; requests, and then block.&lt;/li&gt;
&lt;li&gt;Increasing the number of threads here can better utilize computing resources and eliminate bubble time spent waiting on communication/I/O.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Too Many Threads (Right Side of the V)&lt;/strong&gt;: Exacerbates CPU and API-Server contention, leading to a performance decrease.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The bottleneck becomes the computing resources themselves, plus increased cross-job Pod queuing and blocking.&lt;/li&gt;
&lt;li&gt;A large number of threads have already saturated all computing resources. Pods from different jobs now compete for creation in a fair-queuing manner.&lt;/li&gt;
&lt;li&gt;The last few pods in a job block the entire job, which makes the surge-and-stall phenomenon more severe.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://deploy-preview-499--volcano-sh.netlify.app/img/performance-tuning/v-shaped-performance-curve-worker-threads.png&#34; alt=&#34;V-Shaped CREATE Time with Different Worker Threads&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;4-3-hypothesis-3-contention-between-controller-and-scheduler&#34;&gt;4.3 Hypothesis 3: Contention Between Controller and Scheduler&lt;/h3&gt;

&lt;p&gt;We observed that the stair-step stalls for &lt;code&gt;CREATE&lt;/code&gt; (performed by the Controller) and &lt;code&gt;SCHEDULE&lt;/code&gt; (performed by the Scheduler) never occurred simultaneously. Further investigation revealed that &lt;strong&gt;the root cause is contention from two independent components concurrently writing to a shared resource, the K8s API-Server/ETCD&lt;/strong&gt;. Short‑term queuing/retries manifest macroscopically as alternating execution.&lt;/p&gt;

&lt;h4 id=&#34;4-3-1-analysis-of-independence-at-the-source-code-level&#34;&gt;4.3.1 Analysis of Independence at the Source Code Level&lt;/h4&gt;

&lt;p&gt;A careful analysis of the Volcano source code shows that the &lt;code&gt;CREATE&lt;/code&gt; functionality belongs to the Controller component, while the &lt;code&gt;SCHEDULE&lt;/code&gt; functionality belongs to the Scheduler component. There are no direct calls, dependencies, or other relationships between them at the code level:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;// pkg/controllers/job/job_controller_actions.go
func (cc *jobcontroller) syncJob(jobInfo *apis.JobInfo, updateStatus state.UpdateStatusFn) error {
    // Controller is responsible for Pod creation
    for _, pod := range podToCreateEachTask {
        go func(pod *v1.Pod) {
            defer waitCreationGroup.Done()
            newPod, err := cc.kubeClient.CoreV1().Pods(pod.Namespace).Create(context.TODO(), pod, metav1.CreateOptions{})
            // ...
        }(pod)
    }
    waitCreationGroup.Wait()
}

// pkg/scheduler/actions/allocate/allocate.go
func (alloc *Action) Execute(ssn *framework.Session) {
    // Scheduler is responsible for Pod scheduling
    for _, task := range tasks {
        // Scheduling decision and binding
        ssn.Bind(task, node)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;4-3-2-analysis-of-contention-at-the-api-server-level&#34;&gt;4.3.2 Analysis of Contention at the API-Server Level&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;The real contention occurs at the K8s API-Server level&lt;/strong&gt;. After completing their respective operations, both components must submit their results (creating a Pod / updating a Pod&amp;rsquo;s status) to the &lt;strong&gt;K8s API-Server&lt;/strong&gt;, which then handles writing to etcd. When both components operate on the same Pod object simultaneously, optimistic concurrency control triggers short‑term retries/queuing. Under scale, this ultimately manifests as an alternating execution pattern where one works while the other waits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Request Flow Analysis&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;// Controller&#39;s Pod creation request flow
JobController.syncJob() 
  → kubeClient.CoreV1().Pods().Create() 
    → kube-apiserver 
      → etcd write

// Scheduler&#39;s Pod scheduling request flow
VolcanoScheduler.allocate() 
  → ssn.Bind() 
    → kubeClient.CoreV1().Pods().Update() 
      → kube-apiserver 
        → etcd write
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;4-3-3-in-depth-analysis-of-queuing-and-retry-mechanisms&#34;&gt;4.3.3 In-depth Analysis of Queuing and Retry Mechanisms&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Impact of Job Count on Request Patterns&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Request Fragmentation&lt;/strong&gt;: When the number of jobs is high, a single batch of 10,000 Pod &lt;code&gt;CREATE&lt;/code&gt; requests gets fragmented into many smaller batches.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contention and Interleaving&lt;/strong&gt;: Time gaps appear between these small batches of &lt;code&gt;CREATE&lt;/code&gt; requests. &lt;code&gt;SCHEDULE&lt;/code&gt; (Pod Update) requests sent by the Scheduler &amp;ldquo;fill in&amp;rdquo; these gaps.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Amplifying Effect of Goroutine Blocking and Request Retries&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;The Controller processes jobs one at a time per worker. A worker goroutine waits for all pods within one job to be created before moving on to the next. During this process, if some pods in a job are blocked, it has an amplifying effect, blocking the entire goroutine. Furthermore, resource updates for a series of pods belonging to the same job will trigger updates to the same PodGroup or even the Job object, increasing the likelihood of transient retries and short stalls.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-go&#34;&gt;// pkg/controllers/job/job_controller_actions.go
func (cc *jobcontroller) syncJob(jobInfo *apis.JobInfo, updateStatus state.UpdateStatusFn) error {
    // ...
    waitCreationGroup := sync.WaitGroup{}
    // Collect all pods to be created
    for _, ts := range job.Spec.Tasks {
        for i := 0; i &amp;lt; int(ts.Replicas); i++ {
            // ...
            waitCreationGroup.Add(1)
        }
    }
    
    // Create pods concurrently
    for taskName, podToCreateEachTask := range podToCreate {
        go func(taskName string, podToCreateEachTask []*v1.Pod) {
            for _, pod := range podToCreateEachTask {
                go func(pod *v1.Pod) {
                    defer waitCreationGroup.Done()
                    // API-Server call
                    newPod, err := cc.kubeClient.CoreV1().Pods(pod.Namespace).Create(context.TODO(), pod, metav1.CreateOptions{})
                }(pod)
            }
        }(taskName, podToCreateEachTask)
    }
    
    // ⚠️ Key blocking point: waits for all pods to be created
    waitCreationGroup.Wait()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;4-3-4-experimental-evidence&#34;&gt;4.3.4 Experimental Evidence&lt;/h4&gt;

&lt;p&gt;Direct evidence of resource contention was found during testing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Under multi-job workloads, the &amp;ldquo;stair-step&amp;rdquo; patterns in the cumulative pod count curves for Volcano&amp;rsquo;s Pod creation (CREATE) and scheduling (SCHEDULE) did not occur at the same time. In the per-second throughput curves, the two alternated between performance peaks and troughs but were never in a trough simultaneously.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://deploy-preview-499--volcano-sh.netlify.app/img/performance-tuning/stair-step-stall-phenomenon.png&#34; alt=&#34;CREATE/SCHEDULE Cumulative Pod Counts Show Alternating Stair-Steps&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://deploy-preview-499--volcano-sh.netlify.app/img/performance-tuning/create-schedule-throughput-fluctuating-inversely.png&#34; alt=&#34;CREATE/SCHEDULE Throughput Fluctuates Inversely&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;4-4-other-hypotheses-ruled-out-factors&#34;&gt;4.4 Other Hypotheses: Ruled-Out Factors&lt;/h3&gt;

&lt;p&gt;We also hypothesized and tested other factors. Experiments showed that the &lt;code&gt;enqueue&lt;/code&gt; scheduling phase and Volcano version differences were not the core factors causing the performance issues.&lt;/p&gt;

&lt;h4 id=&#34;4-4-1-verification-of-enqueue-functionality&#34;&gt;4.4.1 Verification of Enqueue Functionality&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Experimental Analysis&lt;/strong&gt;: &lt;strong&gt;enqueue&lt;/strong&gt; is an important stage in the Volcano scheduler&amp;rsquo;s workflow, primarily responsible for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Job Enqueue Management&lt;/strong&gt;: Adding submitted Jobs to the scheduling queue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Priority Sorting&lt;/strong&gt;: Sorting Jobs based on factors like priority and submission time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resource Pre-check&lt;/strong&gt;: Preliminary check to see if cluster resources meet Job requirements.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Queue Capacity Control&lt;/strong&gt;: Managing queue capacity limits and admission control.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The complete scheduling flow of the Volcano scheduler is as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-mermaid&#34;&gt;graph LR
    A[Job Submission] --&amp;gt; B[enqueue]
    B --&amp;gt; C[allocate]
    C --&amp;gt; D[backfill]
    D --&amp;gt; E[reclaim]
    E --&amp;gt; F[preempt]
    
    B1[enqueue stage] --&amp;gt; B2[Queue Management]
    B1 --&amp;gt; B3[Priority Sorting]
    B1 --&amp;gt; B4[Resource Pre-check]
    
    C1[allocate stage] --&amp;gt; C2[Resource Allocation]
    C1 --&amp;gt; C3[Node Selection]
    C1 --&amp;gt; C4[Pod Binding]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;enqueue&lt;/code&gt; could potentially impact scheduling performance by &lt;strong&gt;restricting pod creation based on a preliminary resource check&lt;/strong&gt;: it checks for sufficient resources before pod creation and may limit the creation rate of new pods if resources are scarce. This could cause the CREATED event curve to stagnate and become a bottleneck in some scenarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Experimental Design&lt;/strong&gt;: We disabled the enqueue functionality to test this hypothesis.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# Modify scheduler configuration to remove the enqueue action
actions: &amp;quot;allocate, backfill, reclaim&amp;quot;  # Original: actions: &amp;quot;enqueue, allocate, backfill&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Experimental Result&lt;/strong&gt;: After disabling enqueue, the test results were largely consistent with previous local tests. The periodic surges in CREATED events still occurred, and there was no significant improvement in scheduling performance. The &lt;code&gt;enqueue&lt;/code&gt; action is mainly responsible for task queuing and priority sorting, and its direct impact on pod creation and scheduling is limited.&lt;/p&gt;

&lt;h4 id=&#34;4-4-2-verification-of-version-differences&#34;&gt;4.4.2 Verification of Version Differences&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Experimental Design&lt;/strong&gt;: We noticed that the latest Volcano version was newer than our test version and suspected this might cause performance differences. We tested this by upgrading Volcano from v1.11.0 to v1.12.0-alpha.0:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# Batch replace version numbers
sed -i &#39;s/v1\.11\.0/v1.12.0-alpha.0/g&#39; schedulers/volcano/*/deployment.yaml
sed -i &#39;s/v1\.11\.0/v1.12.0-alpha.0/g&#39; schedulers/volcano/*/job.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Experimental Result&lt;/strong&gt;: After upgrading to v1.12.0-alpha.0, the test results were consistent with previous local tests. The abnormal phenomena in CREATED events persisted, and there was no significant improvement in scheduling performance. While version upgrades may bring some improvements, the core performance bottlenecks remained.&lt;/p&gt;

&lt;h2 id=&#34;5-tuning-guide-and-future-outlook&#34;&gt;5. Tuning Guide and Future Outlook&lt;/h2&gt;

&lt;h3 id=&#34;5-1-short-term-optimization-solutions&#34;&gt;5.1 Short-Term Optimization Solutions&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Adjust Webhook Timeout&lt;/strong&gt;: In the &lt;code&gt;deployment&lt;/code&gt; for &lt;code&gt;volcano-admission-service&lt;/code&gt;, increase the &lt;code&gt;webhook&lt;/code&gt;&amp;rsquo;s &lt;code&gt;timeoutSeconds&lt;/code&gt; from the default of &lt;code&gt;10&lt;/code&gt; to &lt;code&gt;30&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increase Webhook Resources&lt;/strong&gt;: Allocate more CPU and Memory resources to the &lt;code&gt;volcano-admission&lt;/code&gt; Pod (e.g., refer to &amp;ldquo;Huawei Cloud - Volcano Scheduler - Recommended Resources&amp;rdquo; and use &lt;code&gt;limits: cpu: &amp;quot;2500m&amp;quot;, memory: &amp;quot;4Gi&amp;quot;&lt;/code&gt; for clusters with 1000 nodes or more).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The resource quota for the volcano-admission component depends on the cluster scale, as shown in Table 1. The resource quotas for the volcano-controller and volcano-scheduler components are related to the cluster&amp;rsquo;s node and Pod scale, with the following recommendations:
- For clusters with fewer than 100 nodes, the default configuration can be used: CPU request of 500m and limit of 2000m; Memory request of 500Mi and limit of 2000Mi.
- For clusters with more than 100 nodes, for every additional 100 nodes (or 10,000 pods), it is recommended to increase the CPU request by 500m and memory request by 1000Mi. The CPU limit should be 1500m higher than the request, and the memory limit should be 1000Mi higher than the request.
Note:
Recommended calculation formulas for requests:
- CPU Request: Calculate the value of &amp;ldquo;target node count * target Pod scale&amp;rdquo; and find the closest value in Table 2 via interpolation, rounding up to the nearest specification for request and limit values.
  For example, in a scenario with 2000 nodes and 20k pods, &amp;ldquo;target node count * target Pod scale&amp;rdquo; is 4000w. The closest higher spec is 700/7w (&amp;ldquo;cluster node count * Pod scale&amp;rdquo; equals 4900w), so the recommended CPU request is 4000m and the limit is 5500m.
- Memory Request: It is recommended to allocate 2.4G of memory per 1000 nodes and 1G of memory per 10k pods. These values should be added together.
  That is: Memory Request = (Target Node Count / 1000) * 2.4G + (Target Pod Scale / 10k) * 1G. For example, in a 2000-node, 20k-pod scenario, the memory request would be 2 * 2.4G + 2 * 1G = 6.8G.&lt;/p&gt;
&lt;/blockquote&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configure Controller Worker Threads Reasonably&lt;/strong&gt;: Adjust the &lt;code&gt;--worker-threads&lt;/code&gt; startup parameter for &lt;code&gt;volcano-controller-manager&lt;/code&gt; based on cluster size and Job shape. For scenarios with a large number of Jobs (&amp;gt;500), it is recommended to increase this value (e.g., to 100-200).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&#34;5-2-long-term-optimization-solutions&#34;&gt;5.2 Long-Term Optimization Solutions&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Replace Webhook&lt;/strong&gt;: Consider moving some of the Webhook&amp;rsquo;s validation logic down into the Controller or using K8s CRD Validation Rules (CEL) to reduce RPC overhead.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optimize Controller and Scheduler Interaction&lt;/strong&gt;: Design a dynamic rate-matching mechanism to balance the &lt;code&gt;CREATE&lt;/code&gt; and &lt;code&gt;SCHEDULE&lt;/code&gt; rates. This would achieve global optimization rather than blindly improving the performance of a single stage.&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>HyperNode Auto Discovery User Guide</title>
      <link>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_hypernode_auto_discovery/</link>
      <pubDate>Tue, 03 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_hypernode_auto_discovery/</guid>
      <description>

&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;This document describes how to use the HyperNode network topology auto-discovery feature in Volcano. This feature automatically discovers the network topology within the cluster and creates and maintains HyperNode custom resources (CRs) based on the discovered information. The Volcano scheduler leverages these HyperNode CRs for scheduling decisions, eliminating the need for users to manually maintain HyperNode information.&lt;/p&gt;

&lt;h2 id=&#34;prerequisites&#34;&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;Please &lt;a href=&#34;https://github.com/volcano-sh/volcano/tree/master?tab=readme-ov-file#quick-start-guide&#34; target=&#34;_blank&#34;&gt;Install Volcano&lt;/a&gt; with version &amp;gt;= v1.12.0 first.&lt;/p&gt;

&lt;h2 id=&#34;configuration&#34;&gt;Configuration&lt;/h2&gt;

&lt;p&gt;The HyperNode network topology discovery feature is configured via a ConfigMap. The ConfigMap contains the configuration for the discovery sources, such as UFM, RoCE, and label, you can modify the configuration according to your own cluster environments.
Please note that you should replace with your Volcano namespace if Volcano is not installed in the default namespace.&lt;/p&gt;

&lt;h3 id=&#34;secret-configuration-required-first-step&#34;&gt;Secret Configuration (Required First Step)&lt;/h3&gt;

&lt;p&gt;Before configuring the UFM discovery, you must first create a Kubernetes Secret to store your UFM credentials:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl create secret generic ufm-credentials \
  --from-literal=username=&#39;your-ufm-username&#39; \
  --from-literal=password=&#39;your-ufm-password&#39; \
  -n volcano-system
&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Replace your-ufm-username and your-ufm-password with your actual UFM credentials, and adjust the namespace if needed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;example-configmap&#34;&gt;Example ConfigMap&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: v1
kind: ConfigMap
metadata:
  name: volcano-controller-configmap
  namespace: volcano-system # Replace with your Volcano namespace if Volcano is not installed in the default namespace.
data:
  volcano-controller.conf: |
    networkTopologyDiscovery:
      - source: ufm
        enabled: true
        interval: 10m
        credentials:
          secretRef:
            name: ufm-credentials # Replace with the secret name that stores the UFM credentials.
            namespace: volcano-system #Replace with the secret namespace that stores the UFM credentials.
        config:
          endpoint: https://ufm-server:8080
          insecureSkipVerify: true
      - source: roce
        enabled: false
        interval: 15m
        config:
          endpoint: https://roce-server:9090
      - source: label
        enabled: true
        config:
          networkTopologyTypes:
            topologyA2:
              - nodeLabel: &amp;quot;volcano.sh/tor&amp;quot; # The label that indicates which tor a node belongs to. If the values corresponding to this label on different nodes are the same, it means these nodes belong to the same tor. 
              - nodeLabel: &amp;quot;kubernetes.io/hostname&amp;quot; # A standard label automatically added to each node in a Kubernetes cluster, used to identify the hostname of the node.
            topologyA3:
              - nodeLabel: &amp;quot;volcano.sh/hypercluster&amp;quot; # The label that indicates which hypercluster a node belongs to. If the values corresponding to this label on different nodes are the same, it means these nodes belong to the same hypercluster.
              - nodeLabel: &amp;quot;volcano.sh/hypernode&amp;quot; # The label that indicates which hypernode a node belongs to. If the values corresponding to this label on different nodes are the same, it means these nodes belong to the same hypernode.
              - nodeLabel: &amp;quot;kubernetes.io/hostname&amp;quot; # A standard label automatically added to each node in a Kubernetes cluster, used to identify the hostname of the node.
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;configuration-options&#34;&gt;Configuration Options&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;source&lt;/code&gt;: The discovery source. Supported values are &lt;code&gt;ufm&lt;/code&gt;, &lt;code&gt;roce&lt;/code&gt;, and &lt;code&gt;label&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;enabled&lt;/code&gt;: Whether the discovery source is enabled.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;interval&lt;/code&gt;: The interval between discovery operations. If not specified, the default value is 1 hour.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;config&lt;/code&gt;: The configuration for the discovery source. The configuration options vary depending on the discovery source.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;credentials&lt;/code&gt;: The credentials configuration for accessing the discovery source.

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;secretRef&lt;/code&gt;: Reference to a Kubernetes Secret containing credentials.

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt;: The name of the Secret.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;namespace&lt;/code&gt;: The namespace of the Secret.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;ufm-configuration-options&#34;&gt;UFM Configuration Options&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;endpoint&lt;/code&gt;: The UFM API endpoint.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;insecureSkipVerify&lt;/code&gt;: Whether to skip TLS certificate verification. This should only be used in development environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;roce-configuration-options-currently-not-supported&#34;&gt;RoCE Configuration Options(Currently not supported)&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;endpoint&lt;/code&gt;: The RoCE API endpoint.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;token&lt;/code&gt;: The RoCE API token.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;label-configuration-options&#34;&gt;Label Configuration Options&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;networkTopologyTypes&lt;/code&gt;: The structure that supports different types of network topologies, including those for GPU, NPU, etc. Below is an example of the NPU cluster network topology.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;topologyA2&lt;/code&gt;: The network topology type of A2(Ascend 910B) cluster.

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nodeLabel&lt;/code&gt;: For the labels on a node, when there are multiple labels, hypernodes are constructed from bottom to top. The bottommost label is kubernetes.io/hostname, which is a standard built-in label key in Kubernetes, and the label above it is volcano.sh/tor, indicates which tor a node belongs to.&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;topologyA3&lt;/code&gt;: The network topology type of A3(Ascend 910C) cluster.

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nodeLabel&lt;/code&gt;: For the labels on a node, when there are multiple labels, hypernodes are constructed from bottom to top. The bottommost label is kubernetes.io/hostname, which is a standard built-in label key in Kubernetes, and the label above it is volcano.sh/hypernode and volcano.sh/hypercluster, volcano.sh/hypernode indicates which hypernode a node belongs to, volcano.sh/hypercluster indicates which hypercluster a node belongs to.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;

&lt;li&gt;&lt;pre&gt;&lt;code class=&#34;language-text&#34;&gt;    tier2                     s4                                 s5                         
                      /               \                   /              \                 
    tier1           s0                s1                 s2              s3              
                 /      \          /      \           /      \        /      \         
              node0    node1    node2    node3      node4   node5   node6   node7       
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;pre&gt;&lt;code&gt;       The labels of each node in the cluster:
        node0:   kubernetes.io/hostname=192.168.1.10 # Node Ip
                 volcano.sh/hypernode=s0             # HyperNode Name
                 volcano.sh/hypercluster=s4          # HyperCluster Name
        node1:   kubernetes.io/hostname=192.168.1.11           
                 volcano.sh/hypernode=s0             
                 volcano.sh/hypercluster=s4          
        node2:   kubernetes.io/hostname=192.168.1.12 
                 volcano.sh/hypernode=s1             
                 volcano.sh/hypercluster=s4          
        node3:   kubernetes.io/hostname=192.168.1.13 
                 volcano.sh/hypernode=s1             
                 volcano.sh/hypercluster=s4          
        node4:   kubernetes.io/hostname=192.168.1.14 
                 volcano.sh/hypernode=s2
                 volcano.sh/hypercluster=s5 
        node5:   kubernetes.io/hostname=192.168.1.15 
                 volcano.sh/hypernode=s2
                 volcano.sh/hypercluster=s5 
        node6:   kubernetes.io/hostname=192.168.1.16 
                 volcano.sh/hypernode=s3
                 volcano.sh/hypercluster=s5
        node7:   kubernetes.io/hostname=192.168.1.17 
                 volcano.sh/hypernode=s3
                 volcano.sh/hypercluster=s5
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;verification&#34;&gt;Verification&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Check the Volcano controller logs to ensure that the discovery sources are started successfully.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl logs -n volcano-system -l app=volcano-controllers -c volcano-controllers | grep &amp;quot;Successfully started all network topology discoverers&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Check the created HyperNode resources.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl get hypernodes -l volcano.sh/network-topology-source=&amp;lt;source&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Replace &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; with the discovery source you configured, such as &lt;code&gt;ufm&lt;/code&gt; or &lt;code&gt;label&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;troubleshooting&#34;&gt;Troubleshooting&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If the discovery sources are not started successfully, check the Volcano controller logs for errors.&lt;/li&gt;
&lt;li&gt;If the HyperNode resources are not created, check the discovery source configuration and ensure that the discovery source is able to connect to the network topology data source.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;best-practices&#34;&gt;Best Practices&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Volcano uses Kubernetes-standard Secrets to store sensitive credential information (username/password or token). For more stringent key encryption requirements, users should consider additional mechanisms like &lt;a href=&#34;https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/&#34; target=&#34;_blank&#34;&gt;Encrypting Secret Data at Rest&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The credential Secrets can be placed in a specified namespace for better isolation.&lt;/li&gt;
&lt;li&gt;For UFM discoverer, the controller only needs read access to the specific Secret containing credentials.&lt;/li&gt;
&lt;li&gt;For label discoverer, the controller needs to pre-label the nodes with the tags corresponding to the hypernodes.&lt;/li&gt;
&lt;li&gt;When deploying in production environments, proper RBAC policies should be configured to limit access to Secrets.&lt;/li&gt;
&lt;li&gt;TLS certificate verification should be enabled in production environments to prevent MITM attacks.&lt;/li&gt;
&lt;li&gt;Monitor the Volcano controller logs for errors.&lt;/li&gt;
&lt;li&gt;Set a reasonable discovery interval to avoid overloading the network topology data source.&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>MPI Plugin User Guide</title>
      <link>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_mpi_plugin/</link>
      <pubDate>Tue, 03 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_mpi_plugin/</guid>
      <description>

&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;MPI plugin&lt;/strong&gt; is designed to optimize the user experience when running MPI jobs, it not only allows users to write less yaml, but also ensures the normal operation of MPI jobs.&lt;/p&gt;

&lt;h2 id=&#34;how-the-mpi-plugin-works&#34;&gt;How the MPI Plugin Works&lt;/h2&gt;

&lt;p&gt;The MPI plugin will do three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open ports used by MPI for all containers of the job&lt;/li&gt;
&lt;li&gt;Force open &lt;code&gt;ssh&lt;/code&gt; and &lt;code&gt;svc&lt;/code&gt; plugins&lt;/li&gt;
&lt;li&gt;add &lt;code&gt;MPI_HOST&lt;/code&gt; environment variable for master pod, this environment variable includes the worker&amp;rsquo;s domain name, It is used by the &lt;code&gt;--host&lt;/code&gt; parameter of &lt;code&gt;mpiexec&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;parameters-of-the-mpi-plugin&#34;&gt;Parameters of the MPI Plugin&lt;/h2&gt;

&lt;h3 id=&#34;key-points&#34;&gt;Key Points&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;master&lt;/code&gt; or &lt;code&gt;worker&lt;/code&gt; is configured, please ensure that the tasks corresponding to their values exist, and the roles of these tasks correspond to the meaning of the parameters&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;port&lt;/code&gt; is configured, make the port value of &lt;code&gt;sshd&lt;/code&gt; the same as the value of the parameter.&lt;/li&gt;
&lt;li&gt;If the &lt;code&gt;gang&lt;/code&gt; plugin is enabled, then make sure that the value of &lt;code&gt;minAvailable&lt;/code&gt; is &lt;strong&gt;equal&lt;/strong&gt; to the number of &lt;code&gt;replicas of the worker&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;arguments&#34;&gt;Arguments&lt;/h3&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Default Value&lt;/th&gt;
&lt;th&gt;Required&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;master&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;master&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Name of MPI master&lt;/td&gt;
&lt;td&gt;&amp;ndash;master=mpimaster&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;worker&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;worker&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Name of MPI worker&lt;/td&gt;
&lt;td&gt;&amp;ndash;worker=mpiworker&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;port&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;The port to open for the container&lt;/td&gt;
&lt;td&gt;&amp;ndash;port=5000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&#34;examples&#34;&gt;Examples&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
  name: lm-mpi-job
spec:
  minAvailable: 1
  schedulerName: volcano
  plugins:
    mpi: [&amp;quot;--master=mpimaster&amp;quot;,&amp;quot;--worker=mpiworker&amp;quot;,&amp;quot;--port=22&amp;quot;]  ## MPI plugin register
  tasks:
    - replicas: 1
      name: mpimaster
      policies:
        - event: TaskCompleted
          action: CompleteJob
      template:
        spec:
          containers:
            - command:
                - /bin/sh
                - -c
                - |
                  mkdir -p /var/run/sshd; /usr/sbin/sshd;
                  mpiexec --allow-run-as-root --host ${MPI_HOST} -np 2 mpi_hello_world;
              image: volcanosh/example-mpi:0.0.3
              name: mpimaster
              workingDir: /home
          restartPolicy: OnFailure
    - replicas: 2
      name: mpiworker
      template:
        spec:
          containers:
            - command:
                - /bin/sh
                - -c
                - |
                  mkdir -p /var/run/sshd; /usr/sbin/sshd -D;
              image: volcanosh/example-mpi:0.0.3
              name: mpiworker
              workingDir: /home
          restartPolicy: OnFailure
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>Network Topology Aware Scheduling User Guide</title>
      <link>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_network_topology_aware_scheduling/</link>
      <pubDate>Tue, 03 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_network_topology_aware_scheduling/</guid>
      <description>

&lt;h2 id=&#34;1-background&#34;&gt;1 Background&lt;/h2&gt;

&lt;p&gt;In the context of AI large model training, Model Parallelism divides the model across multiple nodes, requiring frequent and substantial data exchange between these nodes during training. At this point, the network transmission performance between nodes often becomes the bottleneck of training, significantly affecting training efficiency. Data centers have diverse network types (such as IB, RoCE, NVSwitch, etc.), and the network topology is complex, typically involving multiple layers of switches. The fewer switches between two nodes, the lower the communication latency and the higher the throughput. Therefore, users want to schedule workloads to the best performance domain with the highest throughput and lowest latency, minimizing cross-switch communication to accelerate data exchange and improve training efficiency.&lt;/p&gt;

&lt;p&gt;To address this, Volcano proposed the &lt;strong&gt;Network Topology Aware Scheduling&lt;/strong&gt; strategy, which uses a unified network topology API and intelligent scheduling policies to solve the network communication performance issues in large-scale data center AI training tasks.&lt;/p&gt;

&lt;h2 id=&#34;2-features&#34;&gt;2 Features&lt;/h2&gt;

&lt;h3 id=&#34;2-1-unified-network-topology-api-accurately-expressing-network-topology&#34;&gt;2.1 Unified Network Topology API: Accurately Expressing Network Topology&lt;/h3&gt;

&lt;p&gt;To shield the differences in data center network types, Volcano defines a new CRD &lt;strong&gt;HyperNode&lt;/strong&gt; to represent the network topology, providing a standardized API interface. Compared to the traditional method of using node labels to represent network topology, HyperNode has the following advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unified Semantics&lt;/strong&gt;: HyperNode provides a standardized way to describe network topology, avoiding the semantic inconsistency issues of the label method.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hierarchical Structure&lt;/strong&gt;: HyperNode supports a tree-like hierarchical structure, allowing for more precise representation of the actual network topology.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy Management&lt;/strong&gt;: Cluster administrators can manually create HyperNodes or use network topology auto-discovery tools to maintain HyperNodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A HyperNode represents a network topology performance domain, typically mapped to a switch or tor. Multiple HyperNodes are connected hierarchically to form a tree structure. For example, the following diagram shows a network topology composed of multiple HyperNodes:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://deploy-preview-499--volcano-sh.netlify.app/img/network-topology/hypernode-example.png&#34; alt=&#34;hypernode-tree-structure.png&#34; /&gt;&lt;/p&gt;

&lt;p&gt;In this structure, the communication efficiency between nodes depends on the HyperNode hierarchy span between them. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;node0 and node1 belong to s0, achieving the highest communication efficiency.&lt;/li&gt;
&lt;li&gt;node1 and node2 need to cross two layers of HyperNodes (s0→s4→s1), resulting in lower communication efficiency.&lt;/li&gt;
&lt;li&gt;node0 and node4 need to cross three layers of HyperNodes (s0→s4→s6), resulting in the worst communication efficiency.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;2-2-hypernode-auto-discovery-simplify-network-topology-management&#34;&gt;2.2 HyperNode Auto Discovery: Simplify Network Topology Management&lt;/h3&gt;

&lt;p&gt;To further reduce the management burden of network topology information, Volcano provides the HyperNode auto-discovery feature. This feature automatically discovers network topology structures within clusters and creates, updates, or deletes corresponding HyperNode Custom Resources (CRs) based on the discovery results.&lt;/p&gt;

&lt;p&gt;The auto-discovery feature offers the following key benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Automated Management&lt;/strong&gt;: Automatically discovers and maintains HyperNode information from various data sources (such as UFM, RoCE, or node labels), eliminating the need for manual maintenance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real-time Updates&lt;/strong&gt;: Periodically synchronizes network topology changes to ensure HyperNode information remains current with the actual network state.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extensible Architecture&lt;/strong&gt;: Supports pluggable Discoverer components, allowing users to develop custom discovery logic for their specific network management tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Through this automated discovery mechanism, users can focus on job scheduling configuration without worrying about the complexities of HyperNode creation and maintenance, significantly simplifying the deployment and management of network topology-aware scheduling.&lt;/p&gt;

&lt;h3 id=&#34;2-3-network-topology-constraints-improve-network-communication-efficiency&#34;&gt;2.3 Network Topology Constraints: Improve Network Communication Efficiency&lt;/h3&gt;

&lt;p&gt;In Volcano Jobs, the &lt;code&gt;NetworkTopology&lt;/code&gt; field can be configured to describe the network topology constraints during job deployment. The specific constraint configuration is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mode&lt;/code&gt;: Supports &lt;code&gt;hard&lt;/code&gt; and &lt;code&gt;soft&lt;/code&gt; modes.

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;hard&lt;/code&gt;: Hard constraint, tasks within the job must be deployed within the same HyperNode.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;soft&lt;/code&gt;: Soft constraint, tasks are deployed within the same HyperNode as much as possible.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;highestTierAllowed&lt;/code&gt;: Used with hard mode, indicating the highest tier of HyperNode allowed for job deployment. This field is not required when mode is soft.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, the following configuration means the job can only be deployed within HyperNodes of tier 2 or lower, such as s4 and s5, and their child nodes s0, s1, s2, s3. Otherwise, the job will remain in the Pending state:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;spec:
  networkTopology:
    mode: hard
    highestTierAllowed: 2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;By configuring this scheduling constraint, users can precisely control the network topology constraints of the job, ensuring that the job runs in the best performance domain that meets the conditions, thereby significantly improving training efficiency.&lt;/p&gt;

&lt;h3 id=&#34;2-4-subgroup-affinity-policy-fine-grained-control-of-scheduling-constraints-for-distributed-jobs&#34;&gt;2.4 SubGroup Affinity Policy: Fine-grained Control of Scheduling Constraints for Distributed Jobs&lt;/h3&gt;

&lt;p&gt;In large model training scenarios, the entire training task requires enormous resources, which typically cannot be deployed within a single network performance domain. It&amp;rsquo;s necessary to split the training task into pipeline parallelism (PP) or data parallelism (DP), allowing parallel tasks to be deployed across network performance domains.&lt;/p&gt;

&lt;p&gt;To address this, Volcano provides the SubGroup Affinity Policy. In a Volcano Job, the &lt;code&gt;partitionPolicy&lt;/code&gt; field can be configured to partition Pods within a Job, and network topology constraints can be configured for each partition.&lt;/p&gt;

&lt;p&gt;During scheduling, each partition will follow its own network topology constraints, thereby meeting the network communication performance requirements of each parallel task partition.&lt;/p&gt;

&lt;p&gt;In addition, each partition must follow the Gang scheduling constraints. That is, a partition is allowed to be scheduled only when all pods within it meet the scheduling conditions.&lt;/p&gt;

&lt;p&gt;For example, the following configuration indicates that the entire job is only allowed to be scheduled to HyperNodes at Tier 2 or below. And within the job, the 8 Pods are divided into 2 partitions, and each partition can only be scheduled to HyperNodes at Tier 1.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;spec:
  networkTopology:
    mode: hard
    highestTierAllowed: 2
  tasks:
    - name: &amp;quot;task1&amp;quot;
      replica: 8
      partitionPolicy:
        totalPartitions: 2
        partitionSize: 4
        networkTopology:
          mode: hard
          highestTierAllowed: 1
      template:
      # pod template
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;2-5-hypernode-level-bin-packing-improve-resource-utilization-for-network-topology-performance-domain&#34;&gt;2.5 HyperNode-Level Bin Packing: Improve Resource Utilization for Network Topology Performance Domain&lt;/h3&gt;

&lt;p&gt;When scheduling workloads with network topology constraints, the scheduler will prioritize scheduling them to HyperNodes with higher current resource utilization to improve resource utilization in the network performance domain.&lt;/p&gt;

&lt;p&gt;As shown in the diagram below, suppose there are two Tier 1 HyperNodes in the cluster, where HyperNode0 already has some resources occupied by other tasks. A user issues a Volcano Job, dividing it into two partitions, each configured with &lt;code&gt;highestTierAllowed=1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://deploy-preview-499--volcano-sh.netlify.app/img/network-topology/hypernode-binpack.png&#34; alt=&#34;hypernode-binpack.png&#34; /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Without HyperNode-level bin packing, the scheduling result might be that partition 0 is scheduled to HyperNode0, and partition 1 is scheduled to HyperNode1.&lt;/li&gt;
&lt;li&gt;With HyperNode-Level bin packing, both partition 0 and 1 will be prioritized for scheduling to HyperNode0. In this case, HyperNode1 can be used as a fully idle HyperNode for other tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Furthermore, for workloads without network topology constraints, the scheduler will prioritize scheduling them to nodes with higher hypernode-level resource utilization (where each tier of hypernodes will be considered), in order to reduce the hypernode-level resource fragmentation.&lt;/p&gt;

&lt;p&gt;For example, as shown in the figure below, there is a cluster consisting of 8 nodes and 7 hypernodes. Currently, the resources of node0, node2 and node4 are occupied by existing tasks, while those of the other nodes are idle. Then, at this point, a user submits a volcano job with two independent pods to this cluster.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://deploy-preview-499--volcano-sh.netlify.app/img/network-topology/hypernode-binpack-normal-pods.png&#34; alt=&#34;hypernode-binpack-normal-pods.png&#34; /&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Without HyperNode-level bin packing, the scheduler may assign these two pods to node1 and node6, or node3 and node7, making the hypernode-level resource fragmentation more severe.&lt;/li&gt;
&lt;li&gt;With HyperNode-level bin packing, the scheduler will prefer to assign them to node1 and node3, leaving node5, node6 and node7 together for other larger network-topology-constrained workloads.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;3-user-guide&#34;&gt;3 User Guide&lt;/h2&gt;

&lt;h3 id=&#34;3-1-installing-volcano&#34;&gt;3.1 Installing Volcano&lt;/h3&gt;

&lt;p&gt;Refer to &lt;a href=&#34;https://github.com/volcano-sh/volcano/blob/master/installer/README.md&#34; target=&#34;_blank&#34;&gt;Install Guide&lt;/a&gt; to install Volcano.&lt;/p&gt;

&lt;p&gt;After installed, update the scheduler configuration:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;kubectl edit cm -n volcano-system volcano-scheduler-configmap
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;kind: ConfigMap
apiVersion: v1
metadata:
  name: volcano-scheduler-configmap
  namespace: volcano-system
data:
  volcano-scheduler.conf: |
    actions: &amp;quot;enqueue, allocate, backfill&amp;quot;
    tiers:
    - plugins:
      - name: priority
      - name: gang
      - name: conformance
    - plugins:
      - name: drf
      - name: predicates
      - name: proportion
      - name: nodeorder
      - name: binpack
      - name: network-topology-aware # Add it to enable network-topology-aware plugin
        arguments:
          weight: 10
          hypernode.binpack.cpu: 5                                     # HyperNode-level bin packing weight for CPU
          hypernode.binpack.memory: 1                                  # HyperNode-Level bin packing weight for memory
          hypernode.binpack.resources: nvidia.com/gpu, example.com/foo # Custom resource names to be considered by the bin packing strategy
          hypernode.binpack.resources.nvidia.com/gpu: 2                # HyperNode-Level bin packing weight for &amp;quot;nvidia.com/gpu&amp;quot; resources
          hypernode.binpack.resources.example.com/foo: 3               # HyperNode-Level bin packing weight for &amp;quot;example.com/foo&amp;quot; resources
          hypernode.binpack.normal-pod.enable: true                    # Whether or not to enable HyperNode-level bin packing for normal pods
          hypernode.binpack.normal-pod.fading: 0.8                     # Parameter to control the weights of hypernodes of different tiers, i.e., the weights of hypernodes of tier `i` are math.Pow(fading, i-1) 
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;3-2-building-network-topology&#34;&gt;3.2 Building Network Topology&lt;/h3&gt;

&lt;h4 id=&#34;3-2-1-build-via-hypernode-auto-discovery-recommended&#34;&gt;3.2.1 Build via HyperNode Auto-Discovery (Recommended)&lt;/h4&gt;

&lt;p&gt;Refers to &lt;a href=&#34;https://deploy-preview-499--volcano-sh.netlify.app/en/docs/user-guide/how_to_use_hypernode_auto_discovery/&#34;&gt;How to Use HyperNode Auto Discovery&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&#34;3-2-2-build-manually&#34;&gt;3.2.2 Build Manually&lt;/h4&gt;

&lt;p&gt;You can build Network Topology by creating HyperNode CRs manually. Refer to the definition of CRD &lt;code&gt;hypernodes.topology.volcano.sh&lt;/code&gt; for more details.&lt;/p&gt;

&lt;h3 id=&#34;3-3-deploy-workloads-using-network-topology-aware-scheduling&#34;&gt;3.3 Deploy Workloads Using Network Topology Aware Scheduling&lt;/h3&gt;

&lt;p&gt;Based on the following network topology, this chapter will demonstrate how workloads can be deployed using Network Topology Aware Scheduling.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://deploy-preview-499--volcano-sh.netlify.app/img/network-topology/workload-deploy-example.png&#34; alt=&#34;workload-deploy-example.png&#34; /&gt;&lt;/p&gt;

&lt;h4 id=&#34;3-3-1-deploying-using-volcano-job-with-network-topology-constraints-configured&#34;&gt;3.3.1 Deploying Using Volcano Job With Network Topology Constraints Configured&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a Volcano job where each Pod requests the full CPU resources of one node. Example follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
 name: network-topology-job
 namespace: default
spec:
 schedulerName: volcano
 minAvailable: 4
 networkTopology:
   mode: hard
   highestTierAllowed: 1
 tasks:
   - name: t0
     replicas: 8
     template:
       spec:
         containers:
           - name: c0
             image: nginx:latest
             resources:
               requests:
                 cpu: &amp;quot;4&amp;quot;
               limits:
                 cpu: &amp;quot;4&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The scheduling result is as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl get pod -owide
NAME                        READY   STATUS    RESTARTS   AGE   IP             NODE
network-topology-job-t0-0   1/1     Running   0          5s    192.168.0.10   node4
network-topology-job-t0-1   1/1     Running   0          5s    192.168.0.11   node5
network-topology-job-t0-2   1/1     Running   0          5s    192.168.0.12   node6
network-topology-job-t0-3   1/1     Running   0          5s    192.168.0.13   node7
network-topology-job-t0-4   0/1     Pending   0          5s    &amp;lt;none&amp;gt;         &amp;lt;none&amp;gt;
network-topology-job-t0-5   0/1     Pending   0          5s    &amp;lt;none&amp;gt;         &amp;lt;none&amp;gt;
network-topology-job-t0-6   0/1     Pending   0          5s    &amp;lt;none&amp;gt;         &amp;lt;none&amp;gt;
network-topology-job-t0-7   0/1     Pending   0          5s    &amp;lt;none&amp;gt;         &amp;lt;none&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this example, Pods within the Job cannot be scheduled across Tier 1 HyperNodes. The Job is scheduled to
HyperNode1, which only has 4 nodes (Node4~Node7), so only 4 Pods are running.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&#34;3-3-2-deploying-using-volcano-job-with-network-topology-constraints-and-subgroup-affinity-policy-configured&#34;&gt;3.3.2 Deploying Using Volcano Job With Network Topology Constraints And SubGroup Affinity Policy Configured&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a Volcano job where each Pod requests the full CPU resources of one node; and configure a SubGroup Affinity Policy to divide the 8 Pods within the Job into 2 partitions. Example follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
 name: network-topology-job
 namespace: default
spec:
 schedulerName: volcano
 minAvailable: 4
 networkTopology:
   mode: hard
   highestTierAllowed: 2
 tasks:
   - name: t0
     replicas: 8
     partitionPolicy:
       totalPartitions: 2
       partitionSize: 4
       networkTopology:
         mode: hard
         highestTierAllowed: 1
     template:
       spec:
         containers:
           - name: c0
             image: nginx:latest
             resources:
               requests:
                 cpu: &amp;quot;4&amp;quot;
               limits:
                 cpu: &amp;quot;4&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The scheduling result is as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl get pod -owide
NAME                        READY   STATUS    RESTARTS   AGE   IP             NODE
network-topology-job-t0-0   1/1     Running   0          5s    192.168.0.10   node2
network-topology-job-t0-1   1/1     Running   0          5s    192.168.0.11   node3
network-topology-job-t0-2   1/1     Running   0          5s    192.168.0.12   node1
network-topology-job-t0-3   1/1     Running   0          5s    192.168.0.13   node0
network-topology-job-t0-4   1/1     Running   0          5s    192.168.0.14   node4
network-topology-job-t0-5   1/1     Running   0          5s    192.168.0.15   node5
network-topology-job-t0-6   1/1     Running   0          5s    192.168.0.16   node6
network-topology-job-t0-7   1/1     Running   0          5s    192.168.0.17   node7
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this example, the entire Job is scheduled to HyperNode2 (Node0~Node7). The first partition (Pod0~Pod3) is scheduled to HyperNode0 (Node0~Node3), the second partitions (Pod4~Pod7) is scheduled to HyperNode1 (Node4~Node7), and each partition satisfies its own network topology constraints.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&#34;3-3-3-deploying-using-volcano-job-without-network-topology-constraints&#34;&gt;3.3.3 Deploying Using Volcano Job Without Network Topology Constraints&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a Volcano job with two independent pods, where each Pod requests the full CPU resources of one node. Example follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
 name: network-topology-job
 namespace: default
spec:
 schedulerName: volcano
 minAvailable: 2
 tasks:
   - name: t0
     replicas: 2
     template:
       spec:
         containers:
           - name: c0
             image: nginx:latest
             resources:
               requests:
                 cpu: &amp;quot;4&amp;quot;
               limits:
                 cpu: &amp;quot;4&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The scheduling result is as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ kubectl get pod -owide
NAME                        READY   STATUS    RESTARTS   AGE   IP             NODE
network-topology-job-t0-0   1/1     Running   0          5s    192.168.0.10   node0
network-topology-job-t0-1   1/1     Running   0          5s    192.168.0.11   node1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Since the resources are all idle, the first pod, i.e., network-topology-job-t0-0, will be scheduled to any node. It is node0 in this example. Then, the second pod, i.e., network-topology-job-t0-1, must be scheduled to node1, node2 or node3. It is node1 in this example. This is because the resource utilization of HyperNode0 is currently higher than HyperNode1.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
  </channel>
</rss>
