A Deployment's RollingUpdate strategy is two knobs, maxSurge and maxUnavailable, each an absolute count or a percentage. They decide how many pods may exist above the desired count during a rollout and how many may be missing from it. Resolve a strategy into the absolute numbers so you can tell whether the rollout will hold capacity — and whether your cluster has room for the surge.
Kubernetes converts percentages against spec.replicas, and the two knobs round in opposite directions, deliberately, so the defaults never violate what they promise:
With replicas: 10 and 25% for both, that is a surge of ceil(2.5) = 3 and unavailability of floor(2.5) = 2. Rounding both the same way is the usual bug.
From there:
min_available = replicas - max_unavailable # the floor on serving capacity
max_pods = replicas + max_surge # peak pods, i.e. peak resource use
Implement:
def rollout_bounds(replicas, max_surge, max_unavailable):
Return a dict with keys "max_surge", "max_unavailable", "min_available", "max_pods", in that order, all ints.
print(rollout_bounds(10, "25%", "25%"))
Output:
{'max_surge': 3, 'max_unavailable': 2, 'min_available': 8, 'max_pods': 13}
Surge rounds up to 3, unavailability rounds down to 2 — so the rollout never drops below 8 serving pods, and the cluster must have headroom for 13.
print(rollout_bounds(10, "25%", "25%"))
{'max_surge': 3, 'max_unavailable': 2, 'min_available': 8, 'max_pods': 13}25% of 10 is 2.5. maxSurge rounds up to 3 so the Deployment may run 13 pods at peak; maxUnavailable rounds down to 2 so at least 8 pods keep serving. The opposite rounding is what guarantees both promises hold at the same time.
max_surge / max_unavailable are ints or percentage strings such as "25%"replicas: surge rounds UP, unavailable rounds DOWN