KEP-5941: DRA Shared Consumable Capacity
KEP-5941: DRA Shared Consumable Capacities Across Related Devices
- Release Signoff Checklist
- Summary
- Motivation
- Proposal
- Design Details
- Production Readiness Review Questionnaire
- Implementation History
- Drawbacks
- Alternatives
- Infrastructure Needed (Optional)
Release Signoff Checklist
- (R) Enhancement issue in release milestone, which links to KEP dir in kubernetes/enhancements (not the initial KEP PR)
- (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, such as design docs, SIG meeting notes, relevant PRs/issues, release notes
Summary
Dynamic Resource Allocation (DRA) currently supports:
- parent-scoped shared integer counters via partitionable devices, and
- per-device request-driven consumable capacity via
allowMultipleAllocations.
However, there is no upstream mechanism that combines both capabilities so that:
- multiple related devices can consume from one shared parent-scoped capacity pool, and
- the consumed amount is determined by the request at allocation time.
This KEP proposes extending the existing DRA sharedCounters with requestPolicy support and adding a valueFrom mapping in consumesCounters, so that multiple related devices can consume request-driven amounts from shared counter sets during allocation, with scheduler accounting that prevents aggregate over-allocation.
The proposal is generic and applies to multiple hardware models. SR-IOV VF bandwidth accounting is one motivating use case, but not the only target.
Motivation
Some resources are naturally parent-scoped and shared across multiple allocatable child devices. Examples include link bandwidth, shared memory channels, or scheduler-governed throughput budgets.
In these cases, publishing only child devices is desirable for user experience and hardware mapping, but scheduler-side accounting must still guard the aggregate shared parent budget.
Existing DRA capabilities leave a gap:
- Partitionable counters are shared across devices, but consumption is static in
ResourceSlicedata. - Consumable capacity is request-driven, but accounting is device-local.
This causes either over-advertisement, rigid static partitioning, or custom out-of-band admission behavior, all of which reduce correctness and portability.
Goals
- Introduce a generic DRA model for parent-scoped shared capacities consumed by related child devices.
- Keep request-driven consumption semantics aligned with consumable capacity (
capacity.requests+ request policy). - Ensure scheduler allocator prevents aggregate over-allocation for each shared capacity set.
- Preserve compatibility with existing DRA features and patterns where possible.
Non-Goals
- Defining device- or vendor-specific runtime enforcement mechanisms (for example, tc, firmware limits, NIC policy engines).
- Defining standard capacity names across vendors.
- Solving cross-node or cross-pool global capacity aggregation.
- Replacing existing partitionable counters or consumable capacity; this extends existing API types.
Proposal
Extend the existing sharedCounters in ResourceSlice with requestPolicy support, and add a valueFrom mapping to consumesCounters so that devices can map inbound capacity requests to shared counters. Reuse existing ResourceClaim request syntax for capacity requests, with scheduler accounting performed against referenced shared counter sets.
At a high level:
- A driver publishes
sharedCounterswithSharedCounterentries that may includerequestPolicy(default, valid range,validValues). - Each allocatable device references the shared counter set(s) it draws from via
consumesCounters, usingvalueFrom.capacityNameto map capacity request keys to counters. - A claim requests capacity using existing
capacity.requestsfields. - During allocation, the scheduler resolves the
valueFrommappings, checks and consumes the requested amount from all relevant counter sets (device-specific staticvalueand/or sharedvalueFrom), rejecting candidates that would exceed any counter limit, and persists the resolved amounts inconsumedCounterson the claim allocation result.
User Stories
Story 1: Virtual network interface bandwidth as a shared parent resource
As a cluster user, I request one or more virtual network interfaces (e.g. SR-IOV VFs) and a bandwidth amount per request. As an operator, I want scheduler admission to ensure that total bandwidth promised across virtual interfaces on the same physical function does not exceed its capacity.
This allows:
- keeping the virtual interface as the allocatable unit, and
- preventing over-allocation of physical link bandwidth without static pre-partitioning.
Story 2: CPU/Memory resource alignment via PCIE root grouping
Co-locating compute resources (cores, devices, memory) is essential for low-latency workloads, and there is work to allocate CPU and memory resources using DRA drivers. There is a growing consensus that NUMA or Socket IDs do not correctly represent modern CPU hardware; the community is shifting towards using PCIE roots as the alignment attribute. This is demonstrated by the fact that pcieRoot was the first DRA standard attribute. In modern CPUs, more than one PCIE root can be attached to the same NUMA zone, which further reinforces the case for using PCIE roots as the alignment mechanism.
Therefore, a non-directly-accessible (parent) set of resources (a CPUSet and a NUMA node) is shared across accessible (child) devices, represented by PCIE roots.
Example from real hardware (dual XEON Gold 6320R):
"root"="pci0000:00" "localCPUs"="0,2,4,...,102" "NUMANode"=0
"root"="pci0000:17" "localCPUs"="0,2,4,...,102" "NUMANode"=0
"root"="pci0000:3a" "localCPUs"="0,2,4,...,102" "NUMANode"=0
"root"="pci0000:85" "localCPUs"="1,3,5,...,103" "NUMANode"=1
"root"="pci0000:ae" "localCPUs"="1,3,5,...,103" "NUMANode"=1
"root"="pci0000:d7" "localCPUs"="1,3,5,...,103" "NUMANode"=1
A CPU/memory DRA driver can publish one shared capacity set per physical CPU package (the parent budget of available CPUs and memory) and map each PCIE root device to the appropriate set. Scheduler accounting then prevents aggregate over-allocation of CPUs or memory across PCIE roots within the same physical package.
See also: kubernetes/enhancements#5491 for related work on PCIE-root-based resource alignment.
Notes/Constraints/Caveats
- This proposal adds API and allocator behavior and therefore requires cross-SIG review (at minimum SIG Scheduling and SIG API Machinery).
- Request policy semantics should stay as close as possible to existing consumable-capacity behavior to reduce user surprise.
- Drivers must publish consistent relationships between devices and shared counter sets; invalid
valueFromreferences must be rejected or treated as unsatisfiable.
Risks and Mitigations
Risk: scheduler overhead increases with extra accounting.
Mitigation: follow existing allocator cache/aggregation patterns used by DRA allocation logic and add perf coverage.Risk: API complexity for users and driver authors.
Mitigation: keep user request syntax unchanged (capacity.requests) and keep shared-set definitions driver-facing.Risk: invalid or inconsistent pool references.
Mitigation: API validation plus allocator safeguards that reject incomplete or invalid candidate mappings.
Design Details
API additions
This KEP extends existing DRA types. sharedCounters and consumesCounters are already beta (+k8s:beta(since: "1.37")) behind DRAPartitionableDevices. The previous shared Counter type is split so definition and consumption no longer share one struct:
SharedCounter(used inCounterSet.counters/sharedCounters): keeps requiredvalueand gains an optionalrequestPolicy.requestPolicyreuses the existingCapacityRequestPolicytype from consumable capacity (default,validRange,validValues). IfrequestPolicyis unset, avalueFrommapping consumes the requested amount as-is, or the full countervaluewhen the claim omits that capacity key.ConsumeCounter(used inDeviceCounterConsumption.counters/consumesCounters):valuebecomes optional. Exactly one ofvalue(static consumption, existing behavior) orvalueFrom(request-driven consumption) must be set. Existing objects that setvaluecontinue to work unchanged.CounterValueFrom:valueFrom.capacityNameis the device capacity name that users set incapacity.requests. IfcapacityNamehas no domain prefix, the ResourceSlicedrivername is used as the domain when matching claim requests.DeviceRequestAllocationResult.consumedCounters: a persisted snapshot of the resolved consumption per counter set (CounterSetConsumption:counterSetpluscountersquantity map). Maximum two counter sets, matching the existing per-deviceconsumesCounterslimit. Gated byDRASharedConsumableCapacity.
The JSON/YAML field names on ResourceSlice objects stay compatible: existing value-only consumesCounters entries remain valid. The Go type rename (Counter → SharedCounter / ConsumeCounter) is an API-package change, not a wire-format break.
Example ResourceSlice with shared counter request policy:
apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
name: counter-slice
spec:
driver: "resource-driver.example.com"
pool:
generation: 1
name: "my-pool"
resourceSliceCount: 2
sharedCounters:
- name: pf-0-counter-set
counters:
bandwidth:
value: "100G"
requestPolicy:
default: "1G"
validRange:
min: "1M"
max: "100G"
step: "1M"
Example ResourceSlice with device valueFrom mapping:
apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
name: device-slice
spec:
driver: "resource-driver.example.com"
pool:
generation: 1
name: "my-pool"
resourceSliceCount: 2
nodeName: "my-node"
devices:
- name: vf-0
consumesCounters:
- counterSet: pf-0-counter-set
counters:
bandwidth:
valueFrom:
capacityName: "resource-driver.example.com/bandwidth"
- name: vf-1
consumesCounters:
- counterSet: pf-0-counter-set
counters:
bandwidth:
valueFrom:
capacityName: "resource-driver.example.com/bandwidth"
Example ResourceClaim requesting bandwidth from one of the VFs above:
apiVersion: resource.k8s.io/v1
kind: ResourceClaim
metadata:
name: my-vf-claim
spec:
devices:
requests:
- name: vf-request
exactly:
deviceClassName: sriov-vfs
capacity:
requests:
resource-driver.example.com/bandwidth: "10G"
Example allocation result snapshot after that claim is bound:
status:
allocation:
devices:
results:
- request: vf-request
driver: resource-driver.example.com
pool: my-pool
device: vf-0
consumedCounters:
- counterSet: pf-0-counter-set
counters:
bandwidth: "10G"
The capacity.requests key resource-driver.example.com/bandwidth matches the capacityName declared in the device’s consumesCounters[].counters[].valueFrom. When the scheduler allocates vf-0 or vf-1 for this claim, it resolves that mapping and subtracts 10G from the shared pf-0-counter-set bandwidth counter (100G total), subject to the requestPolicy defined on the counter set. The resolved 10G is written to status.allocation.devices.results[].consumedCounters.
Key points:
- ResourceSlice objects that already use static
valueinconsumesCountersremain valid. requestPolicyon aSharedCounterdefines how request values are validated and defaulted. It is optional.valueFrom.capacityNameon aConsumeCountermaps acapacity.requestskey to the counter, making consumption request-driven rather than static.- Making
valueFroma struct allows future extensions (e.g. multipliers or transformations) without further API changes. - Claims continue to use existing
capacity.requestsfields. - Mixed static and request-driven consumption is supported across devices that share a counter set (one device may use
value, anothervalueFromon the same counter). A singleConsumeCounterentry cannot set both.
Allocation behavior
For each candidate device allocation:
- Resolve all
valueFrommappings on the candidate device’sconsumesCountersto determine which capacity request keys feed into which shared counters (capacityNamematching, including driver-domain defaulting). - For each resolved counter, apply the counter’s
requestPolicy(if set) to compute the consumed amount (defaulting/rounding/range/validValuesrules). If the claim omits the capacity key, userequestPolicy.defaultwhen present, otherwise the full shared countervalue. - Include static
valueconsumption from the same device when checking remaining budget. - Reject the candidate if any counter set would exceed available capacity, or if
requestPolicyis violated. - Tentatively account consumption during in-progress claim allocation to avoid internal over-commit.
- Persist the resolved amounts on
DeviceRequestAllocationResult.consumedCounters.
This behavior allows one shared counter set to mix:
- device-specific static counter consumption (existing
valuepath on some devices), and - parent aggregate limits via request-driven
valueFromon other devices.
Allocation status snapshot
When DRASharedConsumableCapacity is enabled, the scheduler does not recompute already-allocated consumption from live ResourceSlice consumesCounters / requestPolicy definitions. It subtracts status.allocation.devices.results[].consumedCounters for allocated claims in the same pool.
That makes accounting independent of later driver updates to valueFrom, requestPolicy, or counter-set membership. Without the snapshot, a ResourceSlice republish could change how much an already-running allocation is charged, causing false exhaustion or over-commit after a scheduler restart.
The DynamicResources plugin therefore includes allocated ResourceClaims (not only allocated device IDs) in the allocated-state gather path when the gate is on.
Feature gate
Feature gate name:
DRASharedConsumableCapacity
Dependencies (must also be enabled):
DynamicResourceAllocationDRAPartitionableDevicesDRAConsumableCapacity
Components:
- kube-apiserver (field enablement/validation for
requestPolicy,valueFrom, andconsumedCounters) - kube-scheduler (allocator accounting and snapshot gather)
Test Plan
[ ] I understand the owners of the involved components may require updates to existing tests to make this code solid enough prior to committing the changes necessary to implement this enhancement.
Prerequisite testing updates
- Extend or add allocator-focused test fixtures for DRA counter accounting with mixed static and
valueFrom-driven consumption.
Unit tests
API validation:
- valid/invalid
requestPolicyonSharedCounterdefinitions - valid/invalid
valueFromreferences inConsumeCounter(exactly one ofvalueorvalueFrom; requiredcapacityName) - feature-gate drop of
requestPolicy,valueFrom, andconsumedCounterswhen the gate is off
- valid/invalid
Scheduler allocator:
- aggregate accounting across multiple claims using
consumedCounterssnapshots - candidate rejection when a shared counter set would be exceeded
requestPolicyhandling (default/range/step/validValues)- mixed accounting when some devices use static
valueand others usevalueFromon the same counter set
- aggregate accounting across multiple claims using
k8s.io/dynamic-resource-allocation/structured/internal/experimental: 2026-07-21 - allocator tests forvalueFromresolution, snapshot accounting, mixed static/request-driven consumptionk8s.io/kubernetes/pkg/apis/resource/validation: 2026-07-21 - ResourceSlice and ResourceClaim validation forrequestPolicy,valueFrom, andconsumedCountersk8s.io/kubernetes/pkg/registry/resource/resourceslice: 2026-07-21 - strategy tests for gated field dropk8s.io/kubernetes/pkg/scheduler/framework/plugins/dynamicresources: 2026-07-21 - plugin tests withDRASharedConsumableCapacityenabled
Integration tests
test/integration/dra/shared_consumable_capacity.go: scheduler allocation withrequestPolicyandvalueFromunder feature gate on/off.- Gate off:
valueFromis dropped and devices remain allocatable (treated as zero static consumption). - Gate on: two claims that fit a shared budget of 2 succeed; a third remains pending; releasing the first claim allows the third to schedule.
e2e tests
test/e2e/dra/dra.go(sharedConsumableCapacityTests), withDRAConsumableCapacity,DRAPartitionableDevices, andDRASharedConsumableCapacityenabled:- two child devices map
valueFromto one shared counter set; aggregate requests that exceed the set stay pending; release restores schedulability - mixed static
valueand request-drivenvalueFromdevices sharing one counter set
- two child devices map
Graduation Criteria
Alpha
- Feature implemented behind
DRASharedConsumableCapacity - Core unit and integration tests in place
- Initial e2e signal for shared counter accounting correctness
Beta
- API shape and policy semantics settled
- Stable periodic tests and no unresolved critical correctness bugs
- Monitoring and troubleshooting guidance documented
- Rollout and rollback behavior validated
- scheduler_perf tests covering overhead of shared counter accounting
GA
- Sustained test stability across at least two releases after beta
- No unresolved major correctness regressions
- User docs complete and maintained
Upgrade / Downgrade Strategy
Recommended Rollout
Three components are involved: the kube-apiserver, the kube-scheduler, and the DRA driver that publishes ResourceSlices.
The recommended enablement / upgrade sequence:
Enable the gate (
DRASharedConsumableCapacity) on kube-apiserver and kube-scheduler. Until any driver publishesrequestPolicyorvalueFromfields, this is a no-op for scheduling.Update the DRA driver to publish
requestPolicyon shared counters andvalueFrominconsumesCounters. From this point on, the scheduler enforces shared counter accounting for devices usingvalueFrom.
Why this order: when the gate is OFF on the apiserver, requestPolicy, valueFrom, and consumedCounters are stripped from writes to objects that did not already store them (standard gated-field in-use preservation). A driver that publishes requestPolicy/valueFrom before the gate is enabled will see them silently dropped; enabling the gate later does not retroactively restore them, and the driver must republish. Allocations created while the gate was off have no consumedCounters snapshot; after enablement those allocations do not charge shared counters until they are recreated.
Recommended downgrade / disablement order: reverse of upgrade — update the DRA driver first (remove the new fields), then disable the gate on scheduler and apiserver.
Version Skew Strategy
- kube-apiserver: Must be upgraded first to accept
requestPolicyonSharedCounter,valueFromonConsumeCounter, andconsumedCounterson allocation results. - kube-scheduler:
- A scheduler that understands this feature resolves
valueFrommappings, enforcesrequestPolicy, writesconsumedCounters, and uses those snapshots for later accounting. - An older scheduler ignores
requestPolicy,valueFrom, andconsumedCounters. Devices withvalueFrom(no staticvalue) are treated as consuming zero from the shared counter set, so placement may be overly permissive until the scheduler is upgraded.
- A scheduler that understands this feature resolves
- kubelet: No changes required; kubelet does not interpret
requestPolicy,valueFrom, orconsumedCounters. - DRA driver:
- Drivers publish ResourceSlices with
requestPolicyon shared counters andvalueFrominconsumesCounters. - A driver that publishes the new fields before the apiserver gate is enabled will see them silently dropped at write time.
- Drivers publish ResourceSlices with
During version skew, the main risk is overly permissive scheduling by an older scheduler that does not enforce shared counter budgets. This is operationally acceptable as a transient state during rolling upgrade, similar to other DRA features.
Production Readiness Review Questionnaire
Feature Enablement and Rollback
How can this feature be enabled / disabled in a live cluster?
- Feature gate
- Feature gate name:
DRASharedConsumableCapacity - Components depending on the feature gate: kube-apiserver, kube-scheduler
- Also requires:
DynamicResourceAllocation,DRAPartitionableDevices,DRAConsumableCapacity
- Feature gate name:
- Other
Does enabling the feature change any default behavior?
Only for workloads and resources that use the new fields and request patterns. Existing DRA objects without the new fields behave as before.
Can the feature be disabled once it has been enabled (i.e. can we roll back the enablement)?
Yes, by disabling DRASharedConsumableCapacity and restarting kube-apiserver and kube-scheduler. Gated fields (requestPolicy, valueFrom, consumedCounters) are dropped on writes to objects that did not already store them. Objects that already had those fields keep them (standard API in-use preservation). Already running pods keep their devices.
New allocations do not write consumedCounters. Request-driven shared-counter accounting is skipped. Devices with only valueFrom (no static value) are treated as consuming zero from the shared counter set.
What happens if we reenable the feature if it was previously rolled back?
Request-driven accounting resumes for new allocations after kube-apiserver and kube-scheduler restart with the gate on, and after the DRA driver is publishing requestPolicy / valueFrom again. Enabling the gate does not retroactively restore fields that were stripped from objects written while the gate was off; the driver must republish those ResourceSlices.
Yes, accounting can be wrong for the disable window. The scheduler only subtracts status.allocation.devices.results[].consumedCounters; it does not reconstruct consumption from live ResourceSlices.
- Claims allocated while the feature was on keep charging the shared counters if their snapshot is still present.
- Claims allocated while the feature was off have no snapshot, so after re-enablement they consume zero from request-driven shared counters until the claim is recreated. That under-counts usage and can over-allocate the parent shared capacity.
Admin recovery:
- Confirm the driver has republished ResourceSlices with
requestPolicyandvalueFrom. - Find allocated claims whose devices use
valueFrombutconsumedCountersis empty. - Recreate those ResourceClaims (restart or replace the owning pods) so they are allocated again with a snapshot. There is no in-place backfill.
- Until that churn finishes, treat the shared parent budget as potentially over-committed.
Already running pods keep their devices; only later scheduling is affected until those claims turn over.
Are there any tests for feature enablement/disablement?
Yes. Integration tests cover scheduler allocation with the gate on and off (test/integration/dra/shared_consumable_capacity.go). Unit tests cover validation and strategy drop of gated fields, plus allocator snapshot accounting.
Rollout, Upgrade and Rollback Planning
How can a rollout or rollback fail? Can it impact already running workloads?
- Incorrect accounting logic could cause false negatives (pending claims) or false positives (over-allocation).
- Already running workloads should remain running; primary impact is on new allocations.
- Re-enabling after allocations were made while the gate was off under-counts those claims until they are recreated (see Feature Enablement and Rollback).
What specific metrics should inform a rollback?
scheduler_unschedulable_pods{plugin="DynamicResources"}— increased allocation failure rate attributable to shared counter checksscheduler_plugin_execution_duration_seconds{plugin="DynamicResources"}— scheduler allocation latency regression- Unexpected pending claims for requests that should fit (observable via
apiserver_request{resource="resourceclaims"})
Were upgrade and rollback tested? Was the upgrade->downgrade->upgrade path tested?
Planned for beta milestone via integration and e2e coverage.
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?
- API inspection of
ResourceSliceobjects containingsharedCounterswithrequestPolicyand devices withvalueFrominconsumesCounters. - API inspection of
ResourceClaim.status.allocation.devices.results[].consumedCountersfor resolved shared-counter consumption.
How can someone using this feature know that it is working for their instance?
- API .status
- Other field:
ResourceClaim.status.allocation.devices.results[].consumedCountersrecords the resolved shared-counter consumption snapshot used for later accounting
- Other field:
- Events
- Event Reason:
- Other
What are the reasonable SLOs (Service Level Objectives) for the enhancement?
- No material regression to scheduler allocation success latency at supported scale.
- No correctness regressions leading to persistent over-allocation or systematic false rejection under normal operation.
What are the SLIs (Service Level Indicators) an operator can use to determine the health of the service?
- Metrics
- Metric names:
scheduler_unschedulable_podswithplugin="DynamicResources"scheduler_plugin_execution_duration_secondswithplugin="DynamicResources"apiserver_requestwithresource="resourceclaims"
- Components exposing the metric: kube-apiserver, kube-scheduler
- Metric names:
- Other
- Details:
Are there any missing metrics that would be useful to have to improve observability of this feature?
No. Shared counter consumption visibility is not covered by existing metrics. Per-counter utilization metrics would be too granular and high-cardinality for the scheduler. Pool-level resource availability visibility is tracked by KEP-5677, which could be extended in the future to include shared counter consumption data.
Dependencies
Does this feature depend on any specific services running in the cluster?
No new mandatory external services. Behavior depends on DRA-capable control-plane components and compliant DRA drivers publishing valid resource data.
Scalability
Will enabling / using this feature result in any new API calls?
No fundamentally new call types are expected. It may increase processing per allocation decision due to additional accounting checks.
Will enabling / using this feature result in introducing new API types?
No new top-level API types are expected. This proposal splits the previous Counter type into SharedCounter and ConsumeCounter, adds CounterValueFrom, and adds CounterSetConsumption on allocation results.
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. ResourceSlice size may increase slightly due to requestPolicy on shared counters and valueFrom on device counter consumption entries. ResourceClaim status size increases by consumedCounters on each allocated device result (at most two counter sets per result).
Will enabling / using this feature result in increasing time taken by any operations covered by existing SLIs/SLOs?
Possibly scheduler allocation path latency for DRA-using workloads; this must be measured with integration/perf tests.
Will enabling / using this feature result in non-negligible increase of resource usage (CPU, RAM, disk, IO, …) in any components?
Potentially increased scheduler CPU and memory in clusters with many valueFrom-driven shared counter allocations. Bounds and acceptable overhead to be validated before beta.
Can enabling / using this feature result in resource exhaustion of some node resources (PIDs, sockets, inodes, etc.)?
No direct node resource exhaustion risk is expected from this control-plane feature.
Troubleshooting
How does this feature react if the API server and/or etcd is unavailable?
Like other scheduler features, new allocations cannot be completed while required API state is unavailable.
What are other known failure modes?
Invalid driver-published
valueFromor counter references- Detection: allocation failures with clear reason, validation errors where possible
- Mitigations: fix driver publication; reject invalid objects early
- Diagnostics: scheduler and apiserver logs/events
- Testing: unit/integration coverage
requestPolicymismatch causing unexpected rounding/default behavior- Detection: discrepancy between requested amount and
consumedCounterssnapshot - Mitigations: adjust
requestPolicydefinitions and documentation - Diagnostics: allocation result inspection, scheduler logs/events
- Testing: unit tests for policy resolution and arithmetic
- Detection: discrepancy between requested amount and
Re-enable after rollback under-counts disable-window allocations
- Detection: allocated claims whose devices use
valueFrombutstatus.allocation.devices.results[].consumedCountersis empty - Mitigations: republish ResourceSlices with the gated fields; recreate those ResourceClaims (restart or replace owning pods). There is no in-place backfill
- Diagnostics: ResourceClaim allocation status inspection
- Testing: integration coverage of gate on/off allocation; recreate-to-restore-snapshot path planned for beta rollback testing
- Detection: allocated claims whose devices use
What steps should be taken if SLOs are not being met to determine the problem?
- Compare allocation latency/error rates before and after enablement.
- Inspect pending claims and failure reasons tied to shared capacity checks.
- Disable feature gate as rollback if correctness or latency regression is severe.
Implementation History
- 2026-03-03: Initial draft created in local design docs, generalized from SR-IOV-specific proposal.
- 2026-07-21: Alpha implementation: split
CounterintoSharedCounter/ConsumeCounter, persistconsumedCounterson ResourceClaim allocation status, add unit/integration/e2e coverage. - 2026-09-22: Retarget alpha to Kubernetes v1.38.
- 2026-09-28: Expand disable/re-enable accounting and admin recovery in the production readiness review.
Drawbacks
- Adds scheduler complexity for
valueFromresolution,requestPolicyenforcement, and snapshot-based accounting. - Splits the previous
Countertype intoSharedCounterandConsumeCountersorequestPolicyandvalueFromare not mixed on one struct. - Requires careful
requestPolicysemantics when devices using staticvalueand devices usingvalueFromshare one counter set.
Alternatives
- Introduce a new
sharedCapacitiestop-level concept. An earlier version of this KEP proposed a separatesharedCapacitiesfield inResourceSlicewith its own capacity sets and device references. This was rejected in favor of extending the existingsharedCountersandconsumesCountersAPI, which avoids introducing a new concept and keeps the API surface smaller. - Static parent capacity partitioning into child-specific fixed slices. Simple but inflexible; cannot adapt to varying per-request consumption patterns.
- Model parent capacity as a separate allocatable device and require multi-request claims tied by constraints. Works today, but increases user complexity significantly.
- Continue with device-local consumable capacity only. Cannot model cross-device parent-scoped budgets correctly.
- Promote shared counters to the scheduler framework level for cross-plugin use. This would allow shared capacity accounting across different scheduler plugins (e.g. DRA and ResourceFit, see #5517). Feasible but requires solving single-owner population semantics and is a larger scope change. This KEP focuses on the DRA-specific mechanism; framework-level promotion could be a future evolution built on top of this work.
Infrastructure Needed (Optional)
None currently.