Intermediate

Deployments in Kubernetes

Deployments, rollouts and rollbacks and horizontal pod autoscaling with kubectl.

Table of Contents


1. Deployments Overview

1.1 Definition and Desired States

A Deployment is a Kubernetes resource that manages the lifecycle of Pods and guarantees that the correct number of replicas is running at all times. It provides a declarative approach to deploying, updating, and scaling applications, while automatically managing failures through self-healing.

The main objectives of a Deployment are:

  • Expose containerized workloads to users in a reliable, efficient, and secure manner
  • Define everything in a manifest (deployment.yaml)
  • Manage rolling updates (gradual transition between versions)
  • Manage rollbacks (return to a previous version on failure)

Self-healing: if a Pod fails, the Deployment automatically recreates it to maintain the desired state (replicas).


1.2 Architecture: Deployment → ReplicaSet → Pod

graph TD
    User["User / kubectl"] -->|"kubectl apply -f deployment.yaml"| D

    subgraph "Kubernetes Control Plane"
        D["Deployment\n(my-app)"]
        RS["ReplicaSet\n(my-app-abc123)"]
    end

    subgraph "Worker Node(s)"
        P1["Pod 1\n(my-app-abc123-xxx)"]
        P2["Pod 2\n(my-app-abc123-yyy)"]
        P3["Pod 3\n(my-app-abc123-zzz)"]

        P1 --> C1["Container\n(nginx:1.27)"]
        P2 --> C2["Container\n(nginx:1.27)"]
        P3 --> C3["Container\n(nginx:1.27)"]
    end

    D -->|"manages"| RS
    RS -->|"maintains replicas: 3"| P1
    RS -->|"maintains replicas: 3"| P2
    RS -->|"maintains replicas: 3"| P3

Responsibility hierarchy:

ResourceResponsibility
DeploymentManages update strategy, revision history, rollbacks
ReplicaSetMaintains desired number of identical Pods (auto-created by Deployment)
PodExecution unit containing one or more containers
ContainerApplication image running inside the Pod

1.3 Deployment Manifest Structure

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  replicas: 3                      # Desired number of Pods
  selector:
    matchLabels:
      app: my-app                  # Selects Pods managed by this Deployment
  template:
    metadata:
      labels:
        app: my-app                # Labels of created Pods
    spec:
      containers:
      - name: my-container
        image: nginx:latest        # Docker image to use
        ports:
        - containerPort: 8080      # Port exposed by the container
        env:
        - name: APP_ENV
          value: "production"
        - name: LOG_LEVEL
          value: "info"

Essential fields:

FieldDescription
apiVersion: apps/v1API version for Deployments
kind: DeploymentResource type
spec.replicasNumber of Pods to maintain
spec.selector.matchLabelsLink between Deployment and its Pods (must match template labels)
spec.templatePod template used to create each replica
spec.template.spec.containersContainer definitions (image, ports, env vars)

1.4 Applying and Verifying

# Create or update the Deployment
kubectl apply -f dep1.yaml

# Check Deployment status
kubectl get deployments

# See created Pods
kubectl get pods

# Port-forwarding for local testing
kubectl port-forward pod/<pod-name> 8080:80

# Test from another session
curl localhost:8080

Example kubectl get deployments output:

NAME     READY   UP-TO-DATE   AVAILABLE   AGE
my-app   3/3     3            3           2m
ColumnMeaning
READYReady Pods / Desired Pods
UP-TO-DATEPods updated to the latest revision
AVAILABLEPods available to serve traffic

1.5 When to Use Deployment vs StatefulSet

CriterionDeploymentStatefulSet
Pod identityAnonymous — all identicalStable and unique (pod-0, pod-1, pod-2)
StorageEphemeral / sharedDedicated Persistent Volume per Pod
Use casesStateless apps (web APIs, frontends)Databases, Kafka, Elasticsearch
Start orderRandomSequential and guaranteed
Self-healingYesYes, but preserves identity

2. Updates, Rollouts and Rollbacks

2.1 Readiness, Liveness and Startup Probes

Probes are health mechanisms Kubernetes uses to automatically monitor each Pod’s state.

Probe Types

ProbeTriggerObjectiveAction on Failure
startupProbeOnly at startupGive app time to start before other probesKills the container (restart)
readinessProbeContinuouslyCheck if Pod is ready to receive trafficRemoves Pod from Service (no traffic)
livenessProbeContinuouslyCheck if app is still aliveRestarts the container

Verification Methods

# HTTP GET (most common)
httpGet:
  path: /health
  port: 5000

# TCP Socket
tcpSocket:
  port: 8080

# Shell command
exec:
  command:
  - cat
  - /tmp/healthy

Complete Manifest with All 3 Probes

apiVersion: apps/v1
kind: Deployment
metadata:
  name: flask-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: flask
  template:
    metadata:
      labels:
        app: flask
    spec:
      containers:
      - name: flask-container
        image: myrepo/flask-app:latest
        ports:
        - containerPort: 5000

        # Startup probe — active only at boot
        startupProbe:
          httpGet:
            path: /health
            port: 5000
          failureThreshold: 6    # Allows up to 60s (6 × 10s) to start
          periodSeconds: 10

        # Readiness probe — controls whether Pod receives traffic
        readinessProbe:
          httpGet:
            path: /health
            port: 5000
          initialDelaySeconds: 3
          periodSeconds: 5
          failureThreshold: 2

        # Liveness probe — restarts if app is stuck
        livenessProbe:
          httpGet:
            path: /health
            port: 5000
          initialDelaySeconds: 35  # Waits until recovery is possible
          periodSeconds: 10
          failureThreshold: 3

Startup Flow with Probes

sequenceDiagram
    participant K as Kubernetes
    participant P as Pod / Container
    participant S as Service (traffic)

    K->>P: Start the container
    activate P
    Note over P: startupProbe active
    loop Check every 10s (max 60s)
        K->>P: GET /health
        P-->>K: 500 Unhealthy (less than 30s)
    end
    K->>P: GET /health
    P-->>K: 200 OK (after 30s)
    Note over P: startupProbe succeeds
    Note over P: readinessProbe + livenessProbe start
    K->>S: Add Pod to Service
    activate S
    S->>P: User traffic
    deactivate S
    deactivate P

2.2 Rolling Updates

A Rolling Update progressively replaces old Pods with new ones, ensuring continuous availability. There is no service interruption for users.

Manifest with RollingUpdate Strategy

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # Maximum surplus Pods during update
      maxUnavailable: 1  # Maximum unavailable Pods during update
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.26   # Change to 1.27 to trigger an update
        ports:
        - containerPort: 80

Rolling Update Flow (nginx:1.26 to nginx:1.27)

graph LR
    subgraph "Step 1 - Initial state"
        A1["Pod nginx:1.26"]
        A2["Pod nginx:1.26"]
        A3["Pod nginx:1.26"]
    end

    subgraph "Step 2 - Transition (maxSurge=1, maxUnavailable=1)"
        B1["Pod nginx:1.26"]
        B2["Pod nginx:1.26"]
        B3["Pod nginx:1.27 (new)"]
        B4["Pod terminating"]
    end

    subgraph "Step 3 - Final state"
        C1["Pod nginx:1.27"]
        C2["Pod nginx:1.27"]
        C3["Pod nginx:1.27"]
    end

    A1 --> B1
    A2 --> B4
    A3 --> B2
    B3 -.-> C3

Rollout Management Commands

# Apply the update (change image in YAML, then)
kubectl apply -f deployment.yaml

# Track rollout progress
kubectl rollout status deployment/nginx-deployment

# View revision history
kubectl rollout history deployment/nginx-deployment

# Update image directly via CLI
kubectl set image deployment/nginx-deployment nginx=nginx:1.27

2.3 Rollbacks

If an update fails or causes problems, Kubernetes allows instant return to a previous revision.

graph TD
    A["kubectl apply (nginx:1.27)"] --> B["Rolling Update starts"]
    B --> C{Are new version Pods healthy?}
    C -->|Yes| D["Update complete - Revision 2 active"]
    C -->|No - Issue detected| E["kubectl rollout undo"]
    E --> F["Kubernetes returns to previous revision (nginx:1.26)"]
    F --> G["Revision 1 active - Service restored"]
# Rollback to previous revision
kubectl rollout undo deployment/nginx-deployment

# Rollback to a specific revision
kubectl rollout undo deployment/nginx-deployment --to-revision=1

# View detailed history
kubectl rollout history deployment/nginx-deployment --revision=2

# Annotate a deployment to keep a trace
kubectl annotate deployment/nginx-deployment kubernetes.io/change-cause="Update to nginx 1.27"

Note: Kubernetes retains the last 10 revisions by default (revisionHistoryLimit: 10). This can be adjusted in the Deployment manifest.


2.4 Deployment Strategies: RollingUpdate vs Recreate

graph LR
    subgraph "RollingUpdate"
        RU1["v1 active"] --> RU2["v1 + v2 in transition"] --> RU3["v2 active"]
    end

    subgraph "Recreate"
        RC1["v1 active"] --> RC2["Full stop (downtime)"] --> RC3["v2 active"]
    end
# Recreate strategy
spec:
  strategy:
    type: Recreate
# RollingUpdate strategy with percentages
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
ParameterDescriptionExample
maxSurgeMax Pods above replicas count1 or 25%
maxUnavailableMax unavailable Pods during update1 or 25%
CriterionRollingUpdateRecreate
AvailabilityContinuous (zero downtime)Complete interruption
Version coexistenceYes (transient)No
DB migrationComplex (compatibility required)Simple
RollbackAutomatic and fastFull redeploy
Use caseProduction, stateless APIsApps with DB schema changes

3. Horizontal Pod Autoscaling (HPA)

3.1 HPA Principle

The HPA (Horizontal Pod Autoscaler) automatically adjusts the number of Pods in a Deployment, ReplicaSet, or StatefulSet based on observed metrics (CPU, memory, custom metrics).

  • Scale up: Adds Pods when resource utilization exceeds the threshold
  • Scale down: Removes Pods when demand decreases

3.2 Metrics Server

The HPA depends on the Metrics Server to collect CPU/memory metrics.

# Install Metrics Server (from official GitHub manifest)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# Verify Metrics Server is active
kubectl get deployment metrics-server -n kube-system

# View Pod metrics
kubectl top pods
kubectl top nodes

3.3 HPA Manifest

Step 1 — Deployment with resource requests/limits:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        resources:
          requests:
            cpu: "50m"        # Guaranteed minimum (50 millicores)
            memory: "64Mi"
          limits:
            cpu: "200m"       # Maximum allowed
            memory: "128Mi"
        ports:
        - containerPort: 80

Step 2 — Service to expose the Deployment:

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
  type: ClusterIP

Step 3 — HPA (autoscaling/v2):

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: nginx-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx-deployment
  minReplicas: 2    # Minimum Pods (even at zero load)
  maxReplicas: 10   # Maximum allowed Pods
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50  # Scale up if CPU > 50% of request

3.4 HPA Flow

graph TD
    MS["Metrics Server\n(collects CPU/memory)"] -->|"metrics every 15s"| HPA

    subgraph "HPA Controller"
        HPA["HorizontalPodAutoscaler\n(nginx-hpa)\nmin:2 / max:10\ntarget: CPU 50%"]
    end

    HPA -->|"CPU > 50% - Scale UP"| D

    subgraph "Deployment"
        D["nginx-deployment"]
        D --> RS["ReplicaSet"]
        RS --> P1["Pod 1"]
        RS --> P2["Pod 2"]
        RS -.->|"new Pods created"| P3["Pod 3"]
        RS -.-> P4["Pod 4"]
    end

    LB["Load\n(HTTP requests)"] -->|"high load"| P1
    LB --> P2

    HPA -->|"CPU below 50% for 5min - Scale DOWN"| D
# Check HPA status
kubectl get hpa

# Full HPA details
kubectl describe hpa nginx-hpa

# View scaling events
kubectl get events --field-selector reason=SuccessfulRescale

Example kubectl get hpa output:

NAME        REFERENCE                     TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
nginx-hpa   Deployment/nginx-deployment   23%/50%   2         10        2          5m
ColumnMeaning
TARGETSCurrent utilization / target threshold
MINPODSMinimum replicas
MAXPODSMaximum replicas
REPLICASCurrent Pod count

4. kubectl Quick Reference Commands

# --- Deployments ---
kubectl apply -f deployment.yaml          # Create/update
kubectl get deployments                   # List deployments
kubectl describe deployment <name>        # Details
kubectl delete deployment <name>          # Delete

# --- Rollouts ---
kubectl rollout status deployment/<name>  # Track rollout
kubectl rollout history deployment/<name> # View revisions
kubectl rollout undo deployment/<name>    # Rollback
kubectl rollout undo deployment/<name> --to-revision=1  # Specific revision
kubectl set image deployment/<name> <container>=<image>  # Update image

# --- Scaling ---
kubectl scale deployment/<name> --replicas=5  # Manual scaling

# --- HPA ---
kubectl get hpa                           # List HPAs
kubectl describe hpa <name>              # HPA details
kubectl top pods                         # Pod resource usage
kubectl top nodes                        # Node resource usage

# --- Debugging ---
kubectl logs <pod-name>                  # Pod logs
kubectl exec -it <pod-name> -- bash      # Connect to container
kubectl describe pod <pod-name>          # Pod details
kubectl get events                       # Cluster events

5. Reference Tables

Probe Configuration Parameters

ParameterDescriptionDefault
initialDelaySecondsWait time before first check0
periodSecondsInterval between checks10
timeoutSecondsCheck timeout1
failureThresholdFailures before action3
successThresholdSuccesses to consider healthy1

RollingUpdate Configuration

ParameterDescriptionDefault
maxSurgeMax Pods above replicas (int or %)25%
maxUnavailableMax unavailable Pods (int or %)25%

Common Kubernetes Resources

ResourceapiVersionDescription
Deploymentapps/v1Stateless workload management
StatefulSetapps/v1Stateful workload with stable identity
ReplicaSetapps/v1Pod count maintenance (auto-managed by Deployment)
DaemonSetapps/v1One Pod per Node
HorizontalPodAutoscalerautoscaling/v2Metrics-based autoscaling
Podv1 (core)Basic execution unit
Servicev1 (core)Network exposure of Pods

6. Key Concepts Summary

mindmap
  root((Kubernetes Deployments))
    Desired State
      replicas
      self-healing
      ReplicaSet
    YAML Manifest
      apiVersion apps/v1
      kind Deployment
      spec.selector
      spec.template
    Probes
      startupProbe
      readinessProbe
      livenessProbe
    Updates
      RollingUpdate
        maxSurge
        maxUnavailable
      Recreate
    Rollback
      rollout undo
      revisionHistoryLimit
    Autoscaling HPA
      Metrics Server
      minReplicas
      maxReplicas
      CPU Memory target

Essential Points to Remember

  1. A Deployment doesn’t manage Pods directly — it creates a ReplicaSet, which manages the Pods. Each update creates a new ReplicaSet.

  2. Labels are fundamental — the spec.selector.matchLabels must exactly match the spec.template.metadata.labels for the Deployment to find its Pods.

  3. The RollingUpdate strategy is the default and guarantees zero downtime. The maxSurge and maxUnavailable parameters control the speed and safety of the transition.

  4. Probes work as a team:

    • startupProbe: give time at startup
    • readinessProbe: don’t send traffic until the app is ready
    • livenessProbe: automatically restart if app is stuck
  5. HPA requires resources.requests defined in the container to work. Without requests, the Metrics Server cannot calculate the utilization percentage.

  6. kubectl rollout undo is the immediate rollback tool — Kubernetes reactivates the previous ReplicaSet without creating a new revision.


Search Terms

deployments · kubernetes · containers · deployment · hpa · manifest · flow · probes · rollingupdate · commands · configuration · pod · probe · reference · rollbacks · rolling · startup · updates

Interested in this course?

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