Rolling Updates for Python Apps
Implement rolling updates for Python apps in Kubernetes, with hands-on steps, troubleshooting, and next steps.
Focus: implement rolling updates for python apps
You’ve just pushed a new version of your Python API — maybe you’ve added a /health endpoint, fixed a sneaky bug, or upgraded your dependencies. In development, you restart your local server and you’re done. But in production, a naive approach — deleting all your old pods and creating new ones — will drop every in-flight request and leave your users staring at a 502 error. This is exactly the pain that rolling updates solve: a safe, incremental deployment strategy that keeps your service available throughout the release. In this lesson, you’ll learn how to implement rolling updates for Python apps in Kubernetes, from the underlying mechanics to hands-on commands you can run today.
The problem this lesson solves
When you update a running application, the moment your old pods are terminated, they stop accepting new connections and close any in-flight requests. If you replace all pods at once — or worse, delete the Deployment and recreate it — your service experiences a hard cutover with a burst of connection failures, timeouts, and user-visible errors.
Rolling updates fix this by replacing pods gradually. Instead of tearing down the entire fleet, you create new pods while old ones are still serving. Kubernetes watches health checks (readiness probes) to decide when it’s safe to move on. The result: zero downtime and a stable, continuously available service — even during buggy releases, because you can pause or roll back at any moment.
For Python developers, rolling updates are especially important because Python services often carry state in memory (like a FastAPI dependency cache) or rely on long-lived connections (e.g., WebSockets). A blunt restart might break those connections. Rolling updates give you a controlled transition that respects your application’s lifecycle.
Core concept / mental model
Think of a Deployment as a staging manager for your pods. It doesn’t just create and destroy; it orchestrates the changeover. You define a desired state (how many replicas you want, which image version, what ports, and what probes). The Deployment controller ensures that the cluster always moves toward that state — but it does so in a special way when you change the image.
Imagine you run a restaurant with 10 servers (pods). You can’t suddenly replace every server at the same time because you’d have no one serving tables. Instead, you bring in a few new servers, let them learn the menu (wait for readiness), and only then let the old servers go home. That’s a rolling update.
Key terms you’ll hear repeatedly:
- ReplicaSet — the controller that maintains a desired number of identical pod replicas. A Deployment manages one or more ReplicaSets.
- MaxSurge — how many extra pods you can create above the desired count during an update (as a number or percentage).
- MaxUnavailable — how many pods may be unavailable during the update (number or percentage).
- Readiness probe — a check Kubernetes uses to determine if a pod is ready to serve traffic. If it fails, the pod is removed from the Service’s endpoints.
- Rollback — reverting to a previous Revision of the Deployment, often with a single command.
During a rolling update, Kubernetes creates a new ReplicaSet with the updated pod template, then scales it up while scaling down the old ReplicaSet — step by step. The precise behavior is governed by strategy.rollingUpdate.maxSurge and maxUnavailable.
How it works step by step
When you run kubectl set image deployment/myapp myapp=myapp:v2 (or apply a manifest with a new image), the Deployment controller does the following:
- Create a new ReplicaSet with the updated pod template (the new image, labels, etc.).
- Scale up the new ReplicaSet — adding new pods up to
maxSurge(e.g., 25%). These new pods start alongside the old ones. - Wait for the new pods to become Ready — the readiness probe must pass; otherwise the update pauses.
- Scale down the old ReplicaSet — terminating old pods down to
maxUnavailable(e.g., 25%), so the total available pods never drop below the desired count. - Repeat steps 2–4 until the new ReplicaSet has 100% of replicas and the old one is scaled to zero.
- Record a new Revision in the Deployment’s rollout history — this is what allows you to roll back later.
The exact pacing depends on your maxSurge and maxUnavailable settings. By default, both are 25% (of the total replicas). For a 4-replica deployment, that means at most 1 new pod above the target and 1 pod unavailable at a time — a nice balance between speed and safety.
Why readiness probes matter — without them, Kubernetes treats a pod as “Ready” as soon as it’s running. If your Python app takes 10 seconds to load models or connect to a database, those pods will be marked Ready too early, and traffic will be routed to an app that isn’t actually serving. Always define a readinessProbe that hits an endpoint like /health or /ready.
Hands-on walkthrough
Let’s implement rolling updates for a simple Python FastAPI app. You’ll create a Deployment, update it, and observe the rollout — all with kubectl.
1. Start with a minimal Deployment
Create a file called deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 4
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: myregistry/myapp:v1
ports:
- containerPort: 8000
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 10
periodSeconds: 10
Apply it:
kubectl apply -f deployment.yaml
2. Update the image to v2
Now bump the image version — this is the classic way to trigger a rollout:
kubectl set image deployment/myapp app=myregistry/myapp:v2
Watch the rollout in real time:
kubectl rollout status deployment/myapp
Expected output (abbreviated):
Waiting for deployment "myapp" rollout to finish: 1 out of 4 new replicas have been updated...
...
Waiting for deployment "myapp" rollout to finish: 4 out of 4 new replicas have been updated...
deployment "myapp" successfully rolled out
While the rollout runs, inspect what’s happening:
kubectl get pods -l app=myapp
You’ll see pods with different REVISION suffixes or different image versions side by side — that’s the rolling update in action.
3. Verify the rollout history
kubectl rollout history deployment/myapp
Output:
deployments "myapp"
REVISION CHANGE-CAUSE
1 <none>
2 <none>
To record the reason for the change, use the --record flag (deprecated in newer versions, but still useful in older ones) or set the kubernetes.io/change-cause annotation in your manifest.
4. Simulate a failed rollout and roll back
Suppose v3 is buggy — its /health endpoint always returns 503. Deploy it and watch the rollout pause:
kubectl set image deployment/myapp app=myregistry/myapp:v3
kubectl rollout status deployment/myapp
The command will hang because the new pods fail the readiness probe. After a timeout, you’ll see something like:
Waiting for deployment "myapp" rollout to finish: 1 old replicas are pending termination...
Stop waiting and roll back to the previous revision:
kubectl rollout undo deployment/myapp
Or roll back to a specific revision:
kubectl rollout undo deployment/myapp --to-revision=2
5. Apply a new Deployment with custom rolling update strategy
For more control, define the strategy in the manifest:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 6
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 2
maxUnavailable: 1
...
This allows 2 extra pods above the desired count and at most 1 pod unavailable — good if you want to keep a tight minimum availability but don’t mind a slight pop in resource usage.
Compare options / when to choose what
Rolling updates are the default for Deployments, but they’re not the only strategy. Here’s how they compare to alternatives.
| Strategy | How it works | Zero downtime? | When to choose |
|---|---|---|---|
| RollingUpdate | Incrementally swaps pods, respecting probes | Yes, if probes are correct | Default choice for most Python web services; best for steady traffic and no external state changes |
| Recreate | Deletes all old pods, then creates new ones | No — brief downtime | When your app doesn’t support multiple versions running at once (e.g., strong schema incompatibility) |
| Blue/Green | Deploy new version alongside old, then switch Service selector | Yes (switch is atomic) | When you need instant rollback and can double resource usage |
| Canary | Send a small % of traffic to new version, gradually increase | Yes | When you want to validate new version with real traffic before full rollout |
For Python apps, rolling updates are usually the simplest and most cost-effective. They don’t require extra infrastructure or traffic-splitting logic, and Kubernetes’ built-in reconciliation handles the details. If you’re running a public API with moderate traffic, stick with rolling updates. If you need canary ability, consider a service mesh like Istio or a progressive delivery tool like Argo Rollouts.
Pro tip: If your Python app migrates a database schema, a rolling update may create issues where old pods write to a new schema or vice versa. In that case, run migrations as a separate pre-deployment Job, or use the Recreate strategy for that specific release.
Troubleshooting & edge cases
Rollout hangs at “Waiting for deployment ... 0 out of N new replicas have been updated”
- New pods keep crashing. Check
kubectl logsandkubectl describe podon the new pods. Common causes: image pull errors, missing environment variables, or your app exits early.
Rollout proceeds even though new pods are failing readiness
- You may not have a readiness probe, or the probe path is wrong. Kubernetes only waits for the pod to be ready — if your probe is too lenient (e.g., always returns 200), the update will continue even if the app is broken. Test the probe manually with
curlinside the pod.
Old pods are not being terminated
- This happens if
maxUnavailableis 0 and your new pods aren’t becoming Ready. Check readiness probe logs and ensure the new image actually works. If the new pods are stuck, the rollout intentionally pauses to protect availability.
You see “error: deployment already exists”
- You’re using
kubectl createinstead ofkubectl apply. Usekubectl apply -f deployment.yamlto update the existing Deployment.
Rollback doesn’t restore the old version
- Make sure you have a previous Revision in the history. If you edited the Deployment in place without changing its template, Kubernetes may not create a new Revision. To force a new revision, change the
imagefield explicitly.
Connection resets during rollout
- This usually happens because you’re terminating pods too aggressively. Lower
maxUnavailable(e.g., 0) and increasemaxSurge(e.g., 1 or a percentage). Also configure aterminationGracePeriodSecondsso in-flight requests can finish before SIGTERM.
What you learned & what's next
You now know how to implement rolling updates for Python apps in Kubernetes. You understand the mental model of ReplicaSets, the step-by-step update process, how to trigger a rollout with kubectl set image, how to monitor it with kubectl rollout status, and how to roll back when things go wrong. You also saw how to tune the strategy with maxSurge and maxUnavailable, and how to debug common issues like stuck rollouts or probe failures.
In the next lesson, you’ll take rolling updates further by automating them — learn how to use ConfigMaps and Secrets to change environment configuration without rebuilding your image, and how to trigger rollouts on config changes as part of a CI/CD pipeline. You’ll also explore advanced rollout patterns like canary deployments and progressive delivery with Argo Rollouts.
Practice recap: Create a Deployment with 3 replicas of a FastAPI app. Add a readiness probe on /health. Update the image to a new tag, watch the rollout, and then trigger a rollback to the previous version. Verify that zero traffic is lost by running a load test in parallel.
Practice recap
Create a Deployment with 3 replicas of a simple FastAPI app that has a readiness probe on /health. Update the image to a new tag and watch the rollout with kubectl rollout status. Then trigger a rollback and verify that traffic is never interrupted by running a load test in parallel. This hands-on exercise will cement the workflow—and prepare you for the next lesson on ConfigMaps and Secrets.
Common mistakes
- Forgetting to define a readiness probe — Kubernetes treats the pod as ready as soon as it's running, so broken apps get traffic and the rollout looks successful.
- Setting maxUnavailable to 0 without allowing enough maxSurge, causing the rollout to hang forever if new pods never become ready.
- Manually deleting or recreating pods during an update, which can interfere with the ReplicaSet controller and lead to unpredictable states.
- Ignoring the rollout history — if you don't annotate changes with a change-cause, you won't know what version you're rolling back to.
Variations
- Use
kubectl rollout restart deployment/myappto force a rolling update without changing the image — useful for picking up a new Secret or ConfigMap. - Adopt the Recreate strategy for apps that can’t run two versions at the same time (e.g., due to schema migrations).
- Use a tool like Argo Rollouts to implement canary or blue-green deployments with automated traffic analysis.
Real-world use cases
- Deploying a new version of a FastAPI backend to production with zero downtime, so users never see a 502 error.
- Updating a Celery worker deployment to a new dependency version without killing in-flight tasks.
- Rolling back a buggy release of a Django app in seconds using
kubectl rollout undo.
Key takeaways
- Rolling updates replace pods incrementally, using readiness probes to ensure new pods are healthy before old ones are terminated.
- MaxSurge and MaxUnavailable control the update speed and availability guarantee.
- Always define a readiness probe for Python web apps so Kubernetes routes traffic only to truly prepared pods.
- Use
kubectl rollout statusandkubectl rollout historyto track and audit your deployments. - Rolling updates are the default, but you can choose Recreate, Blue-Green, or Canary depending on your app’s needs.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.