StatefulSets, DaemonSets & Jobs

25 minLesson 7 of 8

Learning Objectives

  • Deploy databases with StatefulSets
  • Run node-level agents with DaemonSets
  • Execute batch workloads with Jobs and CronJobs
  • Choose the right controller for each workload

Workload Controllers Overview

ControllerUse CasePod IdentityScaling
DeploymentStateless appsInterchangeableHorizontal
StatefulSetDatabases, queuesStable, orderedOrdered
DaemonSetNode agentsOne per nodePer node
JobBatch tasksTemporaryParallelism
CronJobScheduled tasksTemporaryOn schedule

StatefulSets

StatefulSets manage stateful applications that need:

  • Stable network identities
  • Persistent storage per pod
  • Ordered deployment and scaling

StatefulSet vs Deployment

FeatureDeploymentStatefulSet
Pod namesRandom (app-7d9f8-abc12)Ordered (app-0, app-1, app-2)
StorageShared or noneDedicated PVC per pod
ScalingAny orderSequential (0→1→2)
DeletionAny orderReverse (2→1→0)
DNSVia Service onlyIndividual pod DNS

PostgreSQL StatefulSet

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres
  replicas: 3
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:16
        ports:
        - containerPort: 5432
        env:
        - name: POSTGRES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: pg-secret
              key: password
        - name: PGDATA
          value: /var/lib/postgresql/data/pgdata
        volumeMounts:
        - name: postgres-data
          mountPath: /var/lib/postgresql/data
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
  volumeClaimTemplates:
  - metadata:
      name: postgres-data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 10Gi
---
# Headless service for StatefulSet DNS
apiVersion: v1
kind: Service
metadata:
  name: postgres
spec:
  clusterIP: None
  selector:
    app: postgres
  ports:
  - port: 5432

Pod DNS entries:

  • postgres-0.postgres.default.svc.cluster.local
  • postgres-1.postgres.default.svc.cluster.local
  • postgres-2.postgres.default.svc.cluster.local

DaemonSets

DaemonSets ensure one pod runs on every (or selected) node. Perfect for:

  • Log collectors (Fluentd, Filebeat)
  • Monitoring agents (Node Exporter, Datadog)
  • Network plugins (Calico, Cilium)
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: node-exporter
  template:
    metadata:
      labels:
        app: node-exporter
    spec:
      hostNetwork: true
      containers:
      - name: node-exporter
        image: prom/node-exporter:latest
        ports:
        - containerPort: 9100
          hostPort: 9100
        volumeMounts:
        - name: proc
          mountPath: /host/proc
          readOnly: true
        - name: sys
          mountPath: /host/sys
          readOnly: true
      volumes:
      - name: proc
        hostPath:
          path: /proc
      - name: sys
        hostPath:
          path: /sys
      tolerations:
      - operator: Exists  # Run on ALL nodes including masters

Node Selection

spec:
  template:
    spec:
      nodeSelector:
        node-type: worker    # Only on worker nodes
      # Or use affinity for more control
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/os
                operator: In
                values: ["linux"]

Jobs

Jobs run tasks to completion (batch processing, migrations, backups).

apiVersion: batch/v1
kind: Job
metadata:
  name: db-migration
spec:
  backoffLimit: 3          # Retry up to 3 times
  activeDeadlineSeconds: 600  # Timeout after 10 min
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: migrate
        image: nextgen-app:1.0
        command: ["npm", "run", "migrate"]
        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: db-secret
              key: url

Parallel Jobs

apiVersion: batch/v1
kind: Job
metadata:
  name: batch-processor
spec:
  completions: 10      # Total tasks to complete
  parallelism: 3       # Run 3 pods at a time
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: worker
        image: batch-worker:1.0

CronJobs

apiVersion: batch/v1
kind: CronJob
metadata:
  name: nightly-backup
spec:
  schedule: "0 2 * * *"    # 2 AM daily
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 3
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
          - name: backup
            image: backup-tool:1.0
            command: ["/bin/sh", "-c", "backup.sh && upload-to-s3.sh"]
Concurrency PolicyBehavior
AllowMultiple jobs can run simultaneously
ForbidSkip new job if previous still running
ReplaceCancel running job, start new one

Managing Workloads

# StatefulSets
kubectl get statefulsets
kubectl scale statefulset postgres --replicas=5
kubectl rollout status statefulset postgres
 
# DaemonSets
kubectl get daemonsets -A
kubectl rollout status daemonset node-exporter -n monitoring
 
# Jobs
kubectl get jobs
kubectl describe job db-migration
kubectl logs job/db-migration
 
# CronJobs
kubectl get cronjobs
kubectl create job --from=cronjob/nightly-backup manual-backup

Summary

You've learned:

  • StatefulSets for databases with stable identity and storage
  • DaemonSets for node-level agents and monitoring
  • Jobs for batch processing and one-time tasks
  • CronJobs for scheduled automation
  • Choosing the right controller for each workload type

Next Steps

Next, we'll cover Kubernetes troubleshooting, resource management, and production best practices.