KEP-6276: Integrate Workload APIs with Deployment Controller
KEP-6276: Workload-Aware Scheduling for Deployments
- Release Signoff Checklist
- Summary
- Motivation
- Proposal
- Design Details
- Production Readiness Review Questionnaire
- Implementation History
- Future Work
- Drawbacks
- Alternatives
Release Signoff Checklist
Items marked with (R) are required prior to targeting to a milestone / release.
- (R) Enhancement issue in release milestone, which links to KEP dir in kubernetes/enhancements
- (R) KEP approvers have approved the KEP status as
implementable - (R) Design details are appropriately documented
- (R) Test plan is in place, giving consideration to SIG Architecture and SIG Testing input (including test refactors)
- e2e Tests for all Beta API Operations (endpoints)
- (R) Ensure GA e2e tests meet requirements for Conformance Tests
- (R) Minimum Two Week Window for GA e2e tests to prove flake free
- (R) Graduation criteria is in place
- (R) all GA Endpoints must be hit by Conformance Tests within one minor version of promotion to GA
- (R) Production readiness review completed
- (R) Production readiness review approved
- “Implementation History” section is up-to-date for milestone
- User-facing documentation has been created in kubernetes/website , for publication to kubernetes.io
- Supporting documentation
Summary
This KEP integrates the Workload-aware Scheduling (WAS) APIs (Workload and PodGroup) into
apps/v1 Deployments through a user-facing spec.scheduling field, allowing users to express
scheduling intent such as gang scheduling, topology placement, disruption handling, and DRA
resource claims. The Deployment controller creates one stable Deployment-owned Workload, while
the ReplicaSet controller materializes one ReplicaSet-owned PodGroup per revision via the shared
workloadbuilder library (KEP-6089
), adapting the controller-as-compiler pattern established by
the Job + WAS integration (KEP-5547
) to the Deployment/ReplicaSet rollout, scaling, and
revision-history lifecycle.
Motivation
Long-running inference services (multi-GPU model servers, disaggregated prefill/decode
pipelines) commonly run as apps/v1.Deployment objects and require all replicas co-located
within the same topology domain or placed atomically to avoid wasting accelerator capacity on
partially placed groups.
Today the only path to gang-schedule or topology-schedule a Deployment is to manually create a
PodGroup and inject pod.spec.schedulingGroup.podGroupName into the pod template. This approach
is fragile: a pod created before its referenced PodGroup exists hangs silently in Pending with no
event or error. It also places the entire burden of naming, ownership, garbage collection, and
scale-time reconciliation on the user, none of which composes cleanly with rolling updates,
revision history, or HPA-driven scaling. Alternatively, users can turn to external solutions like
Volcano, Kueue, KAI or Coscheduling plugin.
Goals
- Enable users to apply Workload-Aware Scheduling to Deployments without manually creating or managing Workloads, PodGroups, or their lifecycle.
- Allow users to optionally set gang
minCount. When unset, the controller derives it fromspec.replicas. Validation ensuresminCountdoes not exceedreplicas. - Support gang scheduling with
Recreatestrategy. - Support horizontal scaling and HPA natively through the Deployment
/scalesubresource. - Support topology-constrained Deployments whose replicas must be co-located within a requested topology domain.
- Support shared DRA resource claims for Deployment replicas, including claims backed by
ResourceClaimTemplateobjects. - Re-evaluate
RollingUpdatestrategy with gang scheduling (deferred to Beta). - Re-evaluate elastic gang semantics with multiple PodGroups per ReplicaSet for
minCount < replicas(deferred to Beta).
Non-Goals
- Automatic in-tree recovery or rescheduling of a replacement pod stuck on a saturated topology domain. Left to out-of-tree queue managers.
- Supporting mutable
spec.schedulingpost-creation. All fields are immutable after creation exceptgang.minCount, which is mutable to support scaling. - Multi-level or nested composite (
CompositePodGroup) structures. This KEP covers single-level Deployment to ReplicaSet workloads only. - Integrating gang semantics with the eviction API so that voluntary evictions respect
disruptionMode. - Exclusive access to DRA claims. Any pod on the same node can reference a PodGroup’s claim by name and share the device. Claim isolation is a DRA-layer property; this KEP does not add access control beyond what DRA provides.
Proposal
This proposal builds on the recently introduced Workload-aware Scheduling enhancements. We assume the reader is acquainted with the following KEPs:
- KEP-4671 : Gang Scheduling.
- KEP-5710 : Workload-aware preemption.
- KEP-5732 : Topology-aware workload scheduling.
- KEP-6089 : WAS Controller APIs.
The Deployment controller compiles the user’s scheduling intent into a single Workload, created
once per Deployment. For each ReplicaSet revision, the ReplicaSet controller materializes one
ReplicaSet-owned PodGroup from the Workload’s PodGroupTemplate, carrying the scheduling policy,
topology constraints, and resource claims into a per-revision runtime context. The intent is
expressed through a new spec.scheduling field.
The key design principles:
- One
Workloadper Deployment serves as the shared scheduling template. Each ReplicaSet revision gets its ownPodGroupstamped from that template, with an independent scheduling context (topology domain, gang quorum). - Scheduling intent (gang semantics, topology constraints, disruption mode) is expressed through
spec.schedulingand is orthogonal to the Deployment’s rollout strategy (spec.strategy). Whenspec.schedulingis omitted, no scheduling objects are created. - Gang
minCountdefaults tospec.replicaswhen unset. Users may setminCountexplicitly, but validation rejects values exceedingreplicas. - All
spec.schedulingfields are immutable after creation. - Deployments own the
Workloadfor its lifecycle, and ReplicaSets own individualPodGroupsfor revision-specific scheduling. Each PodGroup also carries a non-controller ownerReference to the Workload for lifecycle management, matching the Job pattern (KEP-5547 ). Supported by deterministic naming and reconciliation, creation is fully idempotent so that controllers recover missing objects after crashes while garbage collection handles cleanup.
Deployment Integration - API Usage Examples
Example 1: Gang scheduling with zone topology and atomic disruption
A multi-GPU inference service whose 3 replicas must schedule together, co-locate within the same availability zone, and be disrupted atomically:
apiVersion: apps/v1
kind: Deployment
metadata:
name: inference-server
namespace: ml-serving
spec:
replicas: 3
strategy:
type: Recreate
scheduling:
schedulingPolicy:
gang: {}
schedulingConstraints:
topology:
- key: "topology.kubernetes.io/zone"
disruptionMode:
all: {}
selector:
matchLabels:
app: inference-server
template:
metadata:
labels:
app: inference-server
spec:
containers:
- name: server
image: inference-server:v1
resources:
limits:
nvidia.com/gpu: 1
The Deployment controller compiles this intent into a Workload owned by the Deployment. The
ReplicaSet controller creates and owns the revision-specific PodGroup. The Workload remains
stable and is reused across rollouts:
apiVersion: scheduling.k8s.io/v1beta1
kind: Workload
metadata:
name: inference-server-<hash>
namespace: ml-serving
ownerReferences:
- apiVersion: apps/v1
kind: Deployment
name: inference-server
uid: <deployment-uid>
controller: true
spec:
controllerRef:
apiVersion: apps/v1
kind: Deployment
name: inference-server
podGroupTemplates:
- name: inference-server-<hash>
schedulingPolicy:
gang:
minCount: 3
schedulingConstraints:
topology:
- key: "topology.kubernetes.io/zone"
disruptionMode:
all: {}
---
apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
name: inference-server-<podTemplateHash>
namespace: ml-serving
ownerReferences:
- apiVersion: apps/v1
kind: ReplicaSet
name: inference-server-<podTemplateHash>
uid: <rs-uid>
controller: true
- apiVersion: scheduling.k8s.io/v1beta1
kind: Workload
name: inference-server-<hash>
uid: <workload-uid>
spec:
schedulingPolicy:
gang:
minCount: 3
schedulingConstraints:
topology:
- key: "topology.kubernetes.io/zone"
disruptionMode:
all: {}
Example 2: Gang scheduling with user-defined minCount
Gang scheduling with a user-defined minCount lower than replicas. The gang is satisfiable
with 3 out of 4 pods, allowing partial placement:
apiVersion: apps/v1
kind: Deployment
metadata:
name: prefill-workers
spec:
replicas: 4
strategy:
type: Recreate
scheduling:
schedulingPolicy:
gang:
minCount: 3
selector:
matchLabels:
app: prefill-workers
template:
metadata:
labels:
app: prefill-workers
spec:
containers:
- name: worker
image: prefill:v2
resources:
limits:
nvidia.com/gpu: 2
Example 3: Gang with template-backed ResourceClaims
A gang Deployment that requests a shared DRA device allocated once per PodGroup:
apiVersion: apps/v1
kind: Deployment
metadata:
name: model-server
spec:
replicas: 3
strategy:
type: Recreate
scheduling:
schedulingPolicy:
gang: {}
resourceClaims:
- name: gpu-pool
resourceClaimTemplateName: gpu-template
selector:
matchLabels:
app: model-server
template:
metadata:
labels:
app: model-server
spec:
containers:
- name: server
image: model-server:v1
resources:
claims:
- name: gpu-pool
User Stories
Distributed inference server. A platform team runs a tensor-parallel inference service as a
Deployment. All replicas must be scheduled together or not at all, because a partially placed set
wastes accelerator capacity without serving traffic. The team sets
spec.scheduling.schedulingPolicy.gang: {}. On initial creation, the scheduler places the full
gang atomically or leaves all pods pending. On scale-up, existing pods continue running while new
pods wait for the updated gang quorum to be satisfiable.
Rack-local worker pool. A latency-sensitive service needs all its pods co-located within one
rack. The team adds a topology constraint on topology.kubernetes.io/rack. The scheduler places
the whole gang in a best-fit rack. If no single rack can satisfy the request, the Deployment
reports unavailable replicas through its standard status conditions.
Notes/Constraints/Caveats
- Users may set
gang.minCount. Validation rejects values exceedingreplicas. WhenminCount < replicas, the gang is satisfiable with fewer pods than the full replica count, but each ReplicaSet still has a single PodGroup. Multiple PodGroups per ReplicaSet for elastic gang semantics are deferred to Beta. - Gang scheduling requires
Recreatestrategy.RollingUpdatewith gang is rejected at admission. - With
Recreatestrategy, the old ReplicaSet scales to zero and its PodGroup and ResourceClaims are released before the new ReplicaSet is created. A transient overlap of old and new claims is possible due to async cleanup but is unlikely in practice. revisionHistoryLimitretains old ReplicaSets for rollback metadata only. PodGroups are explicitly deleted at scale-to-zero, so they are already gone before the ReplicaSet becomes a history entry. If explicit deletion is missed (e.g., crash), owner-reference GC removes the PodGroup when the ReplicaSet is pruned, and thepodgroup-protectionfinalizer ensures referencing pods drain first.- Named ResourceClaims pin all revisions to the same node (the node where the device is allocated). If the node lacks capacity for the gang’s pods and their requested resources, the update may remain Pending.
- Topology binding is permanent per PodGroup. A replacement pod stuck on a full domain will not automatically reschedule to a different domain.
- At
replicas=0, the Deployment-owned Workload is retained. If the user setminCountexplicitly, that value is preserved. Otherwise the controller defaults tominCount=1. The ReplicaSet-owned PodGroup is deleted at zero replicas and recreated when the Deployment scales positive again. - Workload and PodGroup informers and listers are used by the Deployment and ReplicaSet controllers to reconcile scheduling objects.
- PodDisruptionBudgets are independent of
spec.scheduling.Recreaterollouts and controller-driven scaling use direct pod deletion, not the eviction API, so PDBs do not block them. During voluntary evictions such as node drain, the eviction API respects PDBs independently of gang scheduling.disruptionModeonly affects scheduler preemption decisions and does not influence the eviction API. For example, consider a gang of 4 pods on one node with a PDB settingmaxUnavailableto 1. The drain evicts one pod, but the replacement cannot schedule while the node is cordoned. With one pod already unavailable, the PDB blocks eviction of the remaining three. The drain remains blocked until the node is uncordoned or the PDB is removed. - When
DRAWorkloadResourceClaimsgate is off,spec.scheduling.resourceClaimsis stored on the Deployment but silently stripped from the PodGroup by the apiserver. Pods fall back to per-pod claims instead of shared PodGroup-level claims. Alpha gap: rejection deferred to Beta.
Risks and Mitigations
- Named ResourceClaim deadlocks rollouts on tight nodes. A named claim pins revisions to one node. If that node lacks capacity for the gang’s pods and their requested resources, the rollout hangs. Mitigation: document the capacity requirement and prefer template-backed claims when independent per-revision allocation is needed.
Design Details
API Changes
A new optional field is added to DeploymentSpec in both the internal (pkg/apis/apps) and
external (apps/v1) types:
// Scheduling, if set, opts this Deployment into Workload-Aware Scheduling.
// The controller compiles one Workload per Deployment and one PodGroup per
// ReplicaSet. Gang minCount defaults to replicas when unset by the user.
//
// +featureGate=WorkloadWithDeployment
// +optional
// +k8s:ifDisabled(WorkloadWithDeployment)=+k8s:forbidden
// +k8s:optional
// +k8s:update=NoSet
// +k8s:update=NoUnset
Scheduling *DeploymentSchedulingConfiguration `json:"scheduling,omitempty"`
DeploymentSchedulingConfiguration mirrors batch/v1.JobSchedulingConfiguration, reusing the
scheduling.k8s.io/v1alpha3 building-block types directly. The generated Workload and
PodGroup resources use the served scheduling.k8s.io/v1beta1 API:
type DeploymentSchedulingConfiguration struct {
// SchedulingPolicy selects the scheduling mode. Defaults to Basic when gang
// is not specified. The user may set gang.minCount explicitly. When unset,
// the controller derives minCount from replicas.
// +optional
// +k8s:optional
// +k8s:update=NoSet
// +k8s:update=NoUnset
SchedulingPolicy *WorkloadPodGroupSchedulingPolicy
// SchedulingConstraints carries topology placement rules.
// +optional
// +k8s:optional
// +k8s:immutable
SchedulingConstraints *WorkloadPodGroupSchedulingConstraints
// DisruptionMode (single | all) is passed through to the PodGroup
// and consumed by scheduler preemption logic.
// +optional
// +k8s:optional
// +k8s:immutable
DisruptionMode *WorkloadPodGroupDisruptionMode
// ResourceClaims declares DRA ResourceClaims shared across all pods
// of the gang (allocated once to the PodGroup, not per-pod). Max 4
// entries. Immutable after creation.
// +optional
// +listType=map
// +listMapKey=name
// +k8s:maxItems=4
// +k8s:immutable
ResourceClaims []WorkloadPodGroupResourceClaim
}
Feature Gate and RBAC
The Scheduling field is gated by WorkloadWithDeployment (Alpha, default off). The gate depends
on GenericWorkload being enabled. When WorkloadWithDeployment is disabled, requests that set
spec.scheduling are rejected.
The deployment-controller ClusterRole grants get, list, watch, create, update, and
patch on scheduling.k8s.io/workloads.
The replicaset-controller ClusterRole grants:
get,list, andwatchonscheduling.k8s.io/workloads.get,list,watch,create,update,patch, anddeleteonscheduling.k8s.io/podgroups.
Controller Changes
OwnerReferences Relationship
The ownerReferences relationship between Deployment, ReplicaSet, Workload,
PodGroup, and Pod is as follows:
flowchart BT
Pod[Pod]
PodGroup[PodGroup]
Workload[Workload]
ReplicaSet[ReplicaSet]
Deployment[Deployment]
Pod -->|ownerRef <br/> controller| ReplicaSet
Pod -->|ownerRef <br/> non-controller| PodGroup
ReplicaSet -->|ownerRef <br/> controller| Deployment
PodGroup -->|ownerRef <br/> controller| ReplicaSet
PodGroup -->|ownerRef <br/> non-controller| Workload
Workload -->|ownerRef <br/> controller| Deployment- The
Workloadobject has an ownerReference to theDeploymentwithcontroller: true. - The
PodGroupobject has a controller ownerReference to theReplicaSetand a non-controller ownerReference to theWorkloadfor lifecycle management, matching the Job pattern (KEP-5547 ). - The
Podobject has an ownerReference to theReplicaSetwithcontroller: trueand a non-controller ownerReference to thePodGroupfor lifecycle management. Pods also reference their PodGroup throughspec.schedulingGroup.podGroupName.
By this ownership structure, garbage collection cascades correctly: deleting a Deployment
removes its ReplicaSets, which in turn remove their Pods and PodGroups. The Workload is
also removed through its Deployment ownerReference. The podgroup-protection finalizer
on PodGroups ensures referencing pods drain before the PodGroup is deleted.
Creation Ordering
For each scheduling-enabled ReplicaSet revision:
Deterministic naming. The Workload is named
<deployment.Name>-<hash>where the hash is derived from the Deployment UID, avoiding collisions when different controller types share a namespace and name. The PodGroup is named<deployment.Name>-<podTemplateHash>(one per ReplicaSet revision). Both naming patterns are stable across controller restarts.Pod-level injection. The ReplicaSet controller sets
pod.spec.schedulingGroup.podGroupNameat pod creation time, not on the persisted ReplicaSet template. This avoids leaking scheduling details into the template and eliminates the need for special-case exclusions in template-equality checks.Workload creation. Call
ensureWorkloadForDeployment(get-or-create) to instantiate the Deployment-owned Workload. The Workload’s scheduling configuration is derived from the Deployment. If the user set gangminCount, that value is used. OtherwiseminCountis derived from the replica count, defaulting to 1 at zero replicas.ReplicaSet creation. Create or update the ReplicaSet using the Deployment’s pod template.
PodGroup creation. Before creating pods, the ReplicaSet controller calls
ensurePodGroupForReplicaSet(get-or-create) to instantiate the ReplicaSet-owned PodGroup from the Workload’s sole PodGroupTemplate. The resultinggang.minCountis inherited from the Workload template and does not necessarily match the ReplicaSet’s desired replica count.Scale-to-zero cleanup. When the ReplicaSet has zero desired replicas,
ensurePodGroupForReplicaSetcallsdeletePodGroupForReplicaSetto remove the PodGroup. When the ReplicaSet scales positive again, the PodGroup is recreated before creating pods.
workloadbuilder Integration
The Deployment controller uses the shared workloadbuilder library, also used by Job, to compile
the Deployment’s spec.scheduling into one Workload with one PodGroupTemplate. The builder
preserves the configured scheduling constraints, disruption mode, and resource claims while
using the user’s explicit minCount when set, or deriving it from the Deployment’s replica count.
The ReplicaSet controller uses the same builder to materialize one PodGroup from the Workload’s
sole PodGroupTemplate. The runtime PodGroup inherits its gang minCount from the Workload’s
PodGroupTemplate. At zero replicas, the PodGroup is deleted because no pods exist to schedule.
Scaling and HPA
Scaling through the /scale subresource updates the Deployment’s desired replica count. For a
positive replica count, the Deployment controller first reconciles the Workload’s PodGroupTemplate
so its gang minCount reflects the resolved value (user-set or derived from replicas). It then
scales the relevant ReplicaSets.
The ReplicaSet controller reconciles each ReplicaSet-owned PodGroup before managing its pods. For a
positive ReplicaSet size, it creates or updates the PodGroup and inherits its runtime gang
minCount from the Workload’s PodGroupTemplate. When a ReplicaSet reaches zero replicas, its
PodGroup is deleted because no pods exist to schedule. When it scales positive again, the PodGroup is
recreated before new pods are created.
Scaling a positive ReplicaSet does not delete its existing PodGroup. The controller updates its quorum before creating additional pods. If the new gang cannot be scheduled, the new pods remain pending while existing pods continue running.
An explicit minCount acts as a floor for replicas. Since validation rejects
replicas < minCount, HPA or manual scaling cannot reduce replicas below that value. Users who
need HPA-driven scaling could leave minCount unset (gang: {}) so it auto-tracks replicas.
Mutability and Validation
spec.scheduling is validated in three complementary layers:
- Declarative validation (DV) on the building blocks owns the structural rules and most of
the immutability. Because the Deployment API embeds the versioned
scheduling.k8s.io/v1alpha3building blocks directly, their DV markers apply unchanged. - Hand-written Deployment validation covers the cross-cutting rules DV cannot express:
gang.minCountmust not exceedreplicas. If the user setsminCountand it exceeds the current replica count, the request is rejected.RollingUpdatewith gang is rejected. Gang scheduling requiresRecreatestrategy for Alpha.spec.schedulingwith a pre-existingschedulingGroupis rejected. If the pod template already setsspec.schedulingGroup, settingspec.schedulingis rejected at admission.
workloadbuildersemantic validation owns the consistency rules that must stay identical to what the controller compiles. Validation builds the sameWorkloadItemtree the controller does and callsNewBuilder(...).Validate(), running the builder’s allow-list checks. In-tree it is constructed withBuildOptions{DisableDeclarativeValidation: true}because the API server already ran DV on the versioned building blocks.
Test Plan
Unit Tests
Existing coverage for the core packages being modified:
k8s.io/kubernetes/pkg/controller/deployment:2026-09-25-68.9%k8s.io/kubernetes/pkg/controller/deployment/util:2026-09-25-61.4%k8s.io/kubernetes/pkg/controller/replicaset:2026-09-25-85.3%
Tests to add:
- Building the Deployment-owned Workload: scheduling constraints, disruption mode, resource claims,
owner reference, and positive gang
minCountare compiled correctly. - ReplicaSet scheduling reconciliation: the ReplicaSet-owned PodGroup is created from the Workload’s
sole PodGroupTemplate, its runtime
minCountcomes from the Workload’s PodGroupTemplate, and it is reconciled before pod creation. - ReplicaSet scale-to-zero behavior: the PodGroup is deleted at zero replicas and recreated before pods are created when the ReplicaSet scales positive.
- Validation:
minCount > replicasrejected,RollingUpdatewith gang rejected, immutability violations rejected, and resource-claim structural violations rejected. - Idempotent reconciliation: missing Workloads and PodGroups are recreated without duplicates.
Integration Tests
- Create a gang Deployment and verify one Deployment-owned Workload and one ReplicaSet-owned
PodGroup exist, with the resolved
minCountand every created pod carrying the correctschedulingGroup.podGroupName. - Verify creation ordering: the Workload exists before the ReplicaSet is created, and the PodGroup exists before the ReplicaSet creates pods.
- Scale up and down and verify the Workload template and active PodGroup receive the correct
positive
minCount. - Scale to zero and verify the Workload retains the user’s
minCount(or defaults to 1) while the PodGroup is deleted. Scale positive again and verify the Workload is patched and the PodGroup is recreated before pods are created. - Delete the Deployment and verify the Workload and ReplicaSet-owned PodGroup are eventually garbage-collected.
- Verify old PodGroups and template-backed ResourceClaims are released when old ReplicaSets reach zero.
E2E Tests
- Gang Deployment with
Recreate: all replicas bind atomically or none bind. - Admission rejection for
RollingUpdatewith gang andminCount > replicas. - Topology placement: gang lands in a single domain.
disruptionMode.singleversusall: preemption behavior differs as expected.- ResourceClaims: one template-backed claim per PodGroup, released when the PodGroup is deleted; named claims remain pinned to their allocated node.
- Controller crash recovery: deterministic naming yields idempotent recovery without duplicates.
- Scale-to-zero-and-back: the Workload retains the user’s
minCount(or defaults to 1). The PodGroup is deleted and recreated. - Scaling up does not disturb existing running pods: only new pods wait for the updated gang quorum.
- Single-pod replacement: a deleted pod is replaced without recreating the PodGroup.
Graduation Criteria
Alpha
- Feature implemented behind the
WorkloadWithDeploymentfeature gate (default: disabled). - The Deployment controller creates one Workload per Deployment, and the ReplicaSet controller
creates one PodGroup per ReplicaSet when the gate is enabled and
spec.schedulingis set. - ReplicaSet-owned PodGroups are created before the ReplicaSet creates pods.
- Gang scheduling with user-settable
minCount, topology constraints, disruption mode, and resourceClaims are wired end-to-end. - Admission validation rejects
minCount > replicas,RollingUpdatewith gang, immutability violations, and resourceClaims structural violations. - Unit, integration, and E2E tests cover creation ordering, validation, scaling, scale-to-zero cleanup, and garbage collection.
Beta
- Promote
WorkloadWithDeploymentto enabled by default. - Improve observability of scheduling failures through Deployment conditions and dedicated metrics (e.g., Workload/PodGroup creation latency).
- Investigate scheduler-side failure reporting for stuck topology domains, dependent on sig-scheduling exposing standardized signals distinguishing terminal from transient unschedulability.
- Re-evaluate whether elastic gang semantics (multiple PodGroups per ReplicaSet for
minCount < replicas) should be supported. - Re-evaluate
RollingUpdatesupport with gang scheduling. - Re-evaluate interaction between PDBs, voluntary eviction, and gang
disruptionMode. - Re-evaluate Deployment-side admission rejection of
spec.scheduling.resourceClaimswhenDRAWorkloadResourceClaimsis off (currently a silent semantic downgrade). - Align with Job by creating Basic Workload/PodGroup for all Deployments when the gate is
enabled, even without
spec.scheduling. Requires evaluating the PodGroup priority validation maximum, which is currently lower than system-level priority classes. - E2E test coverage for the full scenario matrix.
GA
TBD
Upgrade Strategy
With WorkloadWithDeployment disabled, new requests that set spec.scheduling are rejected, and
Deployments without scheduling configuration behave as they do today.
Disabling the gate after scheduling-enabled Deployments already exist does not remove their stored Workload, PodGroup, or pod references. As described in the OwnerReferences Relationship section, the Workload carries a controller ownerReference to the Deployment and each PodGroup carries a controller ownerReference to its ReplicaSet. Standard garbage collection therefore removes these objects when their owners are deleted; no controller-side cleanup is required while the gate is off. Existing pods retain the scheduling-group reference they were created with. Re-enabling the gate allows the controllers to resume normal scheduling-object reconciliation.
Mixed-pod caveat. Toggling the feature gate while a scheduling-enabled Deployment has running
pods produces a mixed state: some pods carry schedulingGroup and some do not. This is
problematic for:
- Gang scheduling: the PodGroup’s
minCountquorum counts only pods that reference it, so the quorum may become unsatisfiable. - Topology constraints: pods without
schedulingGroupare not bound to the PodGroup’s topology domain, so replicas may spread across domains instead of co-locating. - DRA ResourceClaims: pods without
schedulingGroupdo not reference the PodGroup’s shared claim and fall back to per-pod allocation.
Recovery requires administrator action: delete the inconsistent pods (or the entire ReplicaSet) so the controller recreates all pods consistently. This caveat applies to disabling, rolling back, and re-enabling the gate mid-lifecycle.
Version Skew Strategy
The feature requires GenericWorkload and the scheduling.k8s.io API versions to be active on
the API server. If the API server does not serve these resources, the controller’s create/patch
calls fail and the Deployment sync retries with backoff. No scheduling objects are compiled until
the API server is upgraded. Pods created without schedulingGroup schedule normally through the
default path.
Production Readiness Review Questionnaire
Feature Enablement and Rollback
How can this feature be enabled / disabled in a live cluster?
- Feature gate
- Feature gate name:
WorkloadWithDeployment - Components depending on the feature gate:
- kube-controller-manager
- kube-apiserver
- Feature gate name:
Does enabling the feature change any default behavior?
No. The feature is opt-in via spec.scheduling. Deployments without spec.scheduling are
unaffected. No scheduling objects are created unless the user explicitly sets the field.
Can the feature be disabled once it has been enabled (i.e. can we roll back the enablement)?
Yes. With the gate disabled on kube-apiserver, new requests that set spec.scheduling are
rejected. With the gate disabled on kube-controller-manager, the controllers stop reconciling
scheduling objects. Existing PodGroups remain until their owning ReplicaSet is garbage-collected.
The Workload remains until the Deployment is deleted. See the mixed-pod caveat in the Upgrade
Strategy section for the impact of disabling the gate while scheduling-enabled pods are running.
What happens if we reenable the feature if it was previously rolled back?
When the feature is re-enabled:
- Deployments with a stored
spec.schedulingvalue resume reconciliation on their next sync. - Existing Workload/PodGroup objects are discovered via deterministic naming and reused.
- If only a partial set exists (e.g., Workload but no PodGroup from a crash mid-creation), the controller completes the missing object on its next sync.
- If pods were created while the gate was disabled (without
schedulingGroup), the mixed-pod caveat described in the Upgrade Strategy section applies. The gang quorum may be unsatisfiable until the inconsistent pods are deleted and recreated.
Are there any tests for feature enablement/disablement?
Unit and integration tests for feature gate on/off behavior will be added as part of the Alpha implementation.
Rollout, Upgrade and Rollback Planning
How can a rollout or rollback fail? Can it impact already running workloads?
- If the API server doesn’t serve the Workload and PodGroup APIs, the Deployment and ReplicaSet controllers cannot persist scheduling objects and requeue with backoff until the APIs are available.
- Already running Deployments are not affected by enabling the feature; pods already scheduled continue to run.
- Disabling the gate does not remove existing Workloads, PodGroups, or pod references. Existing ReplicaSets continue running. See the mixed-pod caveat in the Upgrade Strategy section for the impact on gang quorum when the gate is toggled mid-lifecycle.
What specific metrics should inform a rollback?
deployment_sync_duration_seconds: significant increase may indicate issues with Workload/PodGroup creation.- Increased error rate in deployment-controller logs for
scheduling.k8s.ioAPI calls.
Were upgrade and rollback tested? Was the upgrade->downgrade->upgrade path tested?
This will be tested manually as part of alpha release.
Is the rollout accompanied by any deprecations and/or removals of features, APIs, fields of API types, flags, etc.?
No.
Monitoring Requirements
How can an operator determine if the feature is in use by workloads?
kubectl get workloads -Awill show Workload objects created by the Deployment controller.kubectl get podgroups -Awill show PodGroup objects created by the ReplicaSet controller for each active Deployment revision.
How can someone using this feature know that it is working for their instance?
- API .status
- Condition name:
Available=Falsewith reasonMinimumReplicasUnavailablewhen required replicas are unavailable;Progressing=Falsewith reasonProgressDeadlineExceededwhen placement does not make progress before the deadline.
- Condition name:
What are the reasonable SLOs (Service Level Objectives) for the enhancement?
TBD
What are the SLIs (Service Level Indicators) an operator can use to determine the health of the service?
TBD
Are there any missing metrics that would be useful to have to improve observability of this feature?
A dedicated metric for Workload/PodGroup creation latency per Deployment would be useful for Beta.
Dependencies
Does this feature depend on any specific services running in the cluster?
Yes. The scheduling.k8s.io API group must be served (requires GenericWorkload feature gate
enabled on the API server).
Scalability
Will enabling / using this feature result in any new API calls?
Yes. The controllers use Workload and PodGroup informers and listers for cached reads. API writes include:
- Creating one Workload for each scheduling-enabled Deployment.
- Patching the Deployment’s Workload when a positive replica count changes.
- Creating one PodGroup for each active ReplicaSet revision, or recreating it after scale-up from zero.
- Patching a ReplicaSet-owned PodGroup when its owner or runtime
minCountneeds reconciliation. - Deleting the PodGroup when its ReplicaSet reaches zero replicas.
Will enabling / using this feature result in introducing new API types?
No. Workload and PodGroup are introduced by KEP-6089 ; this KEP only creates instances.
Will enabling / using this feature result in any new calls to the cloud provider?
No.
Will enabling / using this feature result in increasing size or count of the existing API objects?
Yes. Each Deployment with spec.scheduling creates 1 Workload per Deployment (~500 bytes) and
1 PodGroup per ReplicaSet (~500 bytes), and each Pod gains a schedulingGroup field (~100 bytes).
Will enabling / using this feature result in increasing time taken by any operations covered by existing SLIs/SLOs?
Scheduling-enabled Deployments and ReplicaSets may incur additional reconciliation work while Workload and PodGroup objects are created or updated. Informer-backed reads limit the steady-state overhead, while ordinary Deployments and ReplicaSets are unaffected. The impact should be measured during Alpha.
Will enabling / using this feature result in non-negligible increase of resource usage (CPU, RAM, disk, IO, …) in any components?
The feature is opt-in in Alpha, so the additional overhead is limited to scheduling-enabled Deployments. Each such Deployment adds one long-lived Workload, one PodGroup for each active ReplicaSet revision, informer cache entries for Workloads and PodGroups, and reconciliation work in both controllers.
Can enabling / using this feature result in resource exhaustion of some node resources (PIDs, sockets, inodes, etc.)?
No. This feature is purely control-plane and does not affect node resources.
Troubleshooting
How does this feature react if the API server and/or etcd is unavailable?
- Deployment and ReplicaSet controllers cannot create Workloads or PodGroups.
- Retries with exponential backoff when kube-apiserver recovers.
- Existing Deployments with scheduling objects continue to run.
What are other known failure modes?
- Gang cannot place due to insufficient cluster resources: Deployment reports
Available=False/ProgressDeadlineExceeded. No automatic recovery.
What steps should be taken if SLOs are not being met to determine the problem?
- Verify
WorkloadWithDeploymentandGenericWorkloadare enabled on all control plane components. - Check controller-manager logs for errors related to Workload/PodGroup creation.
- Check resource constraints since gang scheduling may fail if the cluster doesn’t have sufficient resources.
Implementation History
- 2026-08: KEP created for Alpha targeting v1.38.
Future Work
The following items are out of scope for Alpha but are expected to be addressed in Beta or later releases.
Elastic Gang Semantics
When minCount < replicas, the gang is satisfiable with fewer pods than the full replica count,
but each ReplicaSet currently has a single PodGroup. Supporting multiple PodGroups per ReplicaSet
(elastic gang) would allow the scheduler to place subsets of replicas independently, improving
utilization on fragmented clusters. This requires either:
- Multiple PodGroupTemplates in the Workload, with the ReplicaSet controller splitting pods across multiple PodGroups (one per template), or
- CompositePodGroup to coordinate multiple child PodGroups within a single ReplicaSet under a shared scheduling context.
CompositePodGroup
Multi-level or nested composite structures (CompositePodGroup) are a Non-Goal for this KEP,
which covers single-level Deployment/ReplicaSet workloads with one PodGroup per ReplicaSet.
However, future use cases such as disaggregated prefill/decode pipelines, where each stage
forms its own gang, may require coordinating multiple PodGroups within a Deployment. Based on
conversations in the Job Beta promotion ([kubernetes/enhancements#6345]), supporting multiple
PodGroups per workload will likely require either CompositePodGroup or BYO Workload with
downward annotations. If CompositePodGroup support is needed for Deployments, it would be
proposed as a separate KEP dependent on the CompositePodGroup API graduating in the
scheduling.k8s.io API group.
BYO Workload and PodGroup
Following the pattern established in the Job integration (KEP-5547
), a higher-level controller
or user may pre-create a Workload or PodGroup and expect the Deployment or ReplicaSet
controller to discover and use it rather than creating its own. For example:
- BYO Workload: A parent controller pre-creates a
Workloadwhosespec.controllerRefpoints to the Deployment. The Deployment controller discovers it and skips creating its own. The parent propagates thescheduling.k8s.io/group-template-namedownward annotation (KEP-6089 ) onto the ReplicaSet so the ReplicaSet controller knows which PodGroupTemplate to materialize PodGroups from. - BYO PodGroup: The user manages the PodGroup directly and wires pods to it via
pod.spec.schedulingGroup.podGroupNamein the pod template. The controllers do not create or own the PodGroup.
In both cases the controllers treat the discovered object as the source of truth, do not take ownership, and do not mutate or delete it, matching the Job controller’s behavior.
For Alpha, the Deployment and ReplicaSet controllers only use objects they create and own. BYO discovery and delegation semantics would be designed in coordination with the Job controller’s BYO implementation to ensure a consistent pattern across workload types.
Drawbacks
Recreatestrategy terminates all old pods before creating new ones, causing downtime during rollouts.Permanent topology-domain binding can strand replacement pods in Pending with no automatic recovery. The in-tree remedy is triggering a new rollout revision.
Post-bind runtime failures (e.g., bad image) retain node capacity while individual pods crash; the gang holds its reservations even though no useful work is happening.
With
Recreatestrategy, template-backed ResourceClaims are released when the old ReplicaSet reaches zero and its PodGroup is deleted.revisionHistoryLimitdoes not retain the claim.Named ResourceClaims pin all revisions to one node, risking deadlock when node capacity is tight during rollouts.
Alternatives
Delete the Workload when replicas reach zero. Instead of retaining the Deployment-owned
Workload at zero replicas (with the user’s explicit minCount or a default of 1), the controller
would delete the Workload and recreate it when the Deployment scales positive again.
Advantages: No Workload exists while the Deployment has zero replicas. The Workload and its PodGroupTemplate are recreated from the current Deployment configuration on scale-up.
Tradeoffs: Deleting and recreating the Workload adds API operations and creates another
scale-to-zero/scale-up lifecycle transition. The current design retains one stable
Deployment-owned Workload and deletes only the ReplicaSet-owned runtime PodGroup, avoiding
Workload churn while the retained minCount has no runtime effect at zero replicas.
One PodGroup per Deployment. Rejected: topology binding is permanent per PodGroup, so a stuck gang cannot re-place in a different domain without a new revision. Additionally, old and new rollout gangs would collide within a single PodGroup.
User-managed PodGroups (status quo). Rejected: fragile ordering (pods created before PodGroup hang silently), no garbage collection, and no integration with scaling or rolling updates.
Controller-derived minCount only (no user override). The controller always sets
minCount = replicas and rejects user-provided values. This was the original Alpha design.
It was changed to allow user-set minCount (validated to not exceed replicas) based on
feedback that tying minCount to replicas is too restrictive for workloads that can
tolerate partial placement.
Deployment controller creates PodGroups. The Deployment controller would create both the Deployment-owned Workload and each revision’s PodGroup, then the ReplicaSet controller would only create pods.
Advantages: The ReplicaSet controller remains unaware of Workload and PodGroup APIs, requiring no additional scheduling informers or RBAC permissions. Scheduling-object creation stays centralized in the Deployment controller.
Tradeoffs: The Deployment controller must create a PodGroup before the ReplicaSet has a UID, so the PodGroup requires temporary Deployment ownership and later ownership transfer. This adds an ownership-transfer step and requires recovery if that transfer is interrupted. It also couples Deployment reconciliation to revision-specific PodGroup lifecycle.