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.
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.
What it is made of#
| Part | Purpose |
|---|---|
| App container | Your program. Usually the only one |
| Init containers | Run to completion before app containers start |
| Sidecar containers | Run alongside the app (proxy, log shipper, agent) |
| Volumes | Storage shared between the containers in the pod |
| Pause container | Hidden. 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:
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: AlwaysInit 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 containerInit: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 laptopPods are disposable — design for it#
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#
| Symptom | Cause | Fix |
|---|---|---|
Stuck at Init:0/1 | Init container waiting or failing | kubectl logs <pod> -c <init-name> |
0/2 READY but Running | One container's readiness probe failing | kubectl describe pod |
| One container restarts, others do not | Only that container is failing | kubectl logs <pod> -c <name> --previous |
| "container name must be specified" | Multi-container pod | Add -c <name> |
| Both containers want port 8080 | They share one network namespace | Change one of them |
| Data gone after restart | emptyDir or the container filesystem | Use a PVC |
When a second container is justified#
| Pattern | Example | Is it right? |
|---|---|---|
| Sidecar | Log shipper, service-mesh proxy | Yes — needs the same net/fs |
| Init | Wait for a dependency, run a migration | Yes |
| Adapter | Reformat the app's metrics for a scraper | Yes |
| Two unrelated services | An API and a worker | No — 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.
إمتى يبقى الكونتينر التاني مبرّر فعلاً؟
| النمط | مثال | صح؟ |
|---|---|---|
| Sidecar | log shipper، بروكسي service mesh | ✔ محتاج نفس الشبكة/الملفات |
| Init | يستنى dependency، يشغّل migration | ✔ |
| Adapter | يحوّل مقاييس التطبيق لشكل تاني | ✔ |
| سيرفيسين مالهمش علاقة | API و worker | ✘ Deployments منفصلة |
والاختبار اللي يحسم الموضوع في ثانية:
Noteهل ممكن في أي وقت تحب تعمل scale لواحد منهم لوحده؟
لو الإجابة أيوه، يبقى هما في بودات مختلفة. خلاص، مفيش نقاش.
عشان الـ Pod بيعمل scale كوحدة واحدة. فلو حزمت API مع worker في بود واحد، إنت حرمت نفسك للأبد إنك يكون عندك ١٠ من الـ API و ٢ من الـ worker. هتبقى مجبور تعمل ١٠ من الاتنين، وتدفع في worker مش محتاجه.
والقاعدة العامة: الكونتينر التاني ينفع بس لو مضطر يتشارك شبكة البود أو ملفاته. لو مش مضطر، فصله.
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.
"So why not put the whole application in one Pod?" Because the Pod is also the unit of scaling, and that is the tension. Everything in a Pod scales together and dies together. So the design rule falls out of the mechanism: put things in one Pod only when they must share the network or filesystem, and never when you might want to scale them independently.
عشان فيه مساعِدين بلا فايدة إلا لو كانوا جوه شبكة التطبيق وملفاته، وموديل الكونتينر لوحده مفيهوش طريقة تقول «الاتنين دول وحدة واحدة».
الـ log shipper لازم يقرا ملفات التطبيق. وبروكسي الـ service mesh لازم يعترض ترافيك التطبيق على localhost، ولازم يمسك نفس الـ IP عشان الشبكة تشوف عنوان واحد.
والاتنين محتاجين إنهم يكونوا مع بعض مضمون، مش محتمل.
كوبرنيتيس كان يقدر يضيف قواعد affinity للكونتينرات، بس دي بتخليها مرجّحة إنهم يقعدوا مع بعض، مش مضمونة. الـ Pod بيخليها ذرّية: وحدة جدولة واحدة، IP واحد، دورة حياة واحدة، نود واحدة — مضمون.
والسؤال اللي بيجي بعده: «أمال ما نحط التطبيق كله في Pod واحد؟»
عشان الـ Pod كمان هو وحدة الـ scaling. وهنا التوتر: كل حاجة في الـ Pod بتعمل scale مع بعض وبتموت مع بعض.
فالقاعدة بتطلع من الميكانيزم نفسه: حط حاجات في Pod واحد بس لما تكون مضطرة تتشارك الشبكة أو الملفات، وعمرك ما تحطهم لو ممكن تحب تعمل scale لواحد منهم لوحده.
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 5432The three causes, in the order they actually occur:
| Cause | Tell |
|---|---|
| The Service name or port is wrong | kubectl get svc — no such Service, or a different port |
| The Service exists but has no Ready pods | kubectl get endpoints db shows <none> |
| A NetworkPolicy blocks egress from this namespace | Works from one namespace, not another |
An interviewer may follow with: "is waiting for the database in an init container even the right design?" Often no. It makes the app unable to start at all during a brief database blip, and it does not help once the app is running — the database can still go away a second later.
The more robust pattern is an app that retries its connection with backoff and reports itself not-ready via a readiness probe until it succeeds. The init container turns a transient dependency failure into a hard startup failure.
امشي على التلات خطوات دي بالترتيب:
١. kubectl logs <pod> -c wait-for-db — هو بيقول إيه أصلاً؟ ٢. kubectl get endpoints db — الحاجة اللي مستنيها موجودة ولا <none>؟ ٣. جرّب توصلها من بود تاني: nc -zv db 5432
والتلات أسباب بترتيب حدوثهم:
| السبب | تعرفه إزاي |
|---|---|
| اسم الـ Service أو البورت غلط | kubectl get svc — مفيش، أو بورت تاني |
| الـ Service موجودة بس مفيش بودات Ready وراها | get endpoints = <none> |
| NetworkPolicy مانعة الخروج من الـ namespace دي | بتنفع من namespace وتفشل من تانية |
وفيه سؤال تصميم مخبّي في السؤال ده، ساعات بيسألوه بعده:
Note«وهل إنك تستنى الداتابيز في init container ده أصلاً تصميم صح؟»
وغالباً لأ. عشان ده بيخلي التطبيق مش قادر يقوم خالص لو الداتابيز تعثّرت لحظة، وكمان مش بينفع بعد ما التطبيق يقوم — الداتابيز تقدر تروح بعد ثانية وإنت معملتش حاجة.
النمط الأقوى: التطبيق يعيد المحاولة بـ backoff، ويقول عن نفسه إنه مش Ready (من خلال readiness probe) لحد ما ينجح.
الـ init container بيحوّل فشل مؤقت في dependency لـ فشل نهائي في الإقلاع. وده مقايضة غالباً مش في مصلحتك.
Key takeaways#
- A pod is one or more containers sharing an IP and volumes, always on one node.
- They talk over
localhostand 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.
emptyDirdies with the pod. Use a PVC for real data.- With multiple containers,
logsandexecneed-c <name>. - Second container only if it must share the pod's network or filesystem.
- الـ Pod كونتينر أو أكتر بيتشاركوا IP وملفات، وعلى نود واحدة دايماً.
- بيكلّموا بعض على
localhost، ومش ينفع اتنين ياخدوا نفس البورت. - الـ init containers بتخلص الأول — دي الأداة الصح لو محتاج ترتيب.
- البودات بتتخلق عشان تموت: بود جديد = IP جديد وفايل سيستم فاضي.
- الـ
emptyDirبيموت مع البود. للداتا الحقيقية استخدم PVC. - مع أكتر من كونتينر، الـ
logsوالـexecمحتاجين-c <name>. - كونتينر تاني بس لو مضطر يتشارك شبكة البود أو ملفاته. والاختبار: لو ممكن تحب تعمل scale لواحد لوحده، يبقى فصلهم.
Last updated 2026-09-08