Rolling Update

Rolling updates provide a practical way to release new application versions without taking the entire service offline. Instead of terminating every existing instance at once, the platform introduces replacements gradually, verifies that they are healthy, shifts traffic toward them, and retires the old instances only when the new version is ready to carry the load.

This approach is widely supported by container orchestrators such as Kubernetes, Docker Swarm, and Nomad. It is especially effective for stateless services, where any healthy instance can handle requests regardless of the instance that originally received the connection.
A rolling update follows a simple operational pattern:

  1. New instances are created using the updated configuration or image.
  2. The platform waits for those instances to pass readiness checks.
  3. New instances begin receiving traffic through the service or load balancer.
  4. Old instances are removed in controlled batches.
  5. The process continues until every instance runs the new version.

The key principle is incremental replacement with continuous verification. Because old and new instances coexist during the transition, a successful rollout depends on more than simply starting the new containers. The application must tolerate mixed-version traffic, route requests correctly, and shut down old instances without interrupting active work.

Compared with a stop-and-start deployment, rolling updates significantly reduce downtime. Compared with a blue-green release, they also avoid maintaining two complete production environments for the duration of every deployment. The trade-off is that rollout behavior is distributed across several instances rather than switched all at once.

Kubernetes Deployments

In Kubernetes, the Deployment controller manages rolling updates. When the pod template changes—for example, when an image tag changes—the controller creates a new ReplicaSet and gradually adjusts the replica counts of the old and new ReplicaSets.

Several configuration fields control the safety and speed of that process:

Parameter Purpose Default
maxUnavailable Maximum number of unavailable pods allowed during the rollout 25%
maxSurge Maximum number of pods above the desired replica count 25%
minReadySeconds Time a pod must remain ready before it is considered available 0 seconds
progressDeadlineSeconds Maximum time without rollout progress before the Deployment is marked as failed 600 seconds
revisionHistoryLimit Number of old ReplicaSets retained for rollback 10
terminationGracePeriodSeconds Time allowed for a pod to terminate gracefully 30 seconds

Percentages for maxUnavailable are rounded down, while percentages for maxSurge are rounded up. At least one of these values must be greater than zero.

For a service that must retain full capacity throughout the deployment, a common choice is:

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 0
    maxSurge: 1

This creates one additional pod before retiring an old one. It preserves the desired amount of ready capacity, but the cluster must have enough spare CPU, memory, and scheduling capacity to run the surge pod.

The following example shows a production-oriented Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 4
  revisionHistoryLimit: 5
  progressDeadlineSeconds: 600
  minReadySeconds: 10
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      terminationGracePeriodSeconds: 30
      containers:
        - name: web
          image: nginx:1.26.2
          ports:
            - containerPort: 80
          readinessProbe:
            httpGet:
              path: /health/ready
              port: 80
            initialDelaySeconds: 3
            periodSeconds: 5
            failureThreshold: 3
          livenessProbe:
            httpGet:
              path: /health/live
              port: 80
            initialDelaySeconds: 15
            periodSeconds: 10
            failureThreshold: 3
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 256Mi

The Deployment can be applied, monitored, and rolled back with standard Kubernetes commands:

kubectl apply -f web.yaml
kubectl set image deployment/web web=nginx:1.26.3
kubectl rollout status deployment/web
kubectl rollout history deployment/web

If the new revision causes problems, Kubernetes can restore a previous retained revision:

kubectl rollout undo deployment/web
kubectl rollout undo deployment/web --to-revision=2

A Deployment rollback only restores the previous pod template. It does not reverse database migrations or other changes made outside the cluster.

Health Checks and Traffic Management

A rollout is only as reliable as the checks used to evaluate new instances.

A readinessProbe determines whether a pod is prepared to receive traffic. Kubernetes adds ready pods to the Service endpoints and removes them when readiness fails. For slow-starting or dependency-heavy applications, the readiness check should validate the conditions required to serve real requests rather than returning success as soon as the process starts.

A livenessProbe determines whether the container is still making progress. If it fails repeatedly, the kubelet restarts the container. This probe should detect a genuine deadlock or irrecoverable failure, not ordinary temporary load.

Applications with lengthy startup times should use a startupProbe. It gives the container time to initialize while preventing the liveness probe from triggering an premature restart.

Graceful shutdown is equally important. When a pod is deleted, Kubernetes sends a termination signal and allows the container to exit within terminationGracePeriodSeconds. A preStop hook can give the application additional time to stop accepting new connections, finish active requests, flush temporary state, or remove itself from an external load-balancing pool.

For reliable traffic draining:

  • Stop accepting new work as soon as termination begins.
  • Allow existing requests to complete within the grace period.
  • Close idle and persistent connections cleanly.
  • Avoid relying on endpoint removal alone, since propagation through networking layers is not instantaneous.
  • Make shutdown behavior idempotent so repeated termination signals cause no harm.

Production Best Practices

Preserve application compatibility. During a rollout, requests may reach pods running different application versions. API responses, event formats, serialized data, and shared contracts must remain compatible across those versions.

Use immutable artifacts. Versioned image tags are better than mutable tags such as latest, and image digests provide the strongest guarantee. If the same tag is overwritten, different nodes may unexpectedly run different binaries.

Design database changes for coexistence. Use an expand-and-contract approach: add the new schema first, deploy compatible application code, migrate data, and remove the old schema only after the rollout is complete. A rollback may still require the old database structure.

Plan capacity around surge pods. Setting maxUnavailable to zero protects availability but creates additional resource demand. Monitor quota limits and make sure schedulers can place the surge pods, especially on constrained clusters.

Protect critical workloads. A PodDisruptionBudget can preserve availability during voluntary disruptions such as node maintenance. It does not replace careful rollout settings and generally does not prevent controller-driven pod deletion.

Observe every stage. Track rollout status, pod events, restart counts, request latency, error rates, saturation, and business-level indicators such as checkout completion. A deployment can appear healthy at the Kubernetes level while users still experience degraded application behavior.

Make rollback routine. Retain enough revision history, document the rollback command, and test it under realistic conditions. A rollback path that has never been exercised is only an assumption.

Troubleshooting a Stuck Rollout

When a rollout stops progressing, begin with the Deployment and then narrow the investigation to individual pods:

kubectl describe deployment web
kubectl get pods -l app=web -o wide
kubectl get events --sort-by=.lastTimestamp
kubectl describe pod <pod-name>
kubectl logs <pod-name>
kubectl logs <pod-name> --previous

Look for conditions such as ProgressDeadlineExceeded, ImagePullBackOff, CrashLoopBackOff, Unhealthy, FailedCreate, quota errors, or insufficient node resources. Common causes include failing probes, incorrect image names, missing configuration, resource contention, readiness gates that never complete, and application errors triggered only under mixed-version traffic.

If the new version is known to be faulty, stop investigating the failed revision and restore a known-good one:

kubectl rollout undo deployment/web
kubectl rollout status deployment/web

Rolling updates are not automatically risk-free, but they give teams a controlled path from one version to the next. When image versions, probes, shutdown behavior, capacity, and data compatibility are managed deliberately, the result is a deployment process that is safer, more observable, and significantly easier to reverse.