Ravindra BagaleCourses & study guides मराठी

Chapter 59: Kubernetes Pods in Depth: Architecture, YAML Anatomy and Pod Types

59.2 YAML file anatomy: read any Kubernetes file line by line

Why: the problem

Suppose you join the Infosys platform team on Monday. Your lead sends a 200-line YAML file and says: please add a memory limit and a new label. You open it and see apiVersion, kind, metadata, spec, template, selector, matchLabels. Where does the limit go? Which label is safe to change? One wrong indent and kubectl says error. One wrong label and the Deployment loses its pods. Good news: every Kubernetes file follows the same four-part shape. Once you see the shape, any file becomes easy. In this lesson we read YAML like a map, use kubectl explain as a built-in dictionary, and catch mistakes before they reach the cluster.

What: every term in plain English

  • YAML — A text format for data. It uses indentation (spaces, never tabs) to show what belongs inside what.
  • Key: value — One setting, for example replicas: 3.
  • List item (-) — A dash starts one item of a list, for example one container.
  • apiVersion — Which API group and version handles this object, like v1 or apps/v1.
  • kind — The type of object: Pod, Deployment, Service, ConfigMap and so on.
  • metadata — The identity: name, namespace, labels and annotations.
  • spec — What you want. You write it.
  • status — What is really happening. Kubernetes writes it. Never put it in your file.
  • Label — A key-value tag used to select objects, for example app: cart.
  • Selector — A query that picks objects by labels.
  • Annotation — A key-value note for tools and humans. It is not used for selecting.
  • kubectl explain — Prints the official documentation for any field, straight from the cluster.
  • Dry run — Checks a file without saving it. Client dry run checks locally; server dry run asks the API server.
Find the four parts. Find the API group. Look up a field. Generate a skeleton. Edit with care. Validate. Apply and compare.
The four parts of every Kubernetes YAML file

How: step by step

  1. Find the four parts. apiVersion, kind, metadata, spec. Every object has them.
  2. Find the API group. Run kubectl api-resources to see the group and version for each kind.
  3. Look up a field. kubectl explain deployment.spec.template.spec.containers.resources.
  4. Generate a skeleton. kubectl create deployment cart --image=nginx --dry-run=client -o yaml.
  5. Edit with care. Two spaces per level. Lists start with a dash. Never tabs.
  6. Validate. kubectl apply --dry-run=server -f file.yaml, then kubectl diff -f file.yaml.
  7. Apply and compare. kubectl apply, then kubectl get -o yaml to see the status Kubernetes added.

Example 1: Read a full Deployment and Service file part by part

Goal. Read a full Deployment and Service file part by part.

cart.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: cart
  namespace: shop
  labels:
    app: cart
    team: checkout
  annotations:
    owner: "checkout-team@example.com"
spec:
  replicas: 2
  selector:
    matchLabels:
      app: cart
  template:
    metadata:
      labels:
        app: cart
        version: "1.0"
    spec:
      containers:
        - name: cart
          image: nginx:1.27
          ports:
            - containerPort: 80
              name: http
          env:
            - name: CURRENCY
              value: "INR"
          resources:
            requests:
              cpu: 100m
              memory: 64Mi
            limits:
              memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
  name: cart
  namespace: shop
spec:
  selector:
    app: cart
  ports:
    - port: 80
      targetPort: http

What each line does

  • apiVersion: apps/v1 — Deployment is in the apps group. Pods and Services are in the core group, written just v1.
  • metadata.namespace: shop — The object lives in the shop namespace. The namespace must exist first.
  • metadata.labels — Labels on the Deployment itself. Useful for kubectl get -l team=checkout.
  • annotations.owner — A note. Tools and people read it; selectors ignore it.
  • spec.selector.matchLabels — Which pods this Deployment owns. It must match the template labels. It cannot be changed later.
  • template.metadata.labels — Labels stamped on each pod. version can change; app must stay, or the selector breaks.
  • containers: - name: cart — A list. The dash starts the first container.
  • ports.name: http — A named port. The Service uses targetPort: http, so the number can change in one place.
  • value: "INR" — Env values must be strings. Quote numbers and yes/no values.
  • requests / limits — requests help the scheduler; the memory limit is the hard ceiling.
  • --- — Separates two objects in one file.
  • Service spec.selector — Sends traffic to pods with app: cart. Same label, different object.

Green output

$ kubectl create namespace shop
namespace/shop created
$ kubectl apply -f cart.yaml
deployment.apps/cart created
service/cart created
$ kubectl get deploy,svc,pods -n shop --show-labels
NAME                   READY   UP-TO-DATE   AVAILABLE   LABELS
deployment.apps/cart   2/2     2            2           app=cart,team=checkout
NAME           TYPE        CLUSTER-IP     PORT(S)   LABELS
service/cart   ClusterIP   10.96.142.17   80/TCP    none
NAME                        READY   STATUS    LABELS
pod/cart-6f7d9c8b4-2lq8x    1/1     Running   app=cart,pod-template-hash=6f7d9c8b4,version=1.0
pod/cart-6f7d9c8b4-wn5zk    1/1     Running   app=cart,pod-template-hash=6f7d9c8b4,version=1.0

Expected result. Two objects from one file. Pods got the template labels plus pod-template-hash added by the ReplicaSet.

Example 2: Use kubectl explain and api-resources as your dictionary

Goal. Use kubectl explain and api-resources as your dictionary.

explain.sh

kubectl api-resources | grep -E 'NAME|^pods|^deployments|^services|^cronjobs|^ingresses'
kubectl explain deployment
kubectl explain deployment.spec.strategy
kubectl explain pod.spec.containers.resources --recursive
kubectl explain pod.spec.containers.livenessProbe.httpGet

What each line does

  • api-resources — Lists every kind, its short name, its API group and whether it is namespaced.
  • explain deployment — Shows the group, version and top fields with a short description.
  • explain ... .strategy — Goes deeper, one dot per level, like a path in the YAML.
  • --recursive — Shows the whole tree under a field, with types.
  • Why not Google? — explain matches the exact version of your cluster. Official docs are at kubernetes.io/docs/reference.

Green output

$ kubectl api-resources | grep -E 'NAME|^pods|^deployments|^services|^cronjobs|^ingresses'
NAME          SHORTNAMES   APIVERSION             NAMESPACED   KIND
pods          po           v1                     true         Pod
services      svc          v1                     true         Service
cronjobs      cj           batch/v1               true         CronJob
deployments   deploy       apps/v1                true         Deployment
ingresses     ing          networking.k8s.io/v1   true         Ingress
$ kubectl explain deployment.spec.strategy
GROUP:      apps
KIND:       Deployment
VERSION:    v1
FIELD: strategy (DeploymentStrategy)
DESCRIPTION:
    The deployment strategy to use to replace existing pods with new ones.
FIELDS:
  rollingUpdate (RollingUpdateDeployment)
  type  (string)
    Type of deployment. Can be "Recreate" or "RollingUpdate". Default is RollingUpdate.
$ kubectl explain pod.spec.containers.resources --recursive
FIELDS:
  claims    ([]ResourceClaim)
    name    (string) -required-
  limits    (map[string]Quantity)
  requests  (map[string]Quantity)

Expected result. You can find any field and its type without leaving the terminal.

Example 3: Generate, validate and diff before you apply

Goal. Generate, validate and diff before you apply.

safe-edit.sh

kubectl create deployment report --image=python:3.12-slim -n shop \
  --dry-run=client -o yaml > report.yaml
kubectl apply --dry-run=server -f report.yaml
kubectl apply -f cart.yaml
sed -i 's/replicas: 2/replicas: 3/' cart.yaml
kubectl diff -f cart.yaml
kubectl apply -f cart.yaml
kubectl get deploy cart -n shop -o yaml | sed -n '/^status:/,$p'

What each line does

  • --dry-run=client -o yaml — Creates a correct skeleton file without touching the cluster.
  • --dry-run=server — The API server fully validates the file, including defaults and admission rules, but saves nothing.
  • kubectl diff — Shows exactly what will change in the cluster, like git diff.
  • sed -n '/^status:/,$p' — Prints only the status part that Kubernetes wrote.

Green output

$ kubectl apply --dry-run=server -f report.yaml
deployment.apps/report created (server dry run)
$ kubectl diff -f cart.yaml
-  replicas: 2
+  replicas: 3
-  generation: 1
+  generation: 2
$ kubectl apply -f cart.yaml
deployment.apps/cart configured
service/cart unchanged
status:
  availableReplicas: 3
  observedGeneration: 2
  readyReplicas: 3
  replicas: 3
  updatedReplicas: 3

Expected result. You changed one value safely, saw the diff first, and confirmed status matches spec.

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

  1. Create the namespace

    kubectl create namespace shop
    

    What it does: Namespaces group objects. Our files use shop.

    namespace/shop created
    
  2. Apply the two-object file

    kubectl apply -f cart.yaml
    

    What it does: Creates the Deployment and the Service.

    deployment.apps/cart created
    service/cart created
    
  3. Find objects by label

    kubectl get all -n shop -l app=cart
    

    What it does: Labels are how you search.

    pod/cart-6f7d9c8b4-2lq8x   1/1   Running
    service/cart               ClusterIP   10.96.142.17
    deployment.apps/cart       2/2
    
  4. See the Endpoints the selector found

    kubectl get endpointslices -n shop -l kubernetes.io/service-name=cart
    

    What it does: The Service selector found the two pod IPs.

    NAME         ADDRESSTYPE   PORTS   ENDPOINTS
    cart-x7k2p   IPv4          80      10.244.1.6,10.244.2.7
    
  5. Change a pod label by hand

    kubectl label pod -n shop -l app=cart app=broken --overwrite
    kubectl get pods -n shop --show-labels
    

    What it does: Pods with app=broken no longer match, so the ReplicaSet makes two new ones. The old ones become orphans.

    cart-6f7d9c8b4-2lq8x   1/1   Running   app=broken
    cart-6f7d9c8b4-wn5zk   1/1   Running   app=broken
    cart-6f7d9c8b4-9fz3m   1/1   Running   app=cart
    cart-6f7d9c8b4-qk7rd   1/1   Running   app=cart
    
  6. Clean orphans

    kubectl delete pod -n shop -l app=broken
    

    What it does: Labels are powerful. Change them with care.

    pod "cart-6f7d9c8b4-2lq8x" deleted
    pod "cart-6f7d9c8b4-wn5zk" deleted
    
  7. Read the full live object

    kubectl get deploy cart -n shop -o yaml | head -30
    

    What it does: You see your fields plus defaults Kubernetes filled in, like strategy and revisionHistoryLimit.

    progressDeadlineSeconds: 600
    replicas: 3
    revisionHistoryLimit: 10
    strategy:
      rollingUpdate:
        maxSurge: 25%
        maxUnavailable: 25%
      type: RollingUpdate
    

When it is red 1

error: error parsing cart.yaml: error converting YAML to JSON: yaml: line 21: found character that cannot start any token

Cause. A tab character, or a wrong indent, on line 21.

Fix, step by step

  1. Open the file and go to line 21.
  2. Replace tabs with spaces. In vim use :set expandtab then :retab.
  3. Keep two spaces per level.
  4. Run kubectl apply --dry-run=client -f cart.yaml again.

When it is red 2

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

Cause. The template labels do not match spec.selector.matchLabels.

Fix, step by step

  1. Make the template label app: cart, the same as the selector.
  2. Never change the selector of an existing Deployment; delete and recreate if you must.
  3. Validate with --dry-run=server.

When it is red 3

json: cannot unmarshal number into Go struct field EnvVar.spec.template.spec.containers.env.value of type string

Cause. An env value is a number without quotes, like value: 8080.

Fix, step by step

  1. Write value: "8080" with quotes.
  2. Also quote true, false, yes and no.
  3. Apply again.

When it is red 4

error: resource mapping not found for name: "cart" namespace: "" from "cart.yaml": no matches for kind "Deployment" in version "extensions/v1beta1"

Cause. An old apiVersion that was removed from Kubernetes.

Fix, step by step

  1. Run kubectl api-resources | grep deployments to see the right version.
  2. Change apiVersion to apps/v1.
  3. Add spec.selector, which apps/v1 requires.

Practice tasks

Easy Task 1: Four parts

Why: Shape first.

What to do: Mark apiVersion, kind, metadata, spec in cart.yaml.

How:
  1. Open the file.
  2. Mark each part.
Solution
apiVersion / kind / metadata / spec

Easy Task 2: Skeleton

Why: Never type from zero.

What to do: Generate a Deployment YAML for redis:7.

How:
  1. Use --dry-run=client -o yaml.
Solution
kubectl create deployment cache --image=redis:7 --dry-run=client -o yaml

Easy Task 3: Short names

Why: Speed.

What to do: Find the short names of 5 kinds.

How:
  1. Run api-resources.
Solution
kubectl api-resources

Medium Task 4: Explain

Why: Self-help.

What to do: Find what maxSurge means.

How:
  1. Use kubectl explain.
Solution
kubectl explain deployment.spec.strategy.rollingUpdate.maxSurge

Medium Task 5: Server dry run

Why: Catch errors early.

What to do: Break a label and catch it with server dry run.

How:
  1. Change template label.
  2. Run dry run.
Solution
kubectl apply --dry-run=server -f cart.yaml

Medium Task 6: Diff

Why: Safe change.

What to do: Add a memory request change and view the diff.

How:
  1. Edit the file.
  2. kubectl diff.
Solution
kubectl diff -f cart.yaml

Medium Task 7: Label query

Why: Searching.

What to do: List all objects with team=checkout in shop.

How:
  1. Use -l.
Solution
kubectl get all -n shop -l team=checkout

Medium Task 8: Annotate

Why: Notes.

What to do: Add an annotation change-cause to the Deployment.

How:
  1. kubectl annotate.
Solution
kubectl annotate deploy cart -n shop kubernetes.io/change-cause="replicas 3"

Hard Task 9: Orphans

Why: Selector power.

What to do: Relabel one pod and explain the new pod count.

How:
  1. kubectl label --overwrite.
  2. Count pods.
Solution
kubectl label pod POD -n shop app=x --overwrite
kubectl get pods -n shop

Hard Task 10: Live vs file

Why: Defaults.

What to do: List three fields in the live object that are not in your file.

How:
  1. get -o yaml.
  2. Compare.
Solution
kubectl get deploy cart -n shop -o yaml

Homework: try at home

Take any YAML from chapter 18. Write the four parts in your notebook and, for every line, say whether it is identity, wanted state or a pod blueprint.

Recap

  • Every object has apiVersion, kind, metadata and spec; Kubernetes adds status.
  • Indent with two spaces, never tabs; dashes start list items.
  • The selector must match the template labels.
  • kubectl explain and api-resources are your offline dictionary.
  • Use dry-run=server and diff before apply.
  • Chapter 18.7 shows a Deployment file; this lesson explains every line of any file.

FAQ

Q. Can I use JSON instead of YAML?

Yes, the API accepts both. YAML is easier to read and comment.

Q. Why does my file have status after kubectl get -o yaml?

That is the live object. Do not copy status back into your file.

Q. How many spaces should I use?

Two per level is the common style. The number must just be the same everywhere.

Q. What is the difference between apply and create?

create fails if the object exists. apply creates or updates, and remembers what you applied.

Q. Where are the official docs?

kubernetes.io/docs/reference/kubernetes-api lists every kind and field.

Q. How do I check many files in CI?

Run kubectl apply --dry-run=server in a test cluster, or a schema tool like kubeconform.

Interview questions

  1. Explain the structure of a Kubernetes manifest.

    Model answer: apiVersion and kind say which API handles the object, metadata gives identity and labels, spec is the wanted state, and status is filled by controllers.

  2. Difference between labels and annotations?

    Model answer: Labels are short identifying tags used by selectors; annotations hold non-identifying data for tools, like change-cause or ingress settings.

  3. Why must the Deployment selector match the template labels?

    Model answer: The Deployment and ReplicaSet find their pods by selector. If the pods do not match, they would never count as owned, so the API rejects it.

  4. How do you validate manifests before production?

    Model answer: Server-side dry run, kubectl diff, schema validation in CI, and policy tools like Kyverno or OPA Gatekeeper.

  5. What is the difference between client and server dry run?

    Model answer: Client dry run only checks locally. Server dry run runs full validation and admission on the API server without saving.

Quick quiz

Q1. Which four top-level fields does almost every object have?

apiVersion, kind, metadata and spec.

Q2. Who writes the status section?

Kubernetes controllers, not you.

Q3. Labels or annotations: which are used by selectors?

Labels.

Q4. Which command shows docs for a field?

kubectl explain, for example kubectl explain pod.spec.containers.

Q5. How do you see changes before applying?

kubectl diff -f file.yaml.

Samajla ka?