Kubernetes Workloads

The workload resources that run your applications - from single Pods to replicated Deployments, stateful databases, and batch Jobs.

1. Pods

A Pod is the smallest deployable unit in Kubernetes. It wraps one or more containers that share a network namespace (one IP), IPC, and optionally volumes. Most production apps run inside Deployments, but understanding Pods is essential.

┌─────────────────────────────────────────────┐
│  Pod  10.244.1.8                            │
│  ┌─────────────┐  ┌─────────────┐          │
│  │  app        │  │  sidecar    │          │
│  │  :8080      │  │  (logging)  │          │
│  └─────────────┘  └─────────────┘          │
│  shared: localhost, volumes, hostname       │
└─────────────────────────────────────────────┘

Single-container Pod

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
    - name: nginx
      image: nginx:1.25
      ports:
        - containerPort: 80
      resources:
        requests:
          cpu: 100m
          memory: 128Mi
        limits:
          cpu: 500m
          memory: 256Mi

Multi-container Pod (sidecar pattern)

apiVersion: v1
kind: Pod
metadata:
  name: app-with-logger
spec:
  containers:
    - name: app
      image: myapp:1.0
      volumeMounts:
        - name: logs
          mountPath: /var/log/app
    - name: log-shipper
      image: fluent/fluent-bit:2.2
      volumeMounts:
        - name: logs
          mountPath: /var/log/app
          readOnly: true
  volumes:
    - name: logs
      emptyDir: {}

Pod lifecycle phases

PhaseMeaning
PendingAccepted but not yet running (scheduling, image pull)
RunningAt least one container is running
SucceededAll containers terminated successfully (Jobs)
FailedAt least one container failed
UnknownNode communication lost
Do not manage Pods directly in production. Pods are ephemeral. Use a controller (Deployment, StatefulSet, Job) so Kubernetes recreates them when nodes fail or updates roll out.

2. ReplicaSets

A ReplicaSet maintains a stable set of Pod replicas. It creates or deletes Pods to match spec.replicas and uses a label selector to identify managed Pods.

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: api-rs
  labels:
    app: api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api
      tier: backend
  template:
    metadata:
      labels:
        app: api
        tier: backend
    spec:
      containers:
        - name: api
          image: myregistry/api:1.0.0
          ports:
            - containerPort: 8080

You rarely create ReplicaSets directly. Deployments own ReplicaSets and handle rolling updates. ReplicaSets remain the mechanism underneath.

kubectl get rs
kubectl describe rs api-rs
# Pods owned by ReplicaSet show ownerReferences in metadata

3. Deployments

A Deployment is the standard way to run stateless applications. It manages ReplicaSets and supports declarative updates, rollbacks, and scaling.

Basic Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: production
spec:
  replicas: 3
  revisionHistoryLimit: 5
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: myregistry/api:2.0.0
          ports:
            - containerPort: 8080

Rolling update strategy

spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # extra Pods above desired count during update
      maxUnavailable: 0  # zero-downtime: always keep full capacity
  minReadySeconds: 10
# Rollout commands
kubectl set image deployment/api api=myregistry/api:2.1.0
kubectl rollout status deployment/api
kubectl rollout history deployment/api
kubectl rollout undo deployment/api
kubectl rollout undo deployment/api --to-revision=2

Recreate strategy (brief downtime)

spec:
  strategy:
    type: Recreate   # kill all old Pods, then start new ones

Deployment revision diagram

Deployment "api" (desired: 3 replicas, image v2)
    │
    ├── ReplicaSet api-7d4f8b (rev 2, image v2)  ← active, 3 Pods
    └── ReplicaSet api-9a2c1e (rev 1, image v1)  ← scaled to 0, kept for rollback

4. StatefulSets

StatefulSets manage stateful applications with stable network identities, ordered deployment, and persistent storage per replica. Use for databases, Kafka, ZooKeeper, Elasticsearch.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres          # headless Service required
  replicas: 3
  podManagementPolicy: OrderedReady
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:16
          ports:
            - containerPort: 5432
          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: gp3
        resources:
          requests:
            storage: 50Gi
# Headless Service for StatefulSet DNS
apiVersion: v1
kind: Service
metadata:
  name: postgres
spec:
  clusterIP: None
  selector:
    app: postgres
  ports:
    - port: 5432
Deleting a StatefulSet does not delete PVCs by default. Use kubectl delete statefulset postgres --cascade=orphan carefully, or delete PVCs explicitly when decommissioning data.

5. DaemonSets

A DaemonSet ensures one Pod copy runs on every node (or a subset via node selectors). Used for node-level agents: log collectors, monitoring, CNI plugins, storage drivers.

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: node-exporter
  template:
    metadata:
      labels:
        app: node-exporter
    spec:
      tolerations:
        - operator: Exists   # run on tainted nodes too
      containers:
        - name: exporter
          image: prom/node-exporter:v1.7
          ports:
            - containerPort: 9100
          resources:
            requests:
              cpu: 50m
              memory: 64Mi
┌──────────┐  ┌──────────┐  ┌──────────┐
│  Node 1  │  │  Node 2  │  │  Node 3  │
│ ┌──────┐ │  │ ┌──────┐ │  │ ┌──────┐ │
│ │ DS   │ │  │ │ DS   │ │  │ │ DS   │ │
│ │ Pod  │ │  │ │ Pod  │ │  │ │ Pod  │ │
│ └──────┘ │  │ └──────┘ │  │ └──────┘ │
└──────────┘  └──────────┘  └──────────┘
  one DaemonSet Pod per eligible node

6. Jobs & CronJobs

Jobs run Pods to completion (batch, one-off tasks). CronJobs create Jobs on a schedule.

Job

apiVersion: batch/v1
kind: Job
metadata:
  name: db-migrate
spec:
  backoffLimit: 3
  activeDeadlineSeconds: 600
  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - name: migrate
          image: myregistry/api:2.0.0
          command: ["python", "manage.py", "migrate"]

Parallel Job (work queue)

spec:
  completions: 10      # 10 successful Pod completions required
  parallelism: 3       # run 3 Pods at a time
  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - name: worker
          image: batch-worker:latest

CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: nightly-backup
spec:
  schedule: "0 2 * * *"    # 02:00 UTC daily
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 1
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: backup
              image: backup-tool:1.0
              args: ["--target", "s3://backups/prod"]
kubectl get jobs
kubectl get cronjobs
kubectl create job manual-backup --from=cronjob/nightly-backup

7. Probes

Probes tell kubelet whether a container is alive, ready to receive traffic, or still starting up. Misconfigured probes are a top cause of CrashLoopBackOff and flapping Deployments.

ProbePurposeFailure action
LivenessIs the process healthy?Restart the container
ReadinessCan it serve traffic?Remove from Service endpoints
StartupHas it finished booting?Disable liveness until success; restart if fail

HTTP probes

spec:
  containers:
    - name: api
      image: myregistry/api:2.0.0
      ports:
        - containerPort: 8080
      startupProbe:
        httpGet:
          path: /healthz
          port: 8080
        failureThreshold: 30
        periodSeconds: 10          # up to 300s startup time
      livenessProbe:
        httpGet:
          path: /healthz
          port: 8080
        initialDelaySeconds: 0
        periodSeconds: 10
        failureThreshold: 3
      readinessProbe:
        httpGet:
          path: /ready
          port: 8080
        periodSeconds: 5
        failureThreshold: 2

TCP and exec probes

      livenessProbe:
        tcpSocket:
          port: 5432
        periodSeconds: 15

      readinessProbe:
        exec:
          command:
            - pg_isready
            - -U
            - postgres
        periodSeconds: 10
Use startup probes for slow-starting apps. Without them, a long initialDelaySeconds on liveness delays crash detection. Startup probes protect the container during boot.

8. Horizontal Pod Autoscaler (HPA)

The HPA automatically scales Deployment (or StatefulSet) replicas based on observed metrics. Requires metrics-server (CPU/memory) or custom/external metrics (Prometheus adapter).

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-hpa
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api
  minReplicas: 2
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80

Custom metric (requests per second)

  metrics:
    - type: Pods
      pods:
        metric:
          name: http_requests_per_second
        target:
          type: AverageValue
          averageValue: "1000"

Scaling behaviour

  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Percent
          value: 10
          periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
        - type: Pods
          value: 4
          periodSeconds: 60
kubectl get hpa
kubectl describe hpa api-hpa
kubectl top pods -n production

HPA changes replica count; Cluster Autoscaler adds nodes when pending Pods cannot be scheduled. Together they scale the workload and the infrastructure.

9. Resource Requests & Limits

Every container should declare requests (used for scheduling) and limits (maximum allowed). Without requests, the scheduler cannot place Pods intelligently; without limits, one Pod can starve others.

FieldEffect
requests.cpuScheduler reserves this CPU on a node
limits.cpuThrottled via CFS quota when exceeded
requests.memoryScheduler reserves this memory
limits.memoryOOMKilled if exceeded

CPU and memory units

Example container resources

spec:
  containers:
    - name: api
      image: myregistry/api:2.0.0
      resources:
        requests:
          cpu: 250m
          memory: 256Mi
        limits:
          cpu: "1"
          memory: 512Mi

QoS classes

QoSConditionEviction priority
Guaranteedlimits = requests for all containersLast evicted
BurstableAt least one request or limit setMiddle
BestEffortNo requests or limitsFirst evicted

LimitRange and ResourceQuota

# Namespace default for containers without resources
apiVersion: v1
kind: LimitRange
metadata:
  name: defaults
  namespace: production
spec:
  limits:
    - type: Container
      default:
        cpu: 500m
        memory: 256Mi
      defaultRequest:
        cpu: 100m
        memory: 128Mi
      max:
        cpu: "4"
        memory: 4Gi
# Cap total namespace consumption
apiVersion: v1
kind: ResourceQuota
metadata:
  name: prod-quota
  namespace: production
spec:
  hard:
    requests.cpu: "20"
    requests.memory: 40Gi
    limits.cpu: "40"
    pods: "50"

10. Cheat Sheet

TaskCommand
List Deploymentskubectl get deploy -A
Scale Deploymentkubectl scale deploy/api --replicas=5
Rollout undokubectl rollout undo deploy/api
StatefulSet Podskubectl get pods -l app=postgres
Run one-off Jobkubectl create job test --image=busybox -- echo hi
CronJob schedulekubectl get cronjobs
Check probeskubectl describe pod <name> | grep -A5 Liveness
HPA statuskubectl get hpa
Pod resource usagekubectl top pods
QoS classkubectl get pod <name> -o jsonpath='{.status.qosClass}'

Full cheat sheet: kubectl Cheat Sheet