Gendi Notes

Kubernetes Pods

A pod is not "a container" — it is a small group of containers that share an IP address and a filesystem, and always live and die together.

Level 2 guide kubernetespodscontainers

What is it?#

A pod is the smallest thing Kubernetes can schedule. It wraps one or more containers that:

  • share one IP address (they reach each other on localhost)
  • can share volumes
  • are always placed on the same node
  • start and stop together

Most pods contain exactly one container. The ability to hold more exists for a specific pattern, not as a way to bundle unrelated services.

Why it exists#

Some helpers only make sense right next to the application — a log shipper reading the app's files, a proxy handling its network traffic. They need the same filesystem and the same network as the app.

Rather than complicate the container model, Kubernetes added a wrapper: the pod is the unit of scheduling, and containers inside it are as close together as two processes on one machine.

┌──────────── POD (one IP: 10.1.0.4) ────────────┐ │ │ │ ┌───────────┐ ┌──────────────┐ │ │ │ app │ ←────────→ │ log shipper │ │ │ │ :8080 │ localhost └──────┬───────┘ │ │ └─────┬─────┘ │ │ │ │ shared volume │ │ │ └────────── /logs ────────┘ │ └────────────────────────────────────────────────┘

What it is made of#

PartPurpose
App containerYour program. Usually the only one
Init containersRun to completion before app containers start
Sidecar containersRun alongside the app (proxy, log shipper, agent)
VolumesStorage shared between the containers in the pod
Pause containerHidden. Holds the network namespace open so containers keep one IP

How to use it#

You rarely write a Pod manifest directly — you write a Deployment, and the pod spec lives inside its template. But you need to read it:

A pod spec with an init container and a sidecar
apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    app: web
spec:
  # Run first, to completion, in order. The app does not start until all pass.
  initContainers:
    - name: wait-for-db
      image: busybox:1.36
      command: ['sh', '-c', 'until nc -z db 5432; do sleep 2; done']

  containers:
    - name: app
      image: myapp:1.0
      ports:
        - containerPort: 8080
      volumeMounts:
        - name: logs
          mountPath: /var/log/app

    - name: log-shipper            # sidecar: reads what the app writes
      image: fluent-bit:3.1
      volumeMounts:
        - name: logs
          mountPath: /var/log/app
          readOnly: true

  volumes:
    - name: logs
      emptyDir: {}                 # lives and dies with the pod

  restartPolicy: Always

Init containers are the right tool for ordering#

An init container must exit 0 before the next one starts, and all must finish before app containers begin. Use them for:

  • waiting for a dependency to be reachable
  • running a database migration
  • fetching config or a secret into a shared volume
kubectl get pods
# NAME   READY   STATUS      RESTARTS   AGE
# web    0/2     Init:0/1    0          10s    ← still in the init container

Init:0/1 means the first of one init container has not finished. If it stays there, kubectl logs <pod> -c wait-for-db tells you what it is waiting for.

Useful commands#

kubectl get pods -o wide                  # includes pod IP and node
kubectl describe pod <pod>                # events, state, probe results
kubectl logs <pod>                        # single-container pod
kubectl logs <pod> -c app                 # name the container when there are several
kubectl logs <pod> -c app --previous      # the crashed instance
kubectl exec -it <pod> -c app -- sh       # shell inside a specific container
kubectl port-forward pod/<pod> 8080:8080  # reach it from your laptop

Pods are disposable — design for it#

pod restarts → SAME pod, containers restarted, IP KEPT pod deleted → GONE. A new pod: new name, NEW IP, empty filesystem

Three rules follow:

  • Never store data in a container's filesystem. It is wiped on restart. Use a PersistentVolume for anything that must survive.
  • Never rely on a pod's IP. Use a Service.
  • Handle SIGTERM. Kubernetes sends it, waits terminationGracePeriodSeconds (30 by default), then SIGKILLs. An app that ignores it loses in-flight requests on every deploy.

Common problems#

SymptomCauseFix
Stuck at Init:0/1Init container waiting or failingkubectl logs <pod> -c <init-name>
0/2 READY but RunningOne container's readiness probe failingkubectl describe pod
One container restarts, others do notOnly that container is failingkubectl logs <pod> -c <name> --previous
"container name must be specified"Multi-container podAdd -c <name>
Both containers want port 8080They share one network namespaceChange one of them
Data gone after restartemptyDir or the container filesystemUse a PVC

When a second container is justified#

PatternExampleIs it right?
SidecarLog shipper, service-mesh proxyYes — needs the same net/fs
InitWait for a dependency, run a migrationYes
AdapterReformat the app's metrics for a scraperYes
Two unrelated servicesAn API and a workerNo — separate Deployments

The test: would you ever want to scale them separately? If yes, they belong in different pods. A pod scales as one unit; bundling an API with a worker means you can never have 10 of one and 2 of the other.

Interview corner · الأسئلة اللي بتتسأل#

Why does Kubernetes have Pods at all? Why not just schedule containers?

Because some helpers are useless unless they are inside the application's network and filesystem, and the container model has no way to express "these two are one unit".

A log shipper must read the app's files. A service-mesh proxy must intercept the app's traffic on localhost and must own the same IP so the network sees one address. Both need co-location guaranteed, not likely.

Kubernetes could have added "affinity" rules to containers, but that only makes it probable they land together. The Pod makes it atomic: one scheduling unit, one IP, one lifecycle, one node — guaranteed.

An init container waits for the database and the Pod is stuck at Init:0/1 forever. Walk me through it.
# 1. What is it actually saying?
kubectl logs <pod> -c wait-for-db

# 2. Is the thing it waits for even there?
kubectl get svc db
kubectl get endpoints db        # <none> means the Service has no backends

# 3. Can anything reach it from this namespace?
kubectl run t --rm -it --image=busybox --restart=Never -- nc -zv db 5432

The three causes, in the order they actually occur:

CauseTell
The Service name or port is wrongkubectl get svc — no such Service, or a different port
The Service exists but has no Ready podskubectl get endpoints db shows <none>
A NetworkPolicy blocks egress from this namespaceWorks from one namespace, not another

Key takeaways#

  • A pod is one or more containers sharing an IP and volumes, always on one node.
  • They talk over localhost and cannot reuse the same port.
  • Init containers run to completion first — the right tool for ordering.
  • Pods are disposable: new pod means new IP and empty filesystem.
  • emptyDir dies with the pod. Use a PVC for real data.
  • With multiple containers, logs and exec need -c <name>.
  • Second container only if it must share the pod's network or filesystem.

Last updated 2026-09-08