Ravindra BagaleCourses & study guides मराठी

Chapter 60: Kubernetes Workload Controllers in Depth: ReplicaSet, Deployment, StatefulSet, DaemonSet, Jobs and CronJobs

60.1 ReplicationController: the first controller, and why it is legacy

Why: the problem

Suppose we run the IRCTC ticket search service as one bare pod. At 10 AM, tatkal booking opens, the node runs out of memory, and the pod is evicted. Nobody brings it back. Search is down until someone notices and runs kubectl apply again. A bare pod has no guardian. The first guardian Kubernetes ever had was the ReplicationController, or RC. You tell it "keep 3 copies of this pod", and it watches day and night. If one dies, it makes a new one. If there are too many, it deletes the extra. Today nobody writes new RCs. ReplicaSet and Deployment replaced them. But old clusters, old tutorials and interviews still use them, and the idea behind them, a control loop, is the idea behind every controller. In this lesson we run an RC, kill its pods, scale it, see its equality-only selector, and migrate it to a Deployment. Then we break it with a selector that does not match and with a pod that an RC adopts by accident.

What: every term in plain English

  • Controller — A loop in kube-controller-manager that compares desired state with actual state and fixes the difference.
  • ReplicationController (RC) — The original controller that keeps a fixed number of identical pods running. apiVersion v1, kind ReplicationController.
  • replicas — How many pods the controller must keep.
  • selector — Which pods the controller counts as its own. RC supports only equality, like app=search.
  • template — The pod blueprint the controller uses to create new pods.
  • Reconcile loop — Observe, compare, act, repeat. Every controller works this way.
  • Adoption — A controller takes ownership of any existing pod whose labels match its selector.
  • ownerReferences — Metadata on a pod that names the controller that owns it.
  • Rolling update for RC — Old kubectl rolling-update did it on the client side. It was removed in kubectl 1.18.
  • Legacy — Still works and is still in the API, but not used for new work.
Write the RC. Match labels. Apply and list. Kill a pod. Scale. Migrate. Clean up.
The controller loop: observe, compare, act, repeat

How: step by step

  1. Write the RC. apiVersion: v1, kind: ReplicationController, replicas, selector, template.
  2. Match labels. template.metadata.labels must contain every key in selector.
  3. Apply and list. kubectl get rc and kubectl get pods -l app=search.
  4. Kill a pod. kubectl delete pod one of them, and watch a new one appear.
  5. Scale. kubectl scale rc search --replicas=5.
  6. Migrate. Write a Deployment with the same labels, apply it, then delete the RC with --cascade=orphan or normally.
  7. Clean up. kubectl delete rc search deletes its pods too.

Example 1: Run an RC and watch it heal

Goal. Run an RC and watch it heal.

search-rc.yaml

apiVersion: v1
kind: ReplicationController
metadata:
  name: search
  namespace: shop
spec:
  replicas: 3
  selector:
    app: search
  template:
    metadata:
      labels:
        app: search
        tier: backend
    spec:
      containers:
        - name: web
          image: nginx:1.27
          ports:
            - containerPort: 80
          resources:
            requests: {cpu: 20m, memory: 32Mi}
            limits: {memory: 64Mi}

What each line does

  • apiVersion: v1 — RC lives in the core API group, like Pod and Service.
  • replicas: 3 — Desired state: three pods.
  • selector: app: search — A plain map. Only equality matching, no matchLabels or matchExpressions.
  • template.metadata.labels — Must include app: search, or the RC would keep creating pods it cannot count.
  • tier: backend — Extra labels are fine.

Green output

$ kubectl apply -f search-rc.yaml
replicationcontroller/search created
$ kubectl get rc -n shop
NAME     DESIRED   CURRENT   READY   AGE
search   3         3         3       12s
$ kubectl delete pod -n shop $(kubectl get pods -n shop -l app=search -o name | head -1 | cut -d/ -f2)
pod "search-7xk2d" deleted
$ kubectl get pods -n shop -l app=search
NAME           READY   STATUS    RESTARTS   AGE
search-9mfq4   1/1     Running   0          3s
search-h2lzt   1/1     Running   0          40s
search-wq8cn   1/1     Running   0          40s

Expected result. One pod was deleted and a new one, 3 seconds old, took its place. That is the reconcile loop in action.

Example 2: Scale, read ownership, and see adoption

Goal. Scale, read ownership, and see adoption.

stray-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: stray
  namespace: shop
  labels:
    app: search
spec:
  containers:
    - name: web
      image: nginx:1.27

What each line does

  • labels app: search — Same label as the RC selector.
  • No owner — A bare pod has no ownerReferences when created.
  • What happens — The RC now counts 4 pods for 3 desired, and deletes one to get back to 3.

Green output

$ kubectl scale rc search -n shop --replicas=3
$ kubectl get pod -n shop search-h2lzt -o jsonpath='{.metadata.ownerReferences[0].kind}/{.metadata.ownerReferences[0].name}{"\n"}'
ReplicationController/search
$ kubectl apply -f stray-pod.yaml
pod/stray created
$ kubectl get pods -n shop -l app=search
NAME           READY   STATUS        RESTARTS   AGE
search-9mfq4   1/1     Running       0          2m
search-h2lzt   1/1     Running       0          3m
search-wq8cn   1/1     Terminating   0          3m
stray          1/1     Running       0          2s

Expected result. The RC adopted the stray pod and removed one of its own to keep 3. Labels decide ownership, so choose them carefully.

Example 3: Migrate an RC to a Deployment with no downtime

Goal. Migrate an RC to a Deployment with no downtime.

search-deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: search
  namespace: shop
spec:
  replicas: 3
  selector:
    matchLabels:
      app: search
      version: v2
  template:
    metadata:
      labels:
        app: search
        version: v2
        tier: backend
    spec:
      containers:
        - name: web
          image: nginx:1.27
          ports:
            - containerPort: 80
          resources:
            requests: {cpu: 20m, memory: 32Mi}
            limits: {memory: 64Mi}

search-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: search
  namespace: shop
spec:
  selector:
    app: search
  ports:
    - port: 80

What each line does

  • apiVersion: apps/v1 — Deployments live in the apps group.
  • matchLabels with version: v2 — A new label so the Deployment does not fight the RC over the same pods.
  • Service selector app: search — Matches both old and new pods, so traffic flows during the switch.
  • Order — Apply Service, apply Deployment, wait Ready, then delete the RC.

Green output

$ kubectl apply -f search-svc.yaml -f search-deploy.yaml
$ kubectl rollout status deploy/search -n shop
deployment "search" successfully rolled out
$ kubectl get endpointslices -n shop -l kubernetes.io/service-name=search -o jsonpath='{range .items[*].endpoints[*]}{.addresses[0]} {end}{"\n"}'
10.244.1.12 10.244.2.8 10.244.1.13 10.244.2.11 10.244.1.15 10.244.2.12
$ kubectl delete rc search -n shop
replicationcontroller "search" deleted
$ kubectl get pods -n shop -l app=search
NAME                      READY   STATUS    RESTARTS   AGE
search-6d9f7c8b5d-4kq2x   1/1     Running   0          40s
search-6d9f7c8b5d-p8wzn   1/1     Running   0          40s
search-6d9f7c8b5d-vt7hc   1/1     Running   0          40s

Expected result. For a moment the Service had 6 endpoints, old and new. Then the RC was removed and only Deployment pods stayed. Users saw no gap.

Every command, step by step (kind lab with kubectl)

  1. Check the cluster

    kubectl get nodes
    kubectl get ns shop
    

    What it does: Reuse the ch59 cluster.

    ch59-control-plane   Ready
    ch59-worker          Ready
    ch59-worker2         Ready
    
  2. Read the RC docs

    kubectl explain rc.spec.selector
    

    What it does: Note: a map of string, not a LabelSelector.

    FIELD: selector map[string]string
    
  3. Create the RC

    kubectl apply -f search-rc.yaml
    kubectl get rc,pods -n shop -l app=search
    

    What it does: Three pods with random suffixes.

    replicationcontroller/search   3   3   3
    
  4. Watch healing live

    kubectl get pods -n shop -l app=search -w
    

    What it does: Leave it running in a second terminal.

    search-9mfq4   0/1   ContainerCreating   0   0s
    search-9mfq4   1/1   Running             0   2s
    
  5. Delete two pods at once

    kubectl delete pod -n shop -l app=search --wait=false
    

    What it does: All go; the RC makes three new ones.

    pod "search-9mfq4" deleted
    pod "search-h2lzt" deleted
    pod "search-wq8cn" deleted
    
  6. Scale up and down

    kubectl scale rc search -n shop --replicas=5
    kubectl scale rc search -n shop --replicas=2
    

    What it does: The RC adds or removes pods to match.

    replicationcontroller/search scaled
    
  7. See controller events

    kubectl describe rc search -n shop | tail -4
    

    What it does: SuccessfulCreate and SuccessfulDelete lines.

    Normal  SuccessfulCreate  replication-controller  Created pod: search-z4c9k
    Normal  SuccessfulDelete  replication-controller  Deleted pod: search-z4c9k
    
  8. Orphan the pods

    kubectl delete rc search -n shop --cascade=orphan
    kubectl get pods -n shop -l app=search
    

    What it does: The RC is gone but its pods stay, with no owner.

    search-6b8tq   1/1   Running   0   5m
    
  9. Clean up

    kubectl delete pod -n shop -l app=search
    kubectl delete deploy,svc -n shop search
    

    What it does: Ready for ReplicaSet in 60.2.

    pod "search-6b8tq" deleted
    

When it is red 1

The ReplicationController "search" is invalid: spec.template.metadata.labels: Invalid value: map[string]string{"app":"serch"}: `selector` does not match template `labels`

Cause. Typo in the template label.

Fix, step by step

  1. Make template labels contain every selector key and value.
  2. Apply again.

When it is red 2

error: unknown command "rolling-update" for "kubectl"

Cause. Old tutorials use kubectl rolling-update, removed in kubectl 1.18.

Fix, step by step

  1. Migrate to a Deployment and use kubectl set image and kubectl rollout.

When it is red 3

pods keep disappearing right after I create them

Cause. An RC, ReplicaSet or Deployment with a matching selector is adopting and deleting your pods.

Fix, step by step

  1. kubectl get pod -o jsonpath on ownerReferences.
  2. kubectl get rc,rs,deploy -A -o wide and check selectors.
  3. Use unique labels.

When it is red 4

error: unable to recognize "rc.yaml": no matches for kind "ReplicationController" in version "apps/v1"

Cause. RC is in the core group, not apps.

Fix, step by step

  1. Use apiVersion: v1 for ReplicationController.

Practice tasks

Easy Task 1: Create

Why: First controller.

What to do: Apply search-rc.yaml and list pods.

How:
  1. kubectl get rc.
Solution
kubectl apply -f search-rc.yaml

Easy Task 2: Heal

Why: Self-healing.

What to do: Delete one pod and see the replacement.

How:
  1. Watch AGE.
Solution
kubectl delete pod -n shop NAME

Easy Task 3: Scale

Why: Desired state.

What to do: Scale to 5, then back to 3.

How:
  1. kubectl scale.
Solution
kubectl scale rc search -n shop --replicas=5

Medium Task 4: Owner

Why: Ownership.

What to do: Print the owner of one pod.

How:
  1. ownerReferences jsonpath.
Solution
kubectl get pod NAME -n shop -o jsonpath='{.metadata.ownerReferences[0].name}'

Medium Task 5: Adopt

Why: Label danger.

What to do: Create stray and see what the RC does.

How:
  1. Apply stray-pod.yaml.
Solution
kubectl apply -f stray-pod.yaml

Medium Task 6: Explain

Why: Know the API.

What to do: Compare kubectl explain rc.spec.selector and rs.spec.selector.

How:
  1. Two explain commands.
Solution
kubectl explain rs.spec.selector

Medium Task 7: Bad selector

Why: Learn the error.

What to do: Break the template label and read the error.

How:
  1. Change app to serch.
Solution
app: serch

Medium Task 8: Orphan

Why: Cascade.

What to do: Delete the RC with --cascade=orphan and see pods stay.

How:
  1. --cascade=orphan.
Solution
kubectl delete rc search -n shop --cascade=orphan

Hard Task 9: Migrate

Why: Zero downtime.

What to do: Move search from RC to Deployment behind a Service with a curl loop running.

How:
  1. Apply Deployment first.
  2. Then delete RC.
Solution
while true; do kubectl exec -n shop deploy/search -- curl -s -o /dev/null -w '%{http_code} ' http://search; sleep 1; done

Hard Task 10: Controller logs

Why: See the loop.

What to do: Read kube-controller-manager logs for replication-controller lines.

How:
  1. Static pod from 59.7.
Solution
kubectl logs -n kube-system kube-controller-manager-ch59-control-plane | grep -i replication

Homework: try at home

Find one old tutorial that uses a ReplicationController and rewrite its YAML as a Deployment, explaining each change.

Recap

  • A controller is a loop that makes actual state match desired state.
  • RC keeps N identical pods; it is v1, equality-selector only, and legacy.
  • Labels decide ownership; a matching stray pod gets adopted.
  • kubectl rolling-update is gone; use Deployments for updates.
  • Migrate RC to Deployment by running both behind one Service, then deleting the RC.
  • Next, 60.2 covers the ReplicaSet that replaced it.

FAQ

Q. Is ReplicationController deprecated?

It is not removed from the API, but the docs recommend Deployments and ReplicaSets for all new work.

Q. Why learn it at all?

Old clusters and interviews use it, and it shows the reconcile loop in its simplest form.

Q. Can RC do rolling updates?

Not by itself. kubectl rolling-update did it from the client and is removed.

Q. RC vs ReplicaSet in one line?

Same job; ReplicaSet adds set-based selectors and is managed by Deployments.

Q. Who runs the RC loop?

The replication controller inside kube-controller-manager, a static pod from lesson 59.7.

Q. Does RC work on EKS?

Yes, the API still serves it, but use Deployments.

Q. How do I find old RCs in a cluster I just joined?

Run kubectl get rc -A. On a clean modern cluster the list is empty. If you see some, note their selectors and owners, then plan a migration to Deployments one app at a time.

Q. Can an RC and a Deployment share pods?

They should never share labels. If both selectors match the same pods they fight: one adopts, the other creates more, and the replica counts never settle. Always add a unique label such as controller: deploy before migrating.

Q. What happens to RC pods when a node dies?

The node controller marks the node NotReady, the pods are evicted after the timeout (about five minutes by default), and the RC creates replacements on healthy nodes. The same loop protects Deployments; we test it in 63.4.

Q. Does kubectl scale work the same on RC and ReplicaSet?

Yes. Both expose a scale subresource, so kubectl scale and even an autoscaler can change the replica count. Chapter 63 uses HPA on Deployments instead.

Interview questions

  1. What is a ReplicationController?

    Model answer: A legacy v1 controller that ensures a specified number of pod replicas run, using an equality-based selector.

  2. Difference between ReplicationController and ReplicaSet?

    Model answer: ReplicaSet supports set-based selectors (matchExpressions: In, NotIn, Exists) and is used by Deployments; RC only supports equality and is legacy.

  3. Explain the reconcile loop.

    Model answer: Controllers watch the API, compare desired spec with actual status, and create, delete or update objects to remove the difference, repeating forever.

  4. Why did my bare pod disappear?

    Model answer: A controller with a matching selector adopted it and scaled down to its replica count.

  5. How would you migrate an RC workload?

    Model answer: Create a Deployment with a distinguishing label behind the same Service, wait until ready, then delete the RC.

  6. An interviewer says: an RC shows 3 desired but 0 current pods. How do you debug it?

    Model answer: Run kubectl describe rc and read the events. Common causes are a ResourceQuota that forbids new pods, an image pull error, an admission webhook rejecting the pod, or a node selector that no node matches. Fix the cause and the RC creates pods on its own.

Quick quiz

Q1. Which apiVersion does RC use?

v1.

Q2. What kind of selector does RC support?

Equality only, a plain map of labels.

Q3. What happens if you delete an RC pod?

The RC creates a new one.

Q4. What replaced RC?

ReplicaSet, managed by Deployment.

Q5. What does --cascade=orphan do?

Deletes the controller but keeps its pods.

Samajla ka?