Intermediate

Managing Kubernetes Controllers and Deployments

Deploy and maintain apps with Deployments, DaemonSets, Jobs, CronJobs and StatefulSets.

Prerequisites: Linux CLI, TCP/IP, basic knowledge of containers and Kubernetes


Table of Contents


1. Course Overview

This course covers all Kubernetes controllers used to deploy and manage workloads in production:

  1. Introduction to controllers: understand what they are and how they maintain desired state
  2. The Deployment controller: the main mechanism for deploying, updating, rolling back, and scaling applications
  3. Additional controllers: DaemonSet, Job, CronJob, and StatefulSet for specialized workloads

Lab Environment

NodeRoleOSvCPURAM
c1-cp1Control PlaneUbuntu 22.0422 GB
c1-node1WorkerUbuntu 22.0422 GB
c1-node2WorkerUbuntu 22.0422 GB
c1-node3WorkerUbuntu 22.0422 GB

2. Using Controllers to Deploy Applications — Deployment Basics

2.1 Kubernetes Core Principles

  1. Desired State & Declarative Configuration: describe the desired application state in code (YAML), and Kubernetes converges toward that state
  2. Controllers: monitor the current cluster state and make the necessary changes to reach desired state
  3. API Server: the cluster information center — all interactions go through it

2.2 The Controller Manager

Controller ManagerRole
kube-controller-managerNative cluster controllers (Deployment, ReplicaSet, DaemonSet, Job, etc.) — runs on the control plane
cloud-controller-managerCloud infrastructure integration (load balancers, storage, nodes)

The controller manager implements watch loops:

Watch Loop:
  1. Observe  → read current state from API server
  2. Diff     → compare with desired state
  3. Act      → make changes if needed

2.3 Main Controllers Overview

graph TD
    A[Controller Manager] --> B[Deployment]
    A --> C[StatefulSet]
    A --> D[DaemonSet]
    A --> E[Job]
    A --> F[CronJob]
    B --> G[ReplicaSet]
    G --> H[Pod]
    C --> I[Pod with stable identity]
    D --> J[Pod per node]
    E --> K[Single completion Pod]
    F --> L[Scheduled Job]
ControllerShort Description
DeploymentDeclarative deployment with rolling updates and rollback
StatefulSetStateful applications with persistent naming and stable storage
DaemonSetOne Pod per node (or subset of nodes)
JobTask run to completion
CronJobJob scheduled on a cron schedule
ReplicaSetMaintains a number of Pod replicas (managed by Deployment)

2.4 The Deployment Controller — Basics

The Deployment is the primary mechanism for deploying stateless applications. It provides:

  • Declarative updates of ReplicaSets and their Pods
  • Orchestrated creation and deletion of Pods
  • Rollout management (new versions) with configurable update strategy
  • Rollback to a previous version
  • Scaling manual or automatic (HPA)
SectionDescription
selectorLabels to identify Pods belonging to the Deployment
replicasDesired Pod count
templatePod specification (image, ports, probes, etc.)
strategyUpdate strategy (RollingUpdate or Recreate)

2.5 The ReplicaSet Controller

Deploys a defined number of Pods and ensures that number stays constant, even during failures.

Behavior during failure:

  1. A Pod disappears (crash, dead node, manual deletion)
  2. ReplicaSet controller detects fewer Pods matching the selector than desired
  3. Creates a new Pod to reach the desired state

Best practice: Never create ReplicaSets directly. Always use Deployments which manage ReplicaSets automatically.

2.6 Demos — Deployment and ReplicaSet

# Create a deployment imperatively
kubectl create deployment hello-world --image=my-registry/hello-app:1.0

# Scale to 5 replicas
kubectl scale deployment hello-world --replicas=5

# Create with image AND replicas in one command
kubectl create deployment hello-world --image=my-registry/hello-app:1.0 --replicas=5

# Apply declaratively
kubectl apply -f deployment.yaml

# Inspect resources
kubectl get replicasets
kubectl describe replicaset hello-world-<hash>

# View Pods with their labels
kubectl get pods --show-labels

# Isolate a Pod by changing its label
kubectl label pod <pod-name> app=DEBUG --overwrite

3. Maintaining Applications with Deployments

3.1 Updating a Deployment

An update is triggered by any change in the Pod template (spec.template):

  • Container image change (most common)
  • Environment variables, secrets, resources, restart policy

Important: Modifying replicas count does not trigger a rollout.

Rolling update process:

  1. Creates a new ReplicaSet with the new configuration
  2. Scales up the new ReplicaSet progressively
  3. Scales down the old ReplicaSet progressively
  4. Old ReplicaSet remains at 0 replicas (for rollback)
kubectl rollout status deployment hello-world
kubectl rollout history deployment hello-world
kubectl rollout history deployment hello-world --revision=2

3.2 Controlling Rollouts — UpdateStrategy

StrategyBehavior
RollingUpdateProgressive transition between old and new ReplicaSet. Default strategy.
RecreateStops all old Pods before starting new ones. Causes downtime, but useful when two versions can’t coexist.

RollingUpdate Parameters:

ParameterDescriptionDefault
maxUnavailableMax Pods that can be unavailable during update (int or %)25%
maxSurgeMax extra Pods that can exist during update (int or %)25%

Other control fields:

FieldDescription
progressDeadlineSecondsIf rollout doesn’t progress within this time, it’s marked as failed
revisionHistoryLimitNumber of ReplicaSets kept to enable rollbacks (default: 10)
minReadySecondsMinimum time a Pod must be Ready before considered available

3.3 Readiness Probes and Controlled Rollouts

A Readiness Probe tells Kubernetes whether a Pod is ready to receive traffic.

With a Readiness Probe, the Deployment halts the rollout if the number of Pods failing the probe drops below maxUnavailable. This protects the application by keeping old Pods active during updates.

ParameterDescription
initialDelaySecondsDelay before first check (for slow-starting apps)
periodSecondsInterval between checks
failureThresholdConsecutive failures before marking Pod as non-ready

3.4 Pause, Resume, and Rollback

# Pause an ongoing rollout
kubectl rollout pause deployment hello-world

# Resume rollout after modifications
kubectl rollout resume deployment hello-world

# Roll back to previous version
kubectl rollout undo deployment hello-world

# Roll back to a specific revision
kubectl rollout undo deployment hello-world --to-revision=1

# Restart a Deployment
kubectl rollout restart deployment hello-world

3.5 Scaling Deployments

# Manual scaling
kubectl scale deployment hello-world --replicas=10

# Autoscaling (HPA)
kubectl autoscale deployment hello-world --min=2 --max=10 --cpu-percent=80

4. DaemonSets, Jobs, CronJobs, and StatefulSets

4.1 DaemonSets

Guarantees one Pod copy runs on each node (or subset of nodes).

Typical use cases:

WorkloadDescription
kube-proxyNetworking — present in all Kubernetes clusters
Log agents (Fluentd, Filebeat)Log collection on each node
Monitoring agents (Prometheus Node Exporter)System metrics per node
Security agentsScanning, intrusion detection
CNI network pluginsCalico-node, Cilium, etc.

Update strategies:

StrategyBehavior
RollingUpdateOld Pods are terminated and replaced automatically. Default.
OnDeleteNew Pods are only created when you manually delete old ones. Full control.
# Label a node to enable selective DaemonSet deployment
kubectl label node c1-node1 node=hello-world-ns

kubectl get daemonsets -o wide
kubectl describe daemonset hello-world-ds

4.2 Jobs

Creates one or more Pods and ensures a specified number of them complete successfully.

Key parameters:

ParameterDescription
completionsTotal successful completions required (default: 1)
parallelismMax Pods running in parallel simultaneously
backoffLimitAttempts before marking Job as failed (default: 6)
restartPolicyMust be Never or OnFailure (never Always for a Job)
activeDeadlineSecondsMaximum Job execution time before cancellation
restartPolicyFailure behavior
NeverCreates new Pod on each failure (up to backoffLimit)
OnFailureRestarts container in same Pod (up to backoffLimit)
kubectl get jobs
kubectl describe job hello-world-job
kubectl get pods --selector=job-name=hello-world-job
kubectl logs <pod-name>

4.3 CronJobs

Creates Job resources at regular intervals using UNIX cron format.

Schedule format: "* * * * *" → minute, hour, day of month, month, day of week

ScheduleMeaning
"*/1 * * * *"Every minute
"0 * * * *"Every hour on the hour
"0 2 * * *"Daily at 2:00 AM
"0 0 * * 0"Sundays at midnight

concurrencyPolicy:

ValueBehavior
AllowMultiple runs can run in parallel
ForbidIf a run is in progress, the next is skipped
ReplaceIf a run is in progress, it’s cancelled and replaced by the new one
kubectl get cronjobs
kubectl describe cronjob hello-world-cron
kubectl get jobs --watch

4.4 StatefulSets — Conceptual Introduction

Manages stateful applications where Pods need persistent identities:

  1. Ordered and persistent naming: Pods are named <name>-0, <name>-1, etc. — reused on redeploy
  2. Persistent storage: via PersistentVolumeClaims stably attached to each Pod via volumeClaimTemplates
  3. Headless Service: no ClusterIP or load balancer, enabling stateful apps to locate each other via DNS

Use cases: Databases (MongoDB, MySQL, PostgreSQL), cache servers (Redis cluster), messaging systems (Kafka, ZooKeeper)

Ordered operations:

  • Scale up: Pods created in order (0, 1, 2…)
  • Scale down: Pods deleted in reverse order (N, N-1…)
  • Updates: applied in reverse order (newest to oldest)

5. Reference Diagrams

5.1 Controller Hierarchy

graph TD
    CM["Controller Manager"]

    CM --> DEP["Deployment\nStateless apps"]
    CM --> SS["StatefulSet\nStateful apps"]
    CM --> DS["DaemonSet\nAgent per node"]
    CM --> JOB["Job\nSingle completion task"]
    CM --> CJ["CronJob\nScheduled task"]

    DEP --> RS["ReplicaSet\nManages Pod count"]
    RS --> P1["Pod"]
    RS --> P2["Pod"]
    RS --> P3["Pod"]

    SS --> SP1["Pod-0\n(stable identity)"]
    SS --> SP2["Pod-1\n(stable identity)"]

    DS --> DP1["Pod\n(node 1)"]
    DS --> DP2["Pod\n(node 2)"]

    JOB --> JP["Pod\n(run to completion)"]
    CJ --> JOB2["Job\n(created per schedule)"]
    JOB2 --> JP2["Pod"]

5.2 Reconciliation Flow

sequenceDiagram
    participant Admin as Admin
    participant API as API Server
    participant ETCD as etcd
    participant CM as Controller Manager
    participant SCH as Scheduler
    participant NODE as Node / kubelet

    Admin->>API: kubectl apply -f deployment.yaml
    API->>ETCD: Persists Deployment object
    CM->>API: Watch → detects new Deployment
    CM->>API: Creates ReplicaSet
    CM->>API: Creates N Pod objects
    SCH->>API: Watch → detects unscheduled Pods
    SCH->>API: Assigns each Pod to a node
    NODE->>API: Watch → detects assigned Pods
    NODE->>NODE: Pull image + start container
    NODE->>API: Updates Pod status (Running/Ready)

5.3 Rolling Update — Transition Flow

graph LR
    subgraph "Initial State — v1.0"
        RS1["ReplicaSet-v1\n(10 replicas)"]
    end

    UPDATE["kubectl apply\n(image: v2.0)"] --> TRANS

    subgraph "Transition"
        TRANS["Deployment Controller"]
        TRANS --> RS2["ReplicaSet-v2\n(scale up)"]
        TRANS --> RS1B["ReplicaSet-v1\n(scale down)"]
    end

    subgraph "Final State — v2.0"
        RS3["ReplicaSet-v2\n(10 replicas)"]
        RS0["ReplicaSet-v1\n(0 replicas — kept for rollback)"]
    end

6. Reference YAML Snippets

6.1 Basic Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-world
spec:
  replicas: 5
  selector:
    matchLabels:
      app: hello-world
  template:
    metadata:
      labels:
        app: hello-world
    spec:
      containers:
      - name: hello-world
        image: my-registry/hello-app:1.0
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: hello-world
spec:
  selector:
    app: hello-world
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080

6.2 Deployment with RollingUpdate and Readiness Probe

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-world
spec:
  replicas: 20
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 10%
      maxSurge: 2
  revisionHistoryLimit: 20
  selector:
    matchLabels:
      app: hello-world
  template:
    metadata:
      labels:
        app: hello-world
    spec:
      containers:
      - name: hello-world
        image: my-registry/hello-app:1.0
        ports:
        - containerPort: 8080
        readinessProbe:
          httpGet:
            path: /index.html
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 10

6.3 DaemonSet on All Nodes

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: hello-world-ds
spec:
  selector:
    matchLabels:
      app: hello-world-app
  template:
    metadata:
      labels:
        app: hello-world-app
    spec:
      containers:
        - name: hello-world
          image: my-registry/hello-app:1.0

6.4 DaemonSet with NodeSelector

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: hello-world-ds
spec:
  selector:
    matchLabels:
      app: hello-world-app
  template:
    metadata:
      labels:
        app: hello-world-app
    spec:
      nodeSelector:
        node: hello-world-ns
      containers:
        - name: hello-world
          image: my-registry/hello-app:1.0

6.5 Simple Job

apiVersion: batch/v1
kind: Job
metadata:
  name: hello-world-job
spec:
  template:
    spec:
      containers:
      - name: ubuntu
        image: ubuntu
        command:
         - "/bin/bash"
         - "-c"
         - "/bin/echo Hello from Pod $(hostname) at $(date)"
      restartPolicy: Never

6.6 Parallel Job

apiVersion: batch/v1
kind: Job
metadata:
  name: hello-world-job-parallel
spec:
  completions: 50
  parallelism: 10
  template:
    spec:
      containers:
      - name: ubuntu
        image: ubuntu
        command:
         - "/bin/bash"
         - "-c"
         - "/bin/echo Hello from Pod $(hostname) at $(date)"
      restartPolicy: Never

6.7 CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: hello-world-cron
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: ubuntu
            image: ubuntu
            command:
            - "/bin/bash"
            - "-c"
            - "/bin/echo Hello from Pod $(hostname) at $(date)"
          restartPolicy: Never

6.8 StatefulSet (MongoDB)

apiVersion: v1
kind: Service
metadata:
  name: mongo
spec:
  clusterIP: None   # Headless service
  selector:
    app: mongo
  ports:
  - port: 27017
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongo
spec:
  selector:
    matchLabels:
      app: mongo
  serviceName: "mongo"
  replicas: 3
  template:
    metadata:
      labels:
        app: mongo
    spec:
      containers:
      - name: mongo
        image: mongo:6
        ports:
        - containerPort: 27017
        volumeMounts:
        - name: data
          mountPath: /data/db
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 1Gi

7. Controller Reference Tables

ControllerTypePod restart after completionScalingTypical use case
DeploymentStatelessYes (Always)Yes (replicas)Web apps, APIs
StatefulSetStatefulYesYes (ordered)Databases, queues
DaemonSetPer-nodeYesAutomatic (1/node)Agents, plugins
JobOne-shotNocompletions + parallelismMigrations, processing
CronJobScheduledNoN/ABackups, exports

8. Essential kubectl Commands

Deployments

kubectl create deployment <name> --image=<image>
kubectl apply -f deployment.yaml
kubectl get deployments
kubectl describe deployment <name>
kubectl scale deployment <name> --replicas=<n>
kubectl rollout status deployment <name>
kubectl rollout history deployment <name>
kubectl rollout undo deployment <name>
kubectl rollout undo deployment <name> --to-revision=<n>
kubectl rollout pause deployment <name>
kubectl rollout resume deployment <name>
kubectl rollout restart deployment <name>
kubectl delete deployment <name>

DaemonSets

kubectl get daemonsets
kubectl get daemonsets --namespace kube-system
kubectl describe daemonset <name>
kubectl delete daemonset <name>

Jobs

kubectl get jobs
kubectl describe job <name>
kubectl get pods --selector=job-name=<name>
kubectl logs <pod-name>
kubectl delete job <name>

CronJobs

kubectl get cronjobs
kubectl describe cronjob <name>
kubectl patch cronjob <name> -p '{"spec": {"suspend": true}}'
kubectl delete cronjob <name>

Labels and Selectors

kubectl get pods --show-labels
kubectl label pod <pod-name> app=DEBUG --overwrite
kubectl label node <node-name> <key>=<value>
kubectl get pods -l app=hello-world

9. Best Practices

Deployments

  1. Always define an appropriate strategy (RollingUpdate or Recreate) with maxUnavailable and maxSurge adapted to infrastructure capacity
  2. Always define readinessProbes in the Pod template — without them, Kubernetes considers a Pod ready on startup
  3. Never manage ReplicaSets directly — always use Deployments
  4. Manage deployments declaratively in YAML rather than imperatively — for reproducibility and version control

DaemonSets

  1. Use OnDelete for critical DaemonSets (like kube-proxy) to manually control update timing on each node
  2. Use nodeSelectors or nodeAffinity to limit DaemonSets to subsets of nodes with required characteristics

Jobs

  1. Define backoffLimit explicitly for critical Jobs to control retry count on failure
  2. Define activeDeadlineSeconds to prevent blocked Jobs from consuming resources indefinitely
  3. Use parallelism and completions for parallelizable Jobs to optimize cluster resource utilization

CronJobs

  1. Set concurrencyPolicy: Forbid for Jobs that must not overlap (e.g., backups)
  2. Configure successfulJobsHistoryLimit and failedJobsHistoryLimit to prevent old Job accumulation

Search Terms

managing · kubernetes · controllers · deployments · containers · deployment · controller · cronjobs · daemonsets · jobs · reference · applications · daemonset · flow · job · readiness · replicaset · rollouts · statefulsets

Interested in this course?

Contact us to book it or get a custom training plan for your team.