Kubernetes deployments aren’t just about getting new code out; they’re about managing risk and ensuring availability.
Let’s see what this looks like in practice. Imagine we have a simple Nginx deployment serving a static index.html.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: nginx
image: nginx:1.21.0
ports:
- containerPort: 80
And a Service to expose it:
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer
When we kubectl apply this, Kubernetes spins up 3 pods matching the app: my-app label and a LoadBalancer service directs traffic to them.
Rolling Update
This is the default strategy in Kubernetes. When you update the image tag in your Deployment spec, Kubernetes gradually replaces old pods with new ones. It ensures that at least maxUnavailable pods are down at any given time and that the number of running pods doesn’t exceed maxSurge above the desired replicas.
Let’s say we want to update to nginx:1.22.0. We’d change the image field in the Deployment manifest:
# ...
containers:
- name: nginx
image: nginx:1.22.0 # <-- Changed here
# ...
And then run kubectl apply -f deployment.yaml.
Kubernetes will start a new pod with nginx:1.22.0. Once it’s ready, it will terminate an old pod with nginx:1.21.0. This continues until all old pods are replaced.
The key levers here are spec.strategy.rollingUpdate.maxUnavailable and spec.strategy.rollingUpdate.maxSurge. If replicas: 3, maxUnavailable: 1, and maxSurge: 1, Kubernetes will ensure at least 2 pods are running and at most 4 pods are running during the update. The old pod is only terminated after the new pod is deemed ready by its readiness probe.
Blue-Green Deployment
This strategy involves running two identical environments, "Blue" (current version) and "Green" (new version). Traffic is directed to one environment. Once the Green environment is ready, traffic is switched over. This allows for instant rollback if issues arise.
In Kubernetes, this is often implemented using two Deployments and a single Service.
First, our initial Blue deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-blue
spec:
replicas: 3
selector:
matchLabels:
app: my-app
version: blue # <-- Label to distinguish
template:
metadata:
labels:
app: my-app
version: blue
spec:
containers:
- name: nginx
image: nginx:1.21.0
ports:
- containerPort: 80
And the Service pointing to the Blue version:
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app
version: blue # <-- Selector for Blue
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer
Now, to deploy the new version (Green), we create a new Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-green
spec:
replicas: 3
selector:
matchLabels:
app: my-app
version: green # <-- Label for Green
template:
metadata:
labels:
app: my-app
version: green
spec:
containers:
- name: nginx
image: nginx:1.22.0 # <-- New image
ports:
- containerPort: 80
Once my-app-green is deployed and ready, we switch traffic by updating the Service’s selector:
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app
version: green # <-- Now points to Green
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer
Rollback is as simple as changing the Service selector back to version: blue.
Canary Release
Canary releases gradually roll out new versions to a small subset of users before a full rollout. This allows for testing in production with minimal blast radius.
This is typically achieved by using multiple Deployments or a single Deployment with weighted routing via an Ingress controller or a service mesh.
Let’s use two Deployments, similar to Blue-Green, but with a twist in traffic management.
Initial Blue Deployment (same as before):
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-blue
spec:
replicas: 10 # More replicas for broader initial audience
selector:
matchLabels:
app: my-app
version: blue
template:
metadata:
labels:
app: my-app
version: blue
spec:
containers:
- name: nginx
image: nginx:1.21.0
ports:
- containerPort: 80
Canary Green Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-green-canary
spec:
replicas: 1 # Small number for initial canary
selector:
matchLabels:
app: my-app
version: green-canary
template:
metadata:
labels:
app: my-app
version: green-canary
spec:
containers:
- name: nginx
image: nginx:1.22.0
ports:
- containerPort: 80
The critical piece is how traffic is routed. You’d use an Ingress controller (like Nginx Ingress, Traefik, or HAProxy Ingress) or a service mesh (like Istio or Linkerd) to split traffic.
For example, with Nginx Ingress, you might have an Ingress resource that looks like this:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10" # 10% of traffic goes to canary
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service-blue # Service for blue
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: my-app-service-green-canary # Service for canary
port:
number: 80
---
# Service for blue
apiVersion: v1
kind: Service
metadata:
name: my-app-service-blue
spec:
selector:
app: my-app
version: blue
ports:
- protocol: TCP
port: 80
targetPort: 80
---
# Service for canary
apiVersion: v1
kind: Service
metadata:
name: my-app-service-green-canary
spec:
selector:
app: my-app
version: green-canary
ports:
- protocol: TCP
port: 80
targetPort: 80
The canary-weight: "10" annotation tells Nginx Ingress to send 10% of traffic to my-app-service-green-canary and 90% to my-app-service-blue. You monitor the canary version, and if it’s stable, you increase the weight or promote it by shifting all traffic.
The real magic of canary deployments is often hidden in the traffic management layer, which can dynamically adjust percentages, perform A/B testing, or even route specific user headers to the canary.
The next step in advanced deployment strategies is often automating the monitoring and promotion/rollback based on metrics.