Full lesson
Explore the full explanation, examples, and visuals at your own pace.
Part 1
You refresh the cart page and get a different version. During the shop-api rollout, the browser sends the same GET /cart to the same Service twice. The first response comes from Pod v1, the old page. After the refresh, Pod v2 answers with the new page. Same address, so the cause sits behind the Service.
Selector: app=shop-api
The Service doesn't know what a version is. Its selector is just app equals shop-api, and it matches Pods by label. Pod v1 A, Pod v1 B, and Pod v2 A all carry that label, so every one of them is an equally valid target.
shop-api.yaml
Look at the rollout settings first. maxSurge 1 with maxUnavailable 0 lets Kubernetes add one extra Pod before removing any old one. Then the labels. Every Pod carries app shop-api, but the template also adds version v2. The Service selector only checks app, so it ignores version.
apiVersion: apps/v1
kind: Deployment
metadata:
name: shop-api
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: shop-api
template:
metadata:
labels:
app: shop-api
version: v2
---
apiVersion: v1
kind: Service
metadata:
name: shop-api
spec:
selector:
app: shop-api
ports:
- port: 80
targetPort: 8080Rolling update: versions overlap
Watch the rollout left to right. A v2 Pod surges in beside three v1 Pods. Once it's ready, one v1 goes away, and that repeats. Through the middle stages, like two v1 and two v2, both versions run together. Only at the end is it all v2.
Readiness gates the endpoint list
A new v2 Pod doesn't get traffic just for starting. The kubelet probes /ready, and while it answers 503 warming, the Pod stays out. Once the probe returns 200, the kubelet marks it Ready, the EndpointSlice updates, and kube-proxy adds the endpoint. Only then can the Service send v2 a request.
v2 container readiness probe
This readinessProbe is what keeps v2 honest. Kubernetes calls /ready on port 8080 every five seconds. Leave it out, and a started container counts as Ready immediately, so traffic arrives early. And /ready should check real dependencies, like caches and the database, not just return 200.
containers:
- name: shop-api
image: shop-api:2.0
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3One pick per connection
A client opens a new connection to the Service IP, and kube-proxy's rules pick one ready Pod, v1 or v2, roughly at random. Version never enters the decision. Keep-alive connections stay pinned to their Pod, and without session affinity, nothing else keeps a client on one version.
Mid-rollout, two v1 Pods are ready, and two v2 Pods exist but one fails readiness. Roughly what share of new connections reach v2?
Mid-rollout, two v1 Pods are ready, and two v2 Pods exist but one fails readiness. Roughly what share of new connections reach v2?
- About one third
- About half
- None at all
Mid-rollout, two v1 Pods are ready, and two v2 Pods exist but one fails readiness. Roughly what share of new connections reach v2?
About one third. Only ready Pods are endpoints, so the Service sees three: two v1 and one v2. Each new connection picks among those three, so v2 gets roughly one in three. The failing v2 Pod exists but receives nothing until its probe passes.
- About one third
- About half
- None at all
Illustrative: equal ready Pods, equal share
As the rollout moves, v2's expected share climbs from zero, to twenty-five, fifty, seventy-five, then a hundred percent. It tracks v2's fraction of ready endpoints. Treat these as expectations, though. Connection reuse and client behavior can skew the real split.
Chart values
| Rollout stage (ready Pods) | Percent to v2 |
|---|---|
| 3 v1 | 0 |
| 3 v1 + 1 v2 | 25 |
| 2 v1 + 2 v2 | 50 |
| 1 v1 + 3 v2 | 75 |
| 3 v2 | 100 |
Controlling which version gets traffic
You have three levers. Make the readiness probe test real readiness, so v2 gets traffic only when it can serve. Keep versions backward compatible, so mixing is harmless. For a hard switch, add version=v2 to the Service selector after the rollout.
- Readiness probes that test real readiness
- Keep v1 and v2 backward compatible
- Version-label cutover for hard switches
Labels plus readiness decide routing
Labels plus readiness decide routing. The Service matches Pods by label, then sends traffic only to the ready ones. It never checks version. So any rollout that overlaps v1 and v2 under one selector will mix them, unless you plan for it.




