Kubernetes for DevOps Engineers: Pods, Deployments, StatefulSets, DaemonSets, Jobs, and CronJobs Made Simple
Learn the Kubernetes workload objects that matter most for DevOps engineers: Pods, Deployments, StatefulSets, DaemonSets, Jobs, and CronJobs, with simple explanations and practical examples.

Kubernetes for DevOps Engineers: Pods, Deployments, StatefulSets, DaemonSets, Jobs, and CronJobs Made Simple
Once you understand the basic Kubernetes mental model, the next step is learning the workload objects you will actually use.
This is where many beginners get confused. Kubernetes gives you several ways to run containers, and at first they can look similar.
They are not the same. Each workload object solves a different operational problem.
In this guide, we will keep things simple and practical. By the end, you should know which Kubernetes workload to choose in the most common DevOps situations.
Start With the Big Idea
In Kubernetes, your application usually runs inside a Pod, but you normally do not manage Pods directly.
Instead, you use a higher-level workload object that creates and manages Pods for you.
A simple way to think about it is this:
- Pod = the runtime unit
- Workload object = the manager of that runtime unit
That manager might keep Pods always running, create one Pod per node, preserve identity for stateful apps, or run a task only until it finishes.
The Quick Decision Guide
- Use a Deployment for a normal stateless application that should stay running.
- Use a StatefulSet for an app that needs stable identity or persistent storage.
- Use a DaemonSet when one Pod should run on every node, or on a selected set of nodes.
- Use a Job for a task that should run once and finish.
- Use a CronJob for a task that should run on a schedule.
- Use a plain Pod mainly for testing, learning, or very special cases.
Pod: The Smallest Unit, Not Usually the Best Starting Point
A Pod is the smallest deployable unit in Kubernetes. It can contain one container or multiple tightly coupled containers that share networking and storage.
In most real applications, you should not create Pods directly. A Pod is designed to be fairly disposable, and Kubernetes usually expects a controller to recreate it when needed.
So yes, Pods matter a lot. But in normal day-to-day work, you usually create a Deployment, Job, DaemonSet, or StatefulSet and let that controller manage the Pods for you.
Simple Pod Example
apiVersion: v1
kind: Pod
metadata:
name: simple-nginx
spec:
containers:
- name: nginx
image: nginx:stable
ports:
- containerPort: 80
This works, but it is not usually how you should run a real application.
Deployment: The Default Choice for Most Applications
A Deployment is the workload object you will use most often. It is the normal choice for stateless applications such as web apps, APIs, and internal services.
It manages Pods for you and supports scaling, rolling updates, and rollbacks.
If your application should always be up and does not need a stable identity for each replica, start with a Deployment.
Use a Deployment When
- your app should always be running
- you want multiple identical replicas
- you want easy rollouts and rollbacks
- your replicas are interchangeable
Simple Deployment Example
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-api
spec:
replicas: 3
selector:
matchLabels:
app: demo-api
template:
metadata:
labels:
app: demo-api
spec:
containers:
- name: api
image: nginx:stable
ports:
- containerPort: 80
Useful commands:
kubectl apply -f deployment.yaml
kubectl get deployments
kubectl get pods
kubectl rollout status deployment/demo-api
kubectl rollout history deployment/demo-api
StatefulSet: For Apps That Need Stable Identity
A StatefulSet is for stateful workloads. This means applications where each Pod is not just another identical replica.
Each Pod in a StatefulSet keeps a stable identity. That can include a stable name, stable network identity, and stable persistent storage.
This matters for systems such as databases, brokers, and clustered services that need predictable identities and storage attached to the right instance.
Use a StatefulSet When
- the app needs persistent storage
- each replica needs its own identity
- ordering matters during startup, scaling, or updates
- your replicas are not interchangeable
Simple StatefulSet Example
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: demo-db
spec:
serviceName: demo-db
replicas: 2
selector:
matchLabels:
app: demo-db
template:
metadata:
labels:
app: demo-db
spec:
containers:
- name: db
image: nginx:stable
ports:
- containerPort: 80
This example is intentionally simple. In real life, StatefulSets are usually paired with persistent volume claims and a headless Service.
DaemonSet: One Pod Per Node
A DaemonSet ensures that a Pod runs on all matching nodes, or on a selected subset of nodes.
This is not usually for your application itself. It is often for cluster-level helpers such as log collectors, monitoring agents, node exporters, or storage and networking helpers.
If you need exactly one copy of something on every node, think DaemonSet.
Use a DaemonSet When
- you need one Pod on every node
- you are deploying node-level monitoring
- you are deploying log collection
- you are deploying node-local platform agents
Simple DaemonSet Example
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: demo-agent
spec:
selector:
matchLabels:
app: demo-agent
template:
metadata:
labels:
app: demo-agent
spec:
containers:
- name: agent
image: nginx:stable
Job: Run Once and Finish
A Job is for work that should complete and then stop.
Unlike a Deployment, the goal is not to keep the Pod running forever. The goal is to finish the task successfully.
This makes Jobs a good fit for database migrations, data imports, report generation, and batch processing.
Use a Job When
- the task has a clear end
- you want Kubernetes to retry if it fails
- you are running migrations or batch work
Simple Job Example
apiVersion: batch/v1
kind: Job
metadata:
name: demo-job
spec:
template:
spec:
restartPolicy: Never
containers:
- name: hello
image: busybox
command: ["sh", "-c", "echo Hello from a Job"]
Useful commands:
kubectl apply -f job.yaml
kubectl get jobs
kubectl get pods
kubectl logs job/demo-job
CronJob: Run on a Schedule
A CronJob is for tasks that should run repeatedly on a schedule.
Under the hood, a CronJob creates Jobs according to a cron-style schedule.
Common examples include backups, cleanup tasks, scheduled exports, and periodic reports.
Use a CronJob When
- the task should run every hour, every night, or on another schedule
- the task should still behave like a Job and finish
- you want Kubernetes to manage the scheduling
Simple CronJob Example
apiVersion: batch/v1
kind: CronJob
metadata:
name: demo-backup
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
restartPolicy: Never
containers:
- name: backup
image: busybox
command: ["sh", "-c", "echo Running scheduled backup"]
A Simple Way to Remember All of Them
- Pod: the basic runtime unit
- Deployment: keep stateless app replicas running
- StatefulSet: keep stateful app identity stable
- DaemonSet: run one Pod per node
- Job: run once until completion
- CronJob: run Jobs on a schedule
Common Beginner Mistakes
Using a Pod for a Real Application
This is one of the most common mistakes. A plain Pod may run fine at first, but it does not give you the safe management features you usually want in production.
Using a Deployment for Everything
Deployments are the default for many apps, but they are not right for stateful services, scheduled tasks, or one-per-node agents.
Treating Stateful Apps Like Stateless Apps
Databases and clustered stateful systems often need stable identity and storage. That is exactly where StatefulSet becomes important.
Forgetting That Jobs End on Purpose
A finished Job is usually success, not failure. Do not troubleshoot a completed Job as if it were a crashed long-running service.
What a DevOps Engineer Must Remember
- Pods are the basic runtime unit, but you usually should not create them directly for normal applications.
- Deployments are the default choice for stateless apps that should keep running.
- StatefulSets are for apps that need stable identity or persistent storage.
- DaemonSets are for node-level agents and one-per-node workloads.
- Jobs are for one-time tasks that must finish.
- CronJobs are for scheduled tasks that create Jobs repeatedly.
Final Thought
Kubernetes gives you several workload objects, but the decision becomes much easier once you focus on the job each one is meant to do.
Ask yourself one question first:
Should this workload keep running forever, keep a stable identity, run once, or run on a schedule?
If you answer that clearly, you will usually pick the right Kubernetes object.