What Is a Kubernetes Deployment? Rolling Updates, Rollbacks, and EKS Examples

A Kubernetes Deployment is the standard controller for running stateless applications on EKS. You describe what you want running: the container image, the number of copies, and how updates should happen. Kubernetes keeps the cluster in that state automatically.

What is a Kubernetes Deployment?

A Deployment is a Kubernetes object that describes the application you want running. Once you create one, the Deployment controller continuously compares the actual state of the cluster with your description and corrects any differences.

If a pod crashes, the controller replaces it. If a node fails and takes several pods with it, replacements are scheduled on healthy nodes. If you push a new container image, the Deployment rolls it out gradually with no downtime. If the update causes problems, you can roll back to the previous version with a single command.

Deployments are the most commonly used workload object in Kubernetes and the default way to run containerised applications on Amazon EKS. If you have created your first EKS cluster and are ready to run an application, a Deployment is almost certainly what you need.

🌡️

How to think about it

A Deployment works like a thermostat. You set the temperature you want: three replicas, this image, these resource limits. The controller watches the cluster and acts whenever reality drifts from your setting. A pod crashes? It creates a replacement. A node disappears? It reschedules the missing pods. You do not intervene. The controller keeps things at the target you defined.

A simple way to think about Deployments

If you are new to Kubernetes, think of a Deployment as a standing instruction you give to the cluster:

  • Describe the application you want running: the image, the port, the number of copies.
  • Kubernetes accepts that description and keeps the cluster in exactly that state.
  • If a pod dies, Kubernetes replaces it with no action needed from you.
  • If you update the description with a new image version, Kubernetes updates the running pods gradually so traffic is never interrupted.

The alternative is creating pods directly. Bare pods are not restarted when they crash, so they are only suitable for one-off debugging. In production, always use a Deployment.

What a Deployment does

Desired state. You specify a replica count and a pod template. The Deployment controller watches the cluster and acts whenever the actual state diverges from your definition.

Self-healing. If a pod crashes or is evicted, the controller immediately schedules a replacement. If a node goes offline, replacements appear on healthy nodes. You do not need to write restart scripts or health-check automation.

Scaling. You can change the replica count at any time with kubectl scale or by editing the manifest. You can also attach a Horizontal Pod Autoscaler to scale the replica count automatically based on CPU or custom metrics.

Rolling updates. When you update the pod template, typically by changing the container image tag, the Deployment replaces pods incrementally. New pods are started and verified before old ones are removed. Your application stays available throughout.

Rollbacks. Kubernetes keeps a history of previous Deployment versions. If an update causes problems, a single kubectl command rolls back to the previous version using the same controlled process as the original update.

How a Deployment works with Pods and ReplicaSets

A Deployment does not manage pods directly. The relationship works in layers:

  • Deployment manages one or more ReplicaSets
  • ReplicaSets manage Pods

When you create a Deployment, it creates a ReplicaSet. The ReplicaSet is responsible for keeping the right number of pods running. The Deployment wraps the ReplicaSet and adds update logic on top.

When you update a Deployment by changing the container image, the Deployment creates a new ReplicaSet for the new version and gradually scales it up. At the same time, the old ReplicaSet is scaled down. Once the update completes, the old ReplicaSet is kept at zero replicas. It is not deleted.

🏢

Think of it like a staffing handover

The Deployment is a project manager. ReplicaSets are team leads. Pods are individual workers. When the manager switches to a new team (version update), the new team lead and their workers are onboarded while the old team winds down. Once the new team is running smoothly, the old team lead sits on standby with zero workers. If anything goes wrong, the old team can be brought back immediately.

This is what makes rollbacks fast. Kubernetes scales the old ReplicaSet back up and scales the current one down. No new images to pull, no new objects to create.

Revision history limit

By default, EKS keeps the last 10 ReplicaSets per Deployment (revisionHistoryLimit: 10). Older ReplicaSets are deleted once the limit is reached. If you need to roll back further than 10 revisions, increase this value in your Deployment manifest.

kubectl get replicasets -l app=my-app

You will see one active ReplicaSet with a matching replica count, and older ReplicaSets sitting at zero.

When to use a Deployment

Deployments are the right controller for most containerised workloads:

  • Web applications: any HTTP server handling requests from users or other services
  • REST and GraphQL APIs: stateless request handlers where any pod can serve any request
  • Stateless microservices: services that do not need stable identity or per-pod persistent storage
  • Background workers: event consumers or queue processors that run continuously

If your workload does not care which specific pod served a previous request, and it does not need persistent disk storage that survives pod restarts, a Deployment is the right choice.

When not to use a Deployment

Kubernetes provides other controllers for workloads that need something a Deployment cannot offer:

StatefulSet: use this when your pods need a stable network identity (fixed hostname and DNS name), ordered startup and shutdown, or persistent storage that stays bound to a specific pod identity across restarts. Databases, Kafka brokers, and Elasticsearch nodes typically use StatefulSets.

DaemonSet: use this when you need exactly one pod running on every node in the cluster. Typical uses are log collectors, node monitoring agents, and network plugins.

Job: use this when you need to run a task to completion rather than keep it running continuously. A Job runs one or more pods until they exit successfully.

CronJob: use this when you need to run a Job on a schedule. Batch reports, data exports, and scheduled cleanup tasks typically run as CronJobs.

Deployment vs Pod vs StatefulSet

This covers the most common points of confusion for people new to Kubernetes:

PodDeploymentStatefulSet
What it isA single running container or groupA controller that manages replicated podsA controller for stateful workloads
Self-healingNo. Crashes are not recoveredYes, controller replaces failed podsYes, controller replaces failed pods
ScalingManual onlyManual or automatic (HPA)Manual or automatic
Pod identityEphemeral, random nameEphemeral, random nameStable, predictable name (pod-0, pod-1)
Persistent storagePossible but not stableNo stable storage per podYes, PVC bound to each pod identity
Rolling updatesNot supportedYes, built inYes, ordered updates
Typical useDebugging, one-offsWeb apps, APIs, microservicesDatabases, Kafka, stateful workloads

For most applications on EKS, you want a Deployment. If you are building something stateful like a database or message broker, reach for a StatefulSet instead.

Deployment YAML example

Here is a complete Deployment for a web application running three replicas on EKS:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-app
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: web-app
        version: "2.1.0"
    spec:
      containers:
      - name: web-app
        image: 123456789012.dkr.ecr.eu-west-1.amazonaws.com/web-app:2.1.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: 200m
            memory: 256Mi
          limits:
            cpu: 1000m
            memory: 512Mi
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 15

Key fields explained:

  • replicas: 3: the number of pod copies to keep running at all times.
  • selector.matchLabels: must match the labels in template.metadata.labels. This is how the Deployment identifies which pods it owns.
  • template.metadata.labels: applied to every pod this Deployment creates. Kubernetes Services use these labels to route traffic to the right pods.
  • image: the container image URI. This example pulls from ECR. Always use a specific version tag, never latest.
  • readinessProbe: Kubernetes only sends traffic to a pod once this probe passes. Without it, pods receive requests before they are ready to serve them.
  • livenessProbe: Kubernetes restarts a pod if this probe fails. Used to detect hanging processes that are running but not responding.
  • strategy.type: RollingUpdate: replace pods incrementally rather than all at once.
  • maxSurge: 1: allow one extra pod above the desired count during an update. With 3 replicas, up to 4 pods run simultaneously during the rollout.
  • maxUnavailable: 0: never reduce below the desired replica count during an update. Capacity stays at 100% throughout.
Good defaults for production

Start with maxUnavailable: 0 and maxSurge: 1. This keeps your service at full capacity during updates while adding one pod at a time. Increase maxSurge only if you want faster rollouts and have headroom in your node resource limits.

You can apply this manifest with kubectl or manage it through Helm. If your application needs secrets or credentials at runtime, see managing secrets in Kubernetes before deploying to production.

How rolling updates work

When you change the container image tag in a Deployment, the following sequence happens:

  1. Kubernetes creates a new ReplicaSet with the updated pod template.
  2. A new pod starts from the new image. Kubernetes waits for it to pass its readiness probe.
  3. Once the new pod is ready and serving traffic, one old pod is gracefully terminated.
  4. Steps 2 and 3 repeat until all pods are running the new version.
  5. The old ReplicaSet is scaled to zero but kept in history for rollback.

With maxUnavailable: 0 and maxSurge: 1, capacity temporarily rises to 4 pods during the update but never drops below 3. Traffic flows uninterrupted throughout.

🛣️

The motorway lane analogy

Think of a rolling update like resurfacing a motorway one lane at a time. Traffic keeps moving on the open lanes while one lane is being worked on. Once that lane is done, another lane closes. No full road closure, no complete stoppage. The motorway stays open from start to finish.

# Trigger an update by changing the container image
kubectl set image deployment/web-app web-app=123456789012.dkr.ecr.eu-west-1.amazonaws.com/web-app:2.2.0

# Watch the rollout progress in real time
kubectl rollout status deployment/web-app

# Check which ReplicaSets exist and their current replica counts
kubectl get replicasets -l app=web-app
Two versions run at the same time

During a rolling update, old and new pods receive live traffic simultaneously. Your API changes must be backwards-compatible. Adding a new endpoint is fine. Removing or renaming an endpoint that old pods still depend on will cause errors during the rollout window.

For more complex release strategies that let you validate changes before a full rollout, see canary deployments and blue-green deployments.

How rollbacks work

If a deployment introduces a problem, roll back immediately:

# Roll back to the previous version
kubectl rollout undo deployment/web-app

# Roll back to a specific revision number
kubectl rollout undo deployment/web-app --to-revision=2

# View rollout history to find a revision number
kubectl rollout history deployment/web-app

A rollback is itself a rolling update. Kubernetes scales up the previous ReplicaSet and scales down the current one using the same controlled process. It is fast and safe, not an emergency restart.

What counts as a revision

Rollout history only records changes to the pod template: a new image, changed environment variables, updated resource limits. Scaling the Deployment (changing the replica count) does not create a new revision. To label a change so you can identify it in history, set the kubernetes.io/change-cause annotation before applying:

kubectl annotate deployment/web-app kubernetes.io/change-cause="v2.2.0: added payment retry logic"

For visibility into rollout behaviour and pod health over time, connect EKS monitoring to your Deployment events. If you manage deployments through a CI/CD pipeline, rollbacks in CodeDeploy covers the equivalent rollback controls at the pipeline level.

RollingUpdate vs Recreate

Kubernetes supports two built-in deployment strategies:

RollingUpdate (default) replaces pods incrementally, keeping your application available throughout. Old and new pods run simultaneously for a brief window.

  • Use this for: web apps, APIs, and any service that can tolerate two versions running in parallel
  • Trade-off: API and schema changes must be backwards-compatible during the update window

Recreate terminates all existing pods before starting new ones. This causes a brief outage but guarantees only one version ever runs at a time.

  • Use this for: applications that cannot tolerate mixed-version execution, such as a worker with a breaking database schema change
  • Trade-off: your service is offline until new pods start and pass their readiness checks
# Recreate strategy - causes downtime during every deployment
strategy:
  type: Recreate
Recreate causes an outage on every deploy

For user-facing services, Recreate is almost always the wrong choice. Design your schema and API changes to be backwards-compatible so you can keep RollingUpdate and avoid planned downtime.

Common mistakes

  1. Using the latest image tag. If you deploy image: my-app:latest and push a new build without changing the tag, the pod spec looks identical to Kubernetes and no rolling update is triggered. Always use specific version tags (a commit SHA or semantic version) and update the tag to trigger a rollout.

  2. Setting maxUnavailable too high. With 3 replicas and maxUnavailable: 3, Kubernetes is allowed to terminate all 3 pods before new ones are ready, causing a complete outage. Keep maxUnavailable at 0 or 1 for production services.

  3. Missing readiness probes. Without a readiness probe, Kubernetes routes traffic to new pods the moment they start, before the application has finished initialising. This causes failed requests at the start of every rollout. Always configure a readiness probe that reflects when your application is genuinely ready to serve traffic.

  4. Confusing Deployments with Pods or StatefulSets. Creating bare pods for production workloads means they will not be restarted when they crash. Using a Deployment for a stateful workload like a database means pods can be rescheduled without their storage, risking data loss. Use the right controller for the workload type.

The mistake that causes mid-rollout data corruption

Deploying a breaking database schema change with RollingUpdate is one of the most common causes of production incidents. During the rollout, old and new pods run in parallel. If the new application version requires a schema that the old version cannot read, requests from old pods will fail until the rollout finishes. Always apply schema changes in a backwards-compatible way before deploying application code.

Frequently asked questions

What is the difference between a Deployment and a Pod?

A Pod is a single running instance of your application. A Deployment is a controller that manages a set of identical pods, keeps the right number running, replaces failed pods, and handles updates. You should almost never create pods directly in production.

What is the difference between a Deployment and a ReplicaSet?

A ReplicaSet keeps a fixed number of identical pods running. A Deployment wraps a ReplicaSet and adds update logic. When you change the pod template, the Deployment creates a new ReplicaSet for the new version and gradually shifts traffic to it. You usually interact with Deployments, not ReplicaSets directly.

Can a Kubernetes Deployment scale automatically?

Yes. You can attach a Horizontal Pod Autoscaler (HPA) to a Deployment to automatically increase or decrease the replica count based on CPU, memory, or custom metrics. The HPA adjusts the replica count field on the Deployment in real time.

How do rolling updates avoid downtime?

During a rolling update, Kubernetes starts new pods before terminating old ones. New pods must pass their readiness probe before traffic is routed to them, and old pods are only removed once new ones are healthy. With maxUnavailable set to 0, the total number of healthy pods never drops below the desired replica count.

When should I use StatefulSet instead of Deployment?

Use StatefulSet when your application requires a stable network identity, ordered pod startup and shutdown, or persistent storage that must survive pod restarts. Databases and distributed systems like Kafka typically use StatefulSets. Stateless web apps and APIs use Deployments.

Last verified: 4 April 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.