A rolling update is a controlled replacement, not a promise of uninterrupted service. Its useful property is that the controller can retain old replicas while introducing new ones. Whether users notice the change also depends on spare capacity, meaningful health checks, and shutdown behavior. This article tunes that process; the companion strategy article asks whether versions should overlap at all.

Two rollout-budget calculations are separated from a terminating tail. Surge rounds up and unavailable down, with the zero-surge fencepost exception. A vertical timeline distinguishes Ready and possible Service traffic from availability after minReadySeconds. Shutdown requires endpoint changes, draining, signal handling and grace. Pause, PDB and progress deadline do not provide exact canary exposure, rollout protection or automatic rollback. Arithmetic and diagrams do not establish runtime availability.
Ten plus two is a target of twelve; ten minus one is a planning budget of nine. Account separately for terminating Pods, stable readiness and real request behavior.

The surge and the gap

With ten desired replicas, maxSurge: 2 permits a rollout target of twelve, not eleven. maxUnavailable: 1 gives the controller an availability budget of nine. It is not a limit of one old Pod deleted per wave: several old replicas can be removed once sufficient replacements are available. Terminating Pods can remain and consume resources beyond the surge target, so twelve is not a hard count of every Pod or process.

Percentages need rounding: surge rounds upward, unavailable downward. For three replicas, the default 25% yields one surge and zero unavailable. Kubernetes 1.34.0 has a boundary exception: zero surge plus a nonzero unavailable percentage that rounds to zero resolves to one unavailable replica, so replacement can progress. Do not infer a zero-disruption policy from that rounded zero.

Neither knob reserves resources. Compare requests with schedulable capacity, quota, placement constraints, and the shutdown tail before choosing faster replacement. A budget that looks affordable on paper may still leave every new Pod Pending.

Health gates replacement

Check that a readiness probe is actually configured. Readiness should answer whether this instance can serve its intended traffic. A listening port alone may miss application failure; checking a required backend can help, but a shared dependency failure can also withdraw every replica. Design that response deliberately rather than blindly weakening a failing probe.

minReadySeconds adds a stable-ready interval before a new Pod counts as available. It does not delay Service traffic until that interval finishes. A startup probe can protect slow initialization from premature liveness restarts. None of these checks proves correct business behavior or sustained throughput.

Shutdown needs its own test. Endpoint changes, connection draining, application signal handling, and the termination grace period must work together. A green readiness endpoint cannot prevent an application from dropping an in-flight request when it exits.

Choose a deliberate pace

One surge and zero unavailable is a useful starting point for a small fleet with spare capacity; it prevents intentional availability reduction by the rollout, not node failures or request errors. A PodDisruptionBudget does not constrain a Deployment’s own rolling upgrade.

Manual pause is useful for inspection, but it does not reserve an exact one-Pod canary or a fixed traffic percentage: reconciliation may advance before the pause takes effect. Use separately controlled canary capacity and routing when that exposure limit matters. Define error-rate, latency, restart, and business-check thresholds before starting, with an observation period after completion.

When it breaks

A stuck rollout needs evidence from the failing layer. Scheduling events point to capacity or placement; image-pull events point to registry access or image references; container logs and probe events distinguish crashes from readiness failures. Do not change probes until you know whether they are detecting a real fault.

A bad new version may consume the configured unavailable allowance before progress stalls. progressDeadlineSeconds reports stalled progress; it neither automatically rolls back nor freezes all reconciliation. Alert on the condition and decide whether to repair or revert. A completed rollout still needs a bake period for memory growth, connection exhaustion, and errors under realistic traffic. Retain usable revision history and the previous image through that period.

Check it quickly

Save this standard-library exercise as rounding_window.py and run python3 rounding_window.py. It checks percentage conversion using integer arithmetic, including a small fleet, an exact boundary, and 100%. It is not a Deployment controller simulation or a complete API validator. Its 0–100% input range is an exercise limit, not a maxSurge API restriction.

"""Check percentage rounding only; no Kubernetes API calls."""


def round_percent(replicas, percent, *, up):
    if type(replicas) is not int or replicas <= 0:
        raise ValueError("this exercise requires positive integer replicas")
    if type(percent) is not int or not 0 <= percent <= 100:
        raise ValueError("this exercise accepts integer percentages 0..100")
    numerator = replicas * percent
    return (numerator + 99) // 100 if up else numerator // 100


def main():
    cases = [(1, 1, 0, 1), (3, 25, 0, 1), (4, 50, 2, 2),
             (10, 20, 2, 2), (10, 10, 1, 1), (4, 100, 4, 4)]
    for replicas, percent, down, up in cases:
        assert round_percent(replicas, percent, up=False) == down
        assert round_percent(replicas, percent, up=True) == up
        print(f"replicas={replicas}, percent={percent}: down={down}, up={up}")
    print("PASS: percentage rounding only; no cluster exercised")


if __name__ == "__main__":
    main()

Expect six case lines and a final arithmetic-only PASS. Three replicas at 25% produce zero rounded down and one rounded up; ten at 20% produce two either way. The assertions were executed with Python 3.12.14 in Linux during this revision. They establish arithmetic, not service availability.

Before applying these numbers, select the intended test context and namespace and confirm the actual Deployment strategy. With an existing api Deployment and app=api Pods, kubectl rollout status deployment/api --timeout=120s observes convergence, while kubectl get pods -l app=api -w watches replacements in a separate terminal. A client timeout does not cancel the rollout. If releases overlap, use --revision=N to follow the intended revision. Stop the watch with Ctrl-C.

Those cluster commands were not executed here. Collect Pod events, logs, and Deployment status during a staging upgrade, together with continuous requests through the real Service or ingress. Record failures and latency during shutdown. This is the integration evidence still needed; a successful controller status alone cannot establish zero downtime.

Further reading

Sources