Skip to content

    Back to articles

    6 min read

    Treat optional device operations as a workload contract

    Skipping a call is not a workload guarantee

    A device that needs no node-local preparation may sound like a simpler device. But “the kubelet can skip a driver call” and “the workload can safely use this device” are different statements. The first is an operational fact about the device driver; the second is a contract the platform and workload must agree on.

    The Kubernetes documentation on optional node operations describes a driver declaring that particular node-local operations can be skipped. The kubelet can then bypass driver lookup and gRPC calls for those devices. The operations in question are NodePrepareResources, called before a container starts, and NodeUnprepareResources, called when a Pod terminates. That declaration is about what Kubernetes needs to ask the node-local driver to do. It does not, by itself, describe the application’s device requirements or promise that every allocated device behaves identically.

    I would therefore treat optional operations as a boundary in the workload contract, not as a workload feature toggle. A workload should state what it needs from a device: for example, whether the device must be available to the container, whether some initialization must have happened before use, and whether cleanup must happen before the resource is reused. The platform then maps those needs onto devices and their supported operations. If a device has no node-local preparation, that may satisfy the contract. If setup is performed elsewhere, the platform must make that responsibility explicit rather than silently assuming the kubelet handled it.

    This distinction matters because “optional” is not the same as “unimportant.” Skipping a call is safe only when the omitted work is unnecessary or is reliably done by another part of the system. That is my design rule, not a Kubernetes guarantee.

    Declare capabilities, not implementation trivia

    I would keep the workload-facing contract focused on outcomes. A workload generally should not need to know whether a driver implements a gRPC method, whether a node-local plugin is installed, or which component performs a particular setup step. Those details belong to the platform’s device integration. The workload needs to know whether the device meets its requirements and what fallback is acceptable.

    For example, a workload might make its policy explicit in application configuration:

    # Illustrative application-level policy, not a Kubernetes API field.
    devicePolicy:
      acceleration: preferred
      initialization: required-before-use
      fallback: cpu

    The values here are an example of the kind of contract I mean, not Kubernetes schema. preferred says that acceleration is useful but not essential; required-before-use says the application must not consume the device before its initialization condition is met; cpu states what the application can do if suitable acceleration is unavailable. A workload that cannot run correctly without the device would express a different policy and should not quietly fall back.

    The platform has a separate job: it must map the workload’s declared needs to resources that can meet them. A device declaration that skips NodePrepareResources cannot be treated as evidence that the workload’s initialization requirement is satisfied unless the platform knows that no such preparation is needed, or can identify the other component responsible for it. Likewise, the application’s willingness to fall back does not mean the scheduler or allocator will automatically provide a CPU-only path. That fallback has to exist in the workload design and deployment configuration.

    This separation gives both sides a useful boundary. The workload describes what it can safely assume; the platform describes which devices satisfy those assumptions and who owns any work outside the kubelet’s node operations. When those statements cannot be matched, I would rather reject or visibly degrade the deployment than let a Pod start with a false promise.

    Handle differences at deployment time

    Optional operations make it easier for a platform to support devices that do not need a node-local driver for every operation. The Kubernetes DRA feature documentation also warns that changing a driver’s node-operation requirements in place does not change the configuration used by existing claims. It recommends ensuring that no active claims exist for the driver before changing those requirements or removing node-local driver DaemonSets. That is a reminder that a declaration change is not merely a cleanup of deployment YAML: existing allocations may still rely on the old contract.

    I would handle a change in three stages. First, inventory the workload assumptions: which device capabilities are required, which operations are currently expected, and whether any setup or cleanup happens outside the driver. Second, make the new declaration available without removing the old path, and test workloads against both kinds of node. Third, move claims and workloads deliberately, then remove obsolete node-local components only after the platform has established that no remaining allocation depends on them. The exact rollout mechanism belongs to the cluster; the invariant is that a live claim must not be stranded between two versions of the contract.

    For deployments, I would expose the difference as a capability or placement constraint, not as a hidden node implementation detail. If a workload requires a device with a particular setup guarantee, the deployment should select only resources for which the platform can make that guarantee. If the workload can operate without the device, the deployment should say what fallback it supports and make that fallback observable to operators. A Pod being scheduled is not proof that an application-level requirement has been met.

    Make the contract reviewable

    KEP 5945 tracks DRA Optional Node Operations, with Beta targeted for Kubernetes v1.38. Kubernetes development coverage reports that the Beta update targets v1.38 with the feature gate on by default. That makes this a timely prompt to review assumptions, but the release milestone does not change the contract principle: the platform must not confuse an optional node operation with an optional workload requirement.

    I would put the contract where both workload and platform changes can be reviewed together: document the device capabilities the workload consumes, the conditions under which it can run without them, and the owner of any setup or cleanup that Kubernetes does not perform. Then test at least the two meaningful cases: a resource whose node operation is skipped, and one where the operation is performed. The test should check what the application can actually rely on, not merely whether the Pod reaches Running.

    When the declaration, workload policy, and deployment behavior agree, optional operations are an implementation choice the platform can make safely. When they do not, a skipped call is just an undocumented assumption waiting to become a production failure.

    Drafted with AI assistance, reviewed and edited by Ali.