Skip to content
Lucas Mauro

What is a Kubernetes Deployment?

How can a deployment help us release new versions with zero down time?

kubernetes 3 min read

A deployment is a Kubernetes object that manages the lifecycle of Pods. Rather than creating pods directly, we declare our desired state in a deployment manifest and let Kubernetes make its magic. The deployment is what ensures that the specified number of pod replicas are running at all times, handles rolling updates, and provides rollback capabilities.

If a pod managed by a deployment crashes or its node goes down, the deployment controller notices the discrepancy between the desired and actual state and recreates the pod on a healthy node.

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80

Here is what each piece means:

  • replicas tells Kubernetes how many identical copies of the pod to maintain (three in this example);
  • selector.matchLabels defines which pods this deployment owns (it matches pods with the label app: nginx);
  • template is essentially a pod definition embedded within the deployment (this is the pod that gets created and replicated);
  • The rest works just like a regular pod manifest (containers, images, ports, and so on).

One of the most valuable things a deployment gives us is zero-downtime updates. When we change the pod template (for example, bumping the image tag from 1.25 to 1.26), the deployment gradually replaces old pods with new ones rather than tearing everything down all at once.

This process follows a rolling update strategy: Kubernetes creates new pods, waits for them to become ready, and then, only then, terminates old ones. If something goes wrong during the update, Kubernetes can automatically roll back to the previous version.

We can control the update behaviour with two parameters:

  • maxSurge: the maximum number of pods that can exist above the desired count during the update;
  • maxUnavailable: the maximum number of pods that can be unavailable during the update.

Let’s have an example: setting maxSurge: 1 and maxUnavailable: 0 means that Kubernetes will create one extra pod before terminating an old one, ensuring we never go below the desired replica count. With replicas: 3, the following is what happens when we bump the image from 1.25 to 1.26:

  1. Kubernetes creates one new pod with the 1.26 image (total pods: 4);
  2. It waits for that pod to be ready (passes its readiness probe);
  3. It terminates one old 1.25 pod (total pods: 3);
  4. It creates another new 1.26 pod (total pods: 4);
  5. It waits for it to be ready;
  6. It terminates another old 1.25 pod (total pods: 3);
  7. It repeats until all pods run 1.26.

At no point would we have fewer than 3 healthy pods serving traffic, and at no point would we have more than 4. The maxUnavailable: 0 guarantees we never dip below the desired replica count, and maxSurge: 1 caps the overhead to one extra pod.

If instead we set maxUnavailable: 1 and maxSurge: 0, Kubernetes would take a different approach: it’d terminate an old pod first, then create a new one. Although this saves resources during the update, it also means we temporarily have fewer than 3 pods available. We must know what is critical and what is not to evaluate the trade-offs.

Deployments are the most common choice for stateless applications: if our application doesn’t need persistent storage or stable network identities, a deployment is almost always the right answer. However, for stateful applications such as databases, we’d look at StatefulSets instead.

Comments