Skip to main content
Redhat Developers  Logo
  • AI

    Get started with AI

    • Red Hat AI
      Accelerate the development and deployment of enterprise AI solutions.
    • AI learning hub
      Explore learning materials and tools, organized by task.
    • AI interactive demos
      Click through scenarios with Red Hat AI, including training LLMs and more.
    • AI/ML learning paths
      Expand your OpenShift AI knowledge using these learning resources.
    • AI quickstarts
      Focused AI use cases designed for fast deployment on Red Hat AI platforms.
    • No-cost AI training
      Foundational Red Hat AI training.

    Featured resources

    • OpenShift AI learning
    • Open source AI for developers
    • AI product application development
    • Open source-powered AI/ML for hybrid cloud
    • AI and Node.js cheat sheet

    Red Hat AI Factory with NVIDIA

    • Red Hat AI Factory with NVIDIA is a co-engineered, enterprise-grade AI solution for building, deploying, and managing AI at scale across hybrid cloud environments.
    • Explore the solution
  • Learn

    Self-guided

    • Documentation
      Find answers, get step-by-step guidance, and learn how to use Red Hat products.
    • Learning paths
      Explore curated walkthroughs for common development tasks.
    • Guided learning
      Receive custom learning paths powered by our AI assistant.
    • See all learning

    Hands-on

    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.
    • Interactive labs
      Learn by doing in these hands-on, browser-based experiences.
    • Interactive demos
      Click through product features in these guided tours.

    Browse by topic

    • AI/ML
    • Automation
    • Java
    • Kubernetes
    • Linux
    • See all topics

    Training & certifications

    • Courses and exams
    • Certifications
    • Skills assessments
    • Red Hat Academy
    • Learning subscription
    • Explore training
  • Build

    Get started

    • Red Hat build of Podman Desktop
      A downloadable, local development hub to experiment with our products and builds.
    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.

    Download products

    • Access product downloads to start building and testing right away.
    • Red Hat Enterprise Linux
    • Red Hat AI
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat Developer Toolset

    References

    • E-books
    • Documentation
    • Cheat sheets
    • Architecture center
  • Community

    Get involved

    • Events
    • Live AI events
    • Red Hat Summit
    • Red Hat Accelerators
    • Community discussions

    Follow along

    • Articles & blogs
    • Developer newsletter
    • Videos
    • Github

    Get help

    • Customer service
    • Customer support
    • Regional contacts
    • Find a partner

    Join the Red Hat Developer program

    • Download Red Hat products and project builds, access support documentation, learning content, and more.
    • Explore the benefits

How Kueue schedules Spark jobs fairly on Red Hat OpenShift AI

Give Spark teams predictable CPU and memory quotas on Red Hat OpenShift AI while preserving a clear path from submission to execution.

November 4, 2026
Vedant Deshpande
Related topics:
Artificial intelligence
Related products:
Red Hat OpenShift

    Table of contents:

    • How Kueue and the Spark Operator divide the work
    • What you will build
    • Set up the integration
    • Prove it works
    • 3 things the reference docs will not tell you
    • Set up operational rules for the queue
    • Conclusion

    A Spark cluster can run out of headroom long before it looks large on paper. A data engineer submits a massive run, an ML team launches feature engineering, and suddenly both developers are staring at stuck pipelines wondering why their driver pods won't schedule. The Kubernetes scheduler places individual pods, but it has no opinion about which application should receive a team's quota first. So every Spark submission turns into a race, and whoever gets pods scheduled first wins.

    Kueue changes the question from "which pod fits on which node?" to "which application deserves resources right now?" It holds a SparkApplication at the gate, before the Kubeflow Spark operator ever creates a driver or executor pod. When the application's declared CPU and memory fit within an available quota, Kueue admits it and the Spark operator proceeds (see figure 1). When they do not fit, the application waits in a queue you can inspect instead of producing a half-started mess competing for nodes.

    The admission flow. Kueue holds the gate; the Spark Operator creates pods only after quota is reserved.
    Figure 1: The admission flow. Kueue holds the gate, and the Spark Operator creates pods only after quota is reserved.

    This article demonstrates how to set up that flow on Red Hat OpenShift AI. More importantly, it covers the operational decisions the reference documentation leaves to you: why self-managed queues beat auto-created ones, what preemption actually costs for Spark, and how to keep an unlabeled job from slipping past the queue.

    How Kueue and the Spark Operator divide the work

    Kueue doesn't replace the Kubernetes scheduler or the Spark Operator. Each controller keeps a distinct job, and understanding the handoff prevents the most common misdiagnoses.

    1. Job submission

    • What happens: User creates a SparkApplication with a local-queue label
    • Observable state: SparkApplication created

    2. Interception and suspension

    • What happens: Kueue's webhook sets spec.suspend: true and creates a Workload — a CR representing the app's resource request inside Kueue's quota engine
    • Observable state: Suspended

    3. Quota evaluation

    • What happens: Kueue compares the Workload's declared requests with ClusterQueue quota
    • Observable state: Pending or QuotaReserved

    4. Workload admission

    • What happens: Quota available — Kueue admits the Workload, sets spec.suspend: false
    • Observable state: Admitted

    5. Pod creation

    • What happens: Spark Operator creates driver + executor pods
    • Observable state: Resuming → Running

    6. Job completion

    • What happens: Application finishes; Kueue releases quota, admits next Workload
    • Observable state: Completed

    There are 2 surprises here. First, a "pending" SparkApplication is not broken, it might simply be waiting for a quota. Second, Kubernetes node capacity and Kueue quota are separate constraints. If a Spark application won't start, check the Kueue Workload conditions before you look at pod events.

    What you will build

    The exercise in this article creates a self-managed queue (as in figure 2) for a project named spark-team-a.

    The queue hierarchy. One application runs, and a second waits until the quota is released.
    Figure 2: The queue hierarchy. One application runs, and a second waits until the quota is released.

    The ClusterQueue reserves 3 CPUs and 4 GiB. The sample app requests a driver and 2 executors (1 CPU, 512m each). One application fits. A second copy waits until the first finishes.

    I use self-managed queues because they make quota boundaries explicit and work well with GitOps. OpenShift AI can auto-create queues (autoCreateQueues: true), but explicit ClusterQueue and LocalQueue resources give administrators tighter control and make code review straightforward.

    Set up the integration

    The complete manifests and step-by-step instructions live in the Kueue Spark administrator guide. Here is the condensed path to a working demo.

    1. Install the Red Hat build of Kueue operator

    Install the Red Hat build of Kueue from OperatorHub in the Red Hat OpenShift web console. Enable cluster monitoring for the openshift-kueue-operator namespace. The official installation guide covers the full steps.

    2. Activate the Spark operator and set Kueue to unmanaged

    oc patch datasciencecluster default-dsc \
     -n redhat-ods-operator --type=merge \
     -p '{"spec":{"components":{"sparkoperator":{"managementState":"Managed"},"kueue":{"managementState":"Unmanaged"}}}}'

    Warning

    Do not set Kueue to Managed in the DataScienceCluster. That refers to the deprecated embedded distribution and conflicts with the external Red Hat build of Kueue operator.

    3. Add SparkApplication to the Kueue frameworks list

    Edit the Kueue CR (oc edit kueue cluster) and add SparkApplication under spec.config.integrations.frameworks. Then apply the RBAC that lets Kueue manage SparkApplication finalizers. See the admin guide RBAC section for the full manifest.

    If a SparkApplication stays suspended with no Workload created, check Kueue controller logs for blockOwnerDeletion errors. That means the RBAC is missing.

    4. Create the project and queue hierarchy

    oc new-project spark-team-a
    oc label namespace spark-team-a \
     kueue.openshift.io/managed=true \
     team=data-platform --overwrite

    Then create a ResourceFlavor, ClusterQueue (3 CPU, 4 GiB), and LocalQueue. The key resource is the ClusterQueue:

    apiVersion: kueue.x-k8s.io/v1beta2
    kind: ClusterQueue
    metadata:
      name: spark-team-a-cq
    spec:
      namespaceSelector:
        matchLabels:
          team: data-platform
      resourceGroups:
      - coveredResources: ["cpu", "memory"]
        flavors:
        - name: spark-default
          resources:
          - name: cpu
            nominalQuota: "3"
          - name: memory
            nominalQuota: 4Gi

    The complete ResourceFlavor, ClusterQueue, and LocalQueue manifests are in the admin guide.

    Prove it works

    Submit a SparkApplication with the queue label. The only change from a standard manifest is 1 label:

    metadata:
      labels:
        kueue.x-k8s.io/queue-name: spark-team-a-lq

    A complete example manifest (spark-pi-kueue.yaml) is in the user guide. Submit it and watch the lifecycle:

    oc apply -f spark-pi-a.yaml
    oc get sparkapplication spark-pi-a -n spark-team-a -w
    oc get workloads -n spark-team-a -w

    Now submit a second copy (spark-pi-b) while the first is still running. It remains suspended—queued, not broken—because the first application consumes the full 3-CPU quota. When spark-pi-a completes, Kueue admits spark-pi-b automatically.

    3 things the reference docs don't tell you

    There are some subtleties about this process that are easy to miss, and that aren't necessarily spelled out in reference documentation.

    Preemption is a restart, not a pause

    When Kueue suspends a running SparkApplication, the Spark operator deletes every driver and executor pod. In-memory state, shuffle data, and ephemeral files are gone. Kueue does not checkpoint the application for you (see figure 3).

    Preemption deletes all pods. Re-admission starts a new driver from scratch.
    Figure 3: Preemption deletes all pods. Re-admission starts a new driver from scratch.

    Start with non-preemptive quotas unless your workloads handle restarts gracefully. If you enable preemption later, require persistent output, idempotent transformations, and checkpoints stored outside the pods. Tell job owners that a higher-priority submission can terminate a lower-priority compute already in progress, not just delay it.

    Note

    Dynamic executor allocation is not supported with Kueue. Set executor.instances to a fixed value.

    An unlabeled SparkApplication can bypass the queue

    The kueue.openshift.io/managed=true namespace label activates Kueue webhooks, but the app still needs a kueue.x-k8s.io/queue-name label.

    Quota is not utilization

    Kueue reserves quota based on declared requests, not runtime consumption. A driver requesting 1 CPU but idling at 100m still holds 1 CPU of quota. Require explicit coreRequest values for both driver and executors in every manifest. A team with missing requests can throw off the quota math for everyone.

    Set up operational rules for the queue

    YAML is the easy part. Before onboarding more teams, your operating policy should answer four questions:

    • Who owns each quota? Use namespace selectors and GitOps-reviewed queue resources so a team can't attach its LocalQueue to another team's capacity.
    • What is the declared footprint? Require explicit driver/executor requests and fixed executor counts. If you leave this informal, nobody can trace consumed quota back to a specific application.
    • When is preemption acceptable? Base the answer on restart cost, not just priority labels. A five-minute SparkPi is cheap to preempt. A 4-hour pipeline writing to ephemeral storage is not.
    • How do users identify a healthy wait? Publish oc get workloads and oc describe workload so users can tell the difference between queued and misconfigured.

    Conclusion

    The configuration surface is small: 1 Kueue CR update, 1 RBAC manifest, and 1 label per SparkApplication. Instead of every application racing for pods on submission, Kueue gives platform teams predictable queue management and quota boundaries for fixed-footprint Spark jobs.

    Test it by submitting 2 copies of the same application. The second one waits without creating any pods, then starts automatically when the first finishes. If it does, then you have a controlled admission path.

    To get started, try the hands-on walkthrough in the Kueue Spark administrator guide on a non-production cluster. Share the Kueue Spark user guide with your data engineering teams before enabling preemption so everyone understands how suspension affects running tasks.

    Additional resources

    • Open Data Hub Spark Operator repository
    • Kueue Spark administrator guide
    • Kueue Spark user guide
    • Red Hat build of Kueue documentation
    • Red Hat OpenShift AI documentation

    Related Posts

    • Smarter GPU sharing: How Red Hat build of Kueue works with dynamic resource allocation

    • Configure admission fair sharing in Red Hat build of Kueue 1.4

    • Gang autoscaling on OpenShift with Kueue and ProvisionRequest

    • Red Hat build of Kueue 1.3: Enhanced batch workload management on Kubernetes

    Recent Posts

    • How Kueue schedules Spark jobs fairly on Red Hat OpenShift AI

    • Manage Java transitive dependencies with Lightwell rebuilds

    • JBoss EAP clustering in OpenShift: KUBE_PING discovery

    • How to run I/O workloads on OpenShift Virtualization VMs

    • Onboard your repository to Testing Farm with Claude Code

    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Platforms

    • Red Hat AI
    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Build

    • Developer Sandbox
    • Developer tools
    • Interactive tutorials
    • API catalog

    Quicklinks

    • Learning resources
    • E-books
    • Cheat sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site status dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2026 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility
    Ask AI