Ravindra BagaleCourses & study guides मराठी

Chapter 19: Kubernetes Services, Ingress and Volumes

19.11 From a Git commit to a running Deployment

Why: the problem

At a company like Zomato, nobody types kubectl run in production. A developer pushes a commit. CI builds an image and tags it with the short Git commit hash, like shop:3f9c2ab. Then the Deployment YAML is updated to that tag and applied, by a pipeline or by a GitOps tool like Argo CD. Why the commit hash and not latest? Because latest changes every day, so you cannot tell what is running, and rollback is guesswork. With the hash, kubectl get deploy tells you the exact commit in production, and rolling back means going to the previous hash. In this lesson you will do this loop by hand on kind: make a tiny app in a local Git repo, build an image tagged with the commit, load it into kind, apply a Deployment, Service and PVC, make a second commit, roll out, watch zero-downtime replacement, and roll back.

What we will build

You will build shop:COMMIT from a local Git repo, load it into kind, deploy it with a Service, change the code, deploy the new commit, and roll back with kubectl rollout undo. Every step shows which commit is running.

What: every term in plain English

  • Commit hash — A unique ID for a Git commit; the short form has 7 characters.
  • Immutable tag — An image tag that never points to different content, like the commit hash.
  • kind load docker-image — Copies a local image into the kind node, no registry needed.
  • Rolling update — Kubernetes replaces Pods a few at a time so the app stays up.
  • rollout status — Waits until the new version is fully running.
  • rollout undo — Goes back to the previous ReplicaSet.
  • change-cause — An annotation that records why a rollout happened.
  • GitOps — The cluster state is kept in Git and a tool syncs it.
Start a lab cluster Make a practice namespace Make the app repo Build with the commit tag Load into kind
Commit to Deployment: tag = commit

How: step by step

  1. Start a lab cluster

    kind create cluster --name lab
    kubectl get nodes
    

    What it does: Creates a one-node Kubernetes cluster inside Docker. On minikube use: minikube start.

    Output

    Creating cluster "lab" ...
     ✓ Ensuring node image (kindest/node:v1.30.0)
     ✓ Preparing nodes
    Set kubectl context to "kind-lab"
    NAME                STATUS   ROLES           AGE   VERSION
    lab-control-plane   Ready    control-plane   40s   v1.30.0
    
  2. Make a practice namespace

    kubectl create namespace practice
    kubectl config set-context --current --namespace=practice
    

    What it does: Keeps all lab objects in one folder that is easy to delete.

    Output

    namespace/practice created
    Context "kind-lab" modified.
    
  3. Make the app repo

    mkdir shop && cd shop && git init -q && printf 'FROM nginx:1.27-alpine\nCOPY index.html /usr/share/nginx/html/\n' > Dockerfile && echo "shop v1" > index.html && git add . && git commit -qm "v1" && git log --oneline
    

    What it does: A tiny static app with one commit.

    Output

    3f9c2ab v1
    
  4. Build with the commit tag

    TAG=$(git rev-parse --short HEAD) && docker build -q -t shop:$TAG . && echo $TAG
    

    What it does: The tag is the commit hash.

    Output

    sha256:8d1e...
    3f9c2ab
    
  5. Load into kind

    kind load docker-image shop:$TAG --name lab
    

    What it does: kind nodes cannot see your laptop images until you load them.

    Output

    Image: "shop:3f9c2ab" with ID "sha256:8d1e..." not yet present on node "lab-control-plane", loading...
    

Example 1: Deploy the commit with a Deployment and Service

Stack. kind, Docker, Git

Goal. Deploy the commit with a Deployment and Service.

deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: shop
spec:
  replicas: 3
  strategy:
    rollingUpdate: {maxUnavailable: 0, maxSurge: 1}
  selector:
    matchLabels: {app: shop}
  template:
    metadata:
      labels: {app: shop}
    spec:
      containers:
      - name: shop
        image: shop:TAG
        imagePullPolicy: IfNotPresent
        ports: [{containerPort: 80}]
        readinessProbe:
          httpGet: {path: /, port: 80}
---
apiVersion: v1
kind: Service
metadata:
  name: shop
spec:
  selector: {app: shop}
  ports: [{port: 80}]

terminal

sed "s/TAG/$TAG/" deploy.yaml | kubectl apply -f -
kubectl annotate deploy shop kubernetes.io/change-cause="commit $TAG" --overwrite
kubectl rollout status deploy/shop
kubectl get deploy shop -o jsonpath="{.spec.template.spec.containers[0].image}{'\n'}"
kubectl run t --rm -i --image=curlimages/curl:8.8.0 --restart=Never -- curl -s shop

What each line does

  • maxUnavailable 0, maxSurge 1 — Add one new Pod before removing an old one. No downtime.
  • image: shop:TAG — sed replaces TAG with the commit hash.
  • imagePullPolicy IfNotPresent — Use the image loaded into kind; do not pull.
  • readinessProbe — Traffic goes to a Pod only when it answers.
  • change-cause — Recorded in rollout history.

Green output

deployment.apps/shop created
service/shop created
deployment "shop" successfully rolled out
shop:3f9c2ab
shop v1

Expected result. You can see the exact commit running in the cluster.

Example 2: Second commit, rolling update

Stack. Deployment rolling update

Goal. Second commit, rolling update.

terminal

echo "shop v2 - new offers" > index.html && git commit -qam "v2 offers"
TAG=$(git rev-parse --short HEAD); docker build -q -t shop:$TAG . && kind load docker-image shop:$TAG --name lab
kubectl set image deploy/shop shop=shop:$TAG
kubectl annotate deploy shop kubernetes.io/change-cause="commit $TAG" --overwrite
kubectl rollout status deploy/shop
kubectl run t --rm -i --image=curlimages/curl:8.8.0 --restart=Never -- curl -s shop

What each line does

  • git commit -am — Commit the change.
  • new TAG — A new hash, so a new image tag.
  • kubectl set image — Changes the image in the Deployment and starts a rollout.
  • rollout status — Waits while Pods are replaced one by one.

Green output

Waiting for deployment "shop" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "shop" rollout to finish: 2 out of 3 new replicas have been updated...
deployment "shop" successfully rolled out
shop v2 - new offers

Expected result. The new commit is live with no downtime.

Example 3: Roll back to the previous commit

Stack. kubectl rollout

Goal. Roll back to the previous commit.

terminal

kubectl rollout history deploy/shop
kubectl rollout undo deploy/shop
kubectl rollout status deploy/shop
kubectl get deploy shop -o jsonpath="{.spec.template.spec.containers[0].image}{'\n'}"

What each line does

  • rollout history — Lists revisions with change-cause.
  • rollout undo — Back to the previous revision.
  • jsonpath image — Confirms which commit runs now.

Green output

deployment.apps/shop
REVISION  CHANGE-CAUSE
1         commit 3f9c2ab
2         commit 7b21e04
deployment.apps/shop rolled back
deployment "shop" successfully rolled out
shop:3f9c2ab

Expected result. Rollback took seconds, and the tag tells you exactly which code is back.

Verify: did it work?

  1. See ReplicaSets per commit

    kubectl get rs -l app=shop -o wide
    

    What it does: Each commit has its own ReplicaSet.

    Output

    NAME              DESIRED   CURRENT   READY   IMAGES
    shop-6d9f7c8b5d   3         3         3       shop:3f9c2ab
    shop-85c4b9f6d7   0         0         0       shop:7b21e04
    
  2. Match the commit to Git

    git log --oneline
    

    What it does: The running tag is in your history.

    Output

    7b21e04 v2 offers
    3f9c2ab v1
    

When it is red 1

ErrImagePull / ImagePullBackOff for shop:3f9c2ab

Cause. The image was not loaded into kind, or pull policy is Always.

Fix, step by step

  1. Run kind load docker-image.
  2. Set imagePullPolicy IfNotPresent.

When it is red 2

error: deployment "shop" exceeded its progress deadline

Cause. New Pods never became Ready.

Fix, step by step

  1. kubectl describe pod for probe failures.
  2. kubectl rollout undo deploy/shop.

When it is red 3

fatal: not a git repository

Cause. You ran git rev-parse outside the repo.

Fix, step by step

  1. cd shop first.

Cleanup

  1. Delete the app

    kubectl delete deploy,svc shop
    

    What it does: Removes the Deployment and Service.

    Output

    deployment.apps "shop" deleted
    service "shop" deleted
    
  2. Remove the repo and images

    cd .. && rm -rf shop && docker image rm $(docker images shop -q) -f
    

    What it does: Cleans your laptop.

    Output

    Untagged: shop:3f9c2ab
    Untagged: shop:7b21e04
    
  3. Delete the practice namespace

    kubectl delete namespace practice
    

    What it does: Deletes every object you made in this lesson in one go.

    Output

    namespace "practice" deleted
    
  4. Delete the lab cluster

    kind delete cluster --name lab
    

    What it does: Removes the whole cluster container. On minikube use: minikube delete.

    Output

    Deleting cluster "lab" ...
    Deleted nodes: ["lab-control-plane"]
    

Ravindra Bagale's Tip

Image la latest tag nako, commit hash dya. Mag kay chalu aahe te nakki kalta, ani rollback ek command!

Practice tasks

Easy Show the running commit

Why: Know what is live.

What to do: Print the image of the Deployment.

How:
  1. jsonpath on containers[0].image

Check: You see shop:HASH.

Medium Bad commit

Why: Practise a failed rollout.

What to do: Commit a Dockerfile that breaks nginx and roll out.

How:
  1. Watch rollout status.
  2. Undo.

Check: Old Pods kept serving.

Hard Kustomize

Why: Avoid sed.

What to do: Use kustomize edit set image shop=shop:$TAG.

How:
  1. kubectl apply -k .

Check: Same result, no sed.

Easy Say Git commit to Deployment in two lines

Why: If you can say it simply, you understand it. Interviewers want the short version first.

What to do: Write two short lines about Git commit to Deployment for a fresher who knows only Docker basics.

How:
  1. Write what problem it solves.
  2. Write the one kubectl command you use for it.
  3. Read it aloud to a friend.

Check: A fresher understands it without asking a question.

Easy Start a fresh lab cluster

Why: Practice needs a throwaway cluster. If you break it, you delete it and start again.

What to do: Create a kind cluster, or a minikube cluster, and check the node is Ready.

How:
  1. kind create cluster --name lab
  2. kubectl get nodes
  3. kubectl get pods -A

Check: One node shows STATUS Ready and the kube-system Pods are Running.

Medium Break it on purpose

Why: You must know the red message by face. During an outage there is no time to read slowly.

What to do: Cause one error from the "When it is red" part of this lesson and fix it.

How:
  1. Follow the error section.
  2. Copy the exact message and the kubectl describe Events into your notes.
  3. Write the fix in one line.

Check: You fixed it using only the steps, without searching the web.

Medium Write a one-page runbook

Why: At 2 a.m. nobody remembers the right command. A short page saves the on-call person.

What to do: Write a runbook page for this lesson.

How:
  1. Title, when to use, exact kubectl command, how to check, how to undo.

Check: A teammate can follow it alone.

Medium Repeat it on a cloud cluster

Why: kind is a laptop toy. Real clusters run on EKS, GKE, AKS or k3s on a VM.

What to do: Do the main steps of this lesson again on a small k3s VM or a free-tier managed cluster.

How:
  1. Install k3s on one Ubuntu 22.04 VM: curl -sfL https://get.k3s.io | sh -
  2. Copy the kubeconfig.
  3. Apply the same YAML and compare the output.

Check: Same output on the cloud cluster as on kind.

Hard Explain it like an interview

Why: Interviewers want real stories, not definitions.

What to do: Record a 60 second answer about this lesson.

How:
  1. Say the problem, the YAML field you used, the kubectl command you ran, and one error you hit.

Check: Your answer has a real command and a real error message.

Hard Draw the flow top to bottom

Why: A drawing shows who talks to whom and in what order.

What to do: Draw this lesson as boxes from top to bottom.

How:
  1. Start at kubectl apply, go through the API server, controller and scheduler, end at the running container.

Check: Each box matches a real thing you saw in kubectl output.

Homework: try at home

Try at home

At home, write a small script deploy.sh that does build, load, set image, annotate and rollout status in one go for the current commit. Then make it refuse to deploy if git status shows uncommitted changes.

Recap

  • CI builds an image tagged with the commit hash.
  • The Deployment is updated to that tag.
  • Rolling updates with readiness keep the app up.
  • rollout history and undo give quick rollbacks.
  • GitOps tools automate the same loop.

FAQ

Do real teams use kind load?

No, they push to a registry like ECR. kind load is for labs.

Is the full or short hash better?

Short is common and readable; full is safest.

Where does Argo CD fit?

It watches a Git repo of YAML and applies changes automatically.

Should I also tag versions like 1.4.0?

Yes, many teams push both a version tag and the commit tag.

How many old ReplicaSets are kept?

revisionHistoryLimit, 10 by default.

Interview questions

  1. How do you deploy a commit to Kubernetes?

    Build and push an image tagged with the commit, update the Deployment image, and watch rollout status.

  2. How do you roll back a Deployment?

    kubectl rollout undo, or revert the image tag in Git with GitOps.

  3. Why avoid the latest tag?

    It is mutable and makes rollbacks and audits unreliable.

  4. What controls rolling update speed?

    maxSurge and maxUnavailable.

  5. What is GitOps?

    Using Git as the source of truth for cluster state, synced by a controller.

Quick quiz

Q1. Why tag images with the commit hash?

You know exactly what runs and can roll back to a known version.

Q2. Why not latest?

It changes over time, so you cannot tell what runs.

Q3. How does kind see local images?

kind load docker-image.

Q4. Which command rolls back?

kubectl rollout undo.

Q5. What keeps the rollout zero-downtime?

maxUnavailable 0 with readiness probes.

Samajla ka?

Ravi Sir's Cards for this lesson

मराठी cards