Skip to main content

Kubernetes Ep 4: Deployments, ReplicaSets & Self-Healing Scaling

Rachmat Hidayat
Author
Rachmat Hidayat
Learn & sharing insights on TypeScript, Go, Kubernetes, DevOps, DevSecOps, SRE, Platform Engineering, AI/ML Engineering, and MLOps.
kubernetes - This article is part of a series.
Part 4: This Article
While Pods are the basic building blocks of Kubernetes, you should rarely deploy bare Pods directly. Instead, production applications use Deployments, a higher-level abstraction that manages ReplicaSets to guarantee high availability, self-healing, and seamless scaling.

TL;DR (Quick Summary)
#

  • Hierarchy: Deployment controls ReplicaSet, which controls Pods.
  • Self-Healing: If a Pod crashes, is killed, or its host node dies, the ReplicaSet controller detects the drift and immediately launches a replacement Pod.
  • Horizontal Scaling: Scale application capacity effortlessly via kubectl scale or by editing spec.replicas in your YAML manifest.
  • Declarative Updates: Modifying a Deployment’s container image triggers a rolling update by spawning a new ReplicaSet while gracefully terminating the old one.

1. The Controller Hierarchy: Deployment vs ReplicaSet vs Pod
#


graph TD
    D["Deployment: web-app-deployment
(Strategy: RollingUpdate)"] --> RS1["ReplicaSet: web-app-7d4f9b8c (v1)
(Desired: 3, Ready: 3)"] RS1 --> P1["Pod: web-app-7d4f9b8c-1a"] RS1 --> P2["Pod: web-app-7d4f9b8c-2b"] RS1 --> P3["Pod: web-app-7d4f9b8c-3c"]
  1. Deployment: Manages declarative updates for application specifications, version history, and rollbacks.
  2. ReplicaSet: Ensures that a specified number of identical Pod replicas (spec.replicas) are running at any given time using label selectors (spec.selector.matchLabels).
  3. Pod: The running container instance.

2. Declarative Deployment Manifest
#

Create deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-deployment
  namespace: default
  labels:
    app: frontend
    tier: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
        version: v1
    spec:
      containers:
      - name: web-app
        image: nginx:1.25-alpine
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: "50m"
            memory: "64Mi"
          limits:
            cpu: "200m"
            memory: "128Mi"

Apply the deployment manifest:

kubectl apply -f deployment.yaml

Expected Terminal Output:

deployment.apps/frontend-deployment created

3. Verifying Deployment & ReplicaSet State
#

Check the Deployment status:

kubectl get deployments
NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
frontend-deployment   3/3     3            3           25s

Inspect the underlying ReplicaSet created automatically by K8s:

kubectl get replicasets
NAME                             DESIRED   CURRENT   READY   AGE
frontend-deployment-75b69bd654   3         3         3       40s

List the 3 running Pod instances:

kubectl get pods -l app=frontend
NAME                                   READY   STATUS    RESTARTS   AGE
frontend-deployment-75b69bd654-2x9lq   1/1     Running   0          55s
frontend-deployment-75b69bd654-8k4mn   1/1     Running   0          55s
frontend-deployment-75b69bd654-m9z12   1/1     Running   0          55s

4. Testing Self-Healing Capabilities
#

To demonstrate self-healing, let’s manually delete one of the Pods:

kubectl delete pod frontend-deployment-75b69bd654-2x9lq

Expected Behavior:

pod "frontend-deployment-75b69bd654-2x9lq" deleted

Now list the Pods immediately:

kubectl get pods -l app=frontend
NAME                                   READY   STATUS    RESTARTS   AGE
frontend-deployment-75b69bd654-8k4mn   1/1     Running   0          2m
frontend-deployment-75b69bd654-m9z12   1/1     Running   0          2m
frontend-deployment-75b69bd654-p4vws   1/1     Running   0          4s

Notice how the ReplicaSet detected that active replicas dropped from 3 to 2 and instantly spawned frontend-deployment-75b69bd654-p4vws (age 4 seconds) to restore the desired state!


5. Horizontal Scaling
#

Imperative Scaling
#

Scale up to 5 replicas:

kubectl scale deployment frontend-deployment --replicas=5

Verify scaled replicas:

kubectl get pods -l app=frontend

Declarative Scaling
#

In production, update replicas: 5 inside deployment.yaml and re-apply:

kubectl apply -f deployment.yaml

6. Summary & Next Steps
#

Deployments provide high availability and self-healing. However, Pod IP addresses are ephemeral—when a Pod dies and is replaced, its IP address changes. How do client applications communicate with a changing set of Pod IPs?

In Episode 05: Networking Services (ClusterIP, NodePort, LoadBalancer), we will explore Kubernetes Services to provide stable virtual IPs, DNS names, and load balancing across active replicas!

kubernetes - This article is part of a series.
Part 4: This Article