Rolling Updates: Deploy Python Without Downtime
A rolling update gradually replaces old pods with new ones, ensuring your Python application remains available throughout the deployment. Instead of stopping all pods and starting new ones (causing downtime), Kubernetes incrementally terminates old pods and spawns new replicas, maintaining service availability. You can control the pace of replacement, monitor each wave of updates, and instantly roll back if issues arise.
Understanding Rolling Update Strategy
Kubernetes Deployments use rolling updates by default. The strategy is controlled by two parameters:
- maxSurge: Maximum number of extra pods allowed during the update (percentage or absolute number).
- maxUnavailable: Maximum number of pods that can be unavailable simultaneously.
For a Deployment with 3 replicas, maxSurge: 1 and maxUnavailable: 1 means:
- Start 1 new pod (now 4 replicas: 3 old, 1 new).
- Terminate 1 old pod (now 3 replicas: 2 old, 1 new).
- Start another new pod (now 4 replicas: 2 old, 2 new).
- Terminate another old pod (now 3 replicas: 1 old, 2 new).
- Start the final new pod (now 4 replicas: 1 old, 3 new).
- Terminate the last old pod (now 3 replicas: all new).
This maintains at least 2 replicas active at all times, ensuring zero downtime.
Configuring Rolling Update Parameters
Here's a Deployment with explicit rolling update settings:
apiVersion: apps/v1
kind: Deployment
metadata:
name: python-web-app
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: python-web
template:
metadata:
labels:
app: python-web
spec:
containers:
- name: app
image: my-registry/python-app:2.0.0
ports:
- containerPort: 8000
terminationGracePeriodSeconds: 30
The maxUnavailable: 0 ensures zero pods are unavailable during the update—the maximum availability strategy. The terminationGracePeriodSeconds: 30 gives your Python app 30 seconds to gracefully shut down before being forcefully killed. I've deployed a Python API with these settings, and rolling updates completed with zero dropped requests—users never noticed the deployment.
Triggering a Rolling Update
Update the image version in your Deployment:
kubectl set image deployment/python-web-app app=my-registry/python-app:2.0.0
Or edit the Deployment directly:
kubectl edit deployment python-web-app
# Change image from :1.0.0 to :2.0.0, save and exit
Kubernetes detects the change and begins the rolling update. Monitor progress:
kubectl rollout status deployment/python-web-app
This shows the update progress. Once complete, all pods are running the new version.
Implementing Graceful Shutdown for Clean Deployments
When Kubernetes terminates a pod during a rolling update, it sends SIGTERM to the main process. Your Python application should handle this signal to gracefully shut down:
import signal
import time
from flask import Flask
from waitress import serve
app = Flask(__name__)
server_thread = None
is_shutting_down = False
def signal_handler(sig, frame):
global is_shutting_down
print("Shutdown signal received. Gracefully shutting down...")
is_shutting_down = True
# Give in-flight requests time to complete
time.sleep(5)
# Perform cleanup (close database connections, flush logs, etc.)
print("Cleanup complete. Exiting.")
exit(0)
signal.signal(signal.SIGTERM, signal_handler)
@app.route("/api/data", methods=["GET"])
def get_data():
if is_shutting_down:
return {"error": "server shutting down"}, 503
return {"data": "example"}, 200
@app.route("/ready", methods=["GET"])
def ready():
"""Kubernetes readiness probe."""
if is_shutting_down:
return {"status": "not_ready"}, 503
return {"status": "ready"}, 200
if __name__ == "__main__":
# Run on 0.0.0.0 to accept traffic from Kubernetes Service
serve(app, host="0.0.0.0", port=8000, threads=4)
When SIGTERM arrives, the app sets is_shutting_down = True, sleeps to allow in-flight requests to finish, cleans up, and exits. The readiness probe returns 503, removing the pod from the Service before in-flight connections close.
Rolling Back a Problematic Deployment
If the new version has issues, instantly roll back to the previous version:
kubectl rollout undo deployment/python-web-app
This restores the previous image and triggers another rolling update backward. Rollback is fast (seconds) and preserves availability—no downtime even on rollback.
View rollout history:
kubectl rollout history deployment/python-web-app
# Show details of a specific revision
kubectl rollout history deployment/python-web-app --revision=2
Rollback to a specific revision:
kubectl rollout undo deployment/python-web-app --to-revision=1
Monitoring and Validation During Rollouts
Readiness and liveness probes guide rolling updates. If a new pod fails readiness probes, Kubernetes does not mark it as ready and does not route traffic to it. If enough pods fail, the rollout pauses or reverses to prevent cascading failures.
Use kubectl describe to monitor pod readiness during a rollout:
kubectl get pods -l app=python-web --watch
This shows pod names, ready status, and restart count in real-time. If a pod shows 0/1 Ready, it is not healthy.
Canary Deployments: Deploy to a Subset First
A canary deployment rolls out to a small percentage of traffic first, validating the new version before deploying to all replicas. Kubernetes does not natively support canary (it supports only rolling), but you can simulate it with two Deployments:
apiVersion: apps/v1
kind: Deployment
metadata:
name: python-web-stable
spec:
replicas: 9
selector:
matchLabels:
app: python-web
version: stable
template:
metadata:
labels:
app: python-web
version: stable
spec:
containers:
- name: app
image: my-registry/python-app:1.0.0
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: python-web-canary
spec:
replicas: 1
selector:
matchLabels:
app: python-web
version: canary
template:
metadata:
labels:
app: python-web
version: canary
spec:
containers:
- name: app
image: my-registry/python-app:2.0.0
---
apiVersion: v1
kind: Service
metadata:
name: python-web-service
spec:
selector:
app: python-web # Matches both stable and canary pods
ports:
- port: 80
targetPort: 8000
The Service routes to both stable (version 1.0) and canary (version 2.0) pods. The 10:1 ratio means 9 out of 10 requests hit the stable version. Monitor metrics (error rate, latency) on the canary. If metrics are healthy, increase canary replicas and decrease stable replicas until fully migrated.
Using kubectl Patch for Minimal Deployments
For critical systems, avoid full rollouts and use strategic patches:
# Update just the image, triggering a rolling update
kubectl patch deployment python-web-app -p '{"spec":{"template":{"spec":{"containers":[{"name":"app","image":"my-registry/python-app:2.0.0"}]}}}}'
This is equivalent to kubectl set image but uses the Kubernetes API directly.
Key Takeaways
- Rolling updates gradually replace old pods with new ones, maintaining availability.
- Configure
maxSurgeandmaxUnavailableto control the update pace and availability guarantees. - Implement graceful shutdown (SIGTERM handling) so your Python app finishes in-flight requests during termination.
- Readiness probes ensure new pods are healthy before receiving traffic.
- Instantly roll back with
kubectl rollout undoif issues are detected.
Frequently Asked Questions
How do I ensure zero downtime during a rolling update?
Set maxUnavailable: 0 to guarantee at least one pod is always available. Set maxSurge to allow temporary over-provisioning (e.g., 1 or 25%). Implement readiness probes to ensure pods are healthy before traffic is routed. Implement graceful shutdown to finish in-flight requests.
What happens if a pod fails during a rolling update?
If a new pod fails readiness probes repeatedly, Kubernetes pauses the rollout. Existing old pods continue serving traffic. Check kubectl describe deployment <name> to see the issue. Fix the problem (update the image) and trigger a new rollout.
How long does a rolling update take?
Time depends on maxUnavailable, pod startup time, and readiness probe settings. For 3 replicas with maxUnavailable: 1 and 30-second startup time, expect 1-2 minutes. For 100 replicas, it may take 10+ minutes. Use --record to mark the deployment for easier tracking: kubectl set image ... --record.
Can I pause a rolling update mid-way?
Yes, use kubectl rollout pause deployment/python-web-app. This keeps the current state unchanged. Resume with kubectl rollout resume deployment/python-web-app.
What is the difference between rolling updates and blue-green deployments?
Rolling updates gradually replace pods. Blue-green deployments maintain two complete versions (blue=old, green=new) and switch traffic between them atomically. Blue-green is safer but requires 2x resources. Use rolling for most applications; use blue-green for critical systems.