Kubernetes v1.36 PodGroup scheduling cycle explained

Why PodGroup moves scheduling from individual Pods to a single atomic decision

Kubernetes v1.36 splits the static template from the runtime group state. The Workload object carries the template side, while PodGroup carries the runtime scheduling policy and the link back to that template. Pods then point at the runtime group through schedulingGroup, which gives the scheduler one place to look when it needs to decide whether the group can run.

The important change is the unit of scheduling. The kube-scheduler no longer treats each Pod as an isolated case when gang scheduling is involved. It takes a single snapshot of cluster state for the whole group, checks whether enough Pods can fit, then binds the set atomically. That avoids the classic deadlock where the first few Pods consume the wrong capacity and the rest never make it.

How the scheduler snapshots cluster state once for the whole group

The scheduler works from one view of the cluster for the entire PodGroup cycle. It gathers the queued members, sorts them in a deterministic order, then runs the usual filter and score phases across the group. The result is judged as a batch, not one Pod at a time.

That matters for heterogeneous groups. A valid placement can be fragile when different Pods need different nodes, different resources, or different topology. A single snapshot stops the cycle from drifting while it is still deciding, but it does not promise a clean fit. It only promises a consistent one.

Where minCount turns gang scheduling into a hard gate

minCount is the hard edge of the policy. If the scheduler cannot find enough Pods that can run together, it does nothing. No partial bind, no optimistic start, no clever guess. The gang is schedulable only if the required count can run at once.

That is a blunt rule, but it avoids the uglier failure mode where a group starts in fragments and then stalls forever. If the threshold is set to 4, then four Pods must be placeable together before the group gets past the gate.

What changes inside the queue, filter, and bind path

The group stays in PreEnqueue until the count threshold is met. That keeps the queue from wasting time on work that already fails the gang rule. Once enough members are present, the scheduler can move the PodGroup into the normal filter and bind path.

Deterministic ordering is the other quiet change. Mixed groups can behave badly if the scheduler changes its mind from one pass to the next. Sorting the queued members in a stable order keeps the same group from being arranged one way on Monday and another way on Tuesday, which is exactly the sort of harmless-looking chaos that becomes a support ticket later.

Why PodGroup stays in PreEnqueue until the group is large enough

PreEnqueue acts as a gate, not a hint. The scheduler holds the Pods there until the group size reaches the point where a gang decision makes sense. That cuts down on churn from groups that are still incomplete.

The downside is obvious. A partially created group does nothing until enough members exist. If a controller is slow, or if one Pod keeps failing admission, the rest of the group sits and waits. That is less dramatic than deadlocking the cluster, but it still looks rude from the outside.

How deterministic ordering keeps mixed groups from drifting between runs

Stable ordering gives the scheduler a repeatable view of the group members. Without it, two runs against the same set of Pods can arrive at different placements purely because the queue happened to hand over items in a different sequence.

For ordinary single-Pod placement that is annoying. For gang scheduling it can break assumptions about dependency order and topology. Deterministic ordering does not make the placement easier, it just makes the outcome less slippery.

What breaks when the group cannot fit, and what Kubernetes does next

If the group cannot fit, the scheduler binds nothing. Existing Pods that already landed are left alone. Later cycles do not claw them back just because the group no longer meets minCount. The scheduler will not unassign or evict them in a failed retry.

That makes the behaviour predictable, which is useful and slightly inconvenient at the same time. A group can drift into a state where the newly scheduled members never catch up with the old ones, and the system does not try to repair that for you.

Why later cycles do not evict Pods that already landed

Kubernetes v1.36 does not treat a later failed PodGroup cycle as grounds for eviction. Once a Pod has been bound, it stays bound unless something else acts on it. The scheduler does not go back and undo the earlier placement just because the rest of the group no longer fits.

This keeps the scheduler from becoming a polite vandal. It also means a half-placed group can stick around in a broken state if the remaining members never find room. Gang scheduling is tidy only when the whole gang fits. Anything else is just waiting with better terminology.

How backoff and retry behave for unschedulable PodGroups

Unschedulable groups go back to the queue after backoff. The cycle does not end in a special rescue path. It retries later, with the same basic rules, and hopes the cluster has changed in the meantime.

That retry loop is useful when the problem is temporary capacity pressure. It is much less useful when the placement is structurally impossible, such as a group with a topology requirement that cannot be met on the available nodes. In that case the scheduler can keep retrying without discovering new physics.

How Workload, schedulingGroup and PodGroup fit together in v1.36

The model now separates the controller-side template from the runtime group. The Job controller defines the Workload object, and that Workload carries the PodGroup templates to be instantiated. The runtime Pods then reference the PodGroup through schedulingGroup.podGroupName, while the PodGroup itself points back to the Workload template reference.

PodGroupScheduled appears in status when the runtime group has cleared scheduling. That keeps the runtime state attached to the object the scheduler actually uses, rather than hiding it in the controller template where it does not belong. ResourceClaimTemplates also matter here, because they let the workload side express resource needs for Dynamic Resource Allocation without forcing the scheduler to guess.

The old workloadRef path is gone from the Pod spec in this model. The runtime group is the scheduling unit, not the controller template. That is cleaner on paper and less forgiving in practice, which is usually how scheduling changes arrive.

A final wrinkle is topology-aware scheduling. Once gang placement and topology constraints are both in play, the scheduler has less room to improvise. A group can satisfy minCount and still fail if the nodes that fit the Pods do not fit the topology rules. That is the sort of failure that looks unfair until you remember the scheduler is doing exactly what it was told.

Related posts

Weekly Tech Digest | 06 Jul 2026

Stay updated with the latest in tech! This digest covers AI ethics, auto industry shifts, and the impact of politics on technology, exploring today's pressing issues.

wolfCOSE zero-allocation parsing in embedded C

wolfCOSE looks sensible only if you care about what your firmware actually has to carry. I like that, because on small targets the wrong crypto feature can cost more than the message itself, and there...

restic | v0.19.1

restic v0 19 1: safer FUSE mounts and mountpoint checks, robust backup source and exclude handling, clearer CLI JSON output, Windows SFTP deletion fixes