This is one of the most important Kubernetes chapters because Pods are the basic building blocks of Kubernetes workloads.
If you understand Pods properly, Deployments, Services, scaling, networking, and troubleshooting will become much easier.
The official concept is:
A Pod is the smallest deployable unit in Kubernetes.
A Pod contains one or more containers that are managed together.
The most common case is:
Pod
└── ContainerFor example:
Pod: node-api
└── Node.js containerBut a Pod can also contain multiple containers:
Pod
├── Application container
└── Sidecar containerThis is an important question.
You might think:
"If Docker/containerd already runs containers, why did Kubernetes create Pods?"
Because Kubernetes wants a unit that represents a group of tightly coupled containers sharing certain resources and lifecycle characteristics.
A Pod provides:
So Kubernetes doesn't normally think:
Run container A on Node 1.It thinks:
Run Pod X on Node 1.Then the Pod contains the container(s).
Think of a Pod like an apartment.
Apartment
├── Person A
└── Person BThe people share the apartment's:
Similarly:
Pod
├── Container A
└── Container BContainers in the same Pod share:
You'll often see:
Pod
└── ContainerThat's because Kubernetes commonly uses:
One main application container per Pod.
For example:
Pod
└── Node.js APIThen scaling becomes simple:
3 Pods
=
3 Node.js application instancesSometimes containers need to work extremely closely together.
Example:
Pod
├── Node.js API
└── Logging sidecarThe sidecar might collect or process logs.
Another example:
Pod
├── Application
└── ProxyThe important concept is:
Containers in the same Pod are co-located and share the Pod's network identity.
Suppose:
Pod
├── Container A
└── Container BThey share the same network namespace.
Therefore they can communicate through:
localhostFor example:
Container A
↓
localhost:8080
↓
Container BThis is very different from two separate Pods.
Pod
├── A
└── BA can communicate with B using:
localhost:<port>Pod A Pod B
│ │
└──── network ─────┘They communicate through the Kubernetes network, usually using Pod IPs or, more commonly for stable communication, a Service.
We'll study Services later.
Every Pod normally receives its own IP address.
For example:
Pod A → 10.244.0.10
Pod B → 10.244.0.11
Pod C → 10.244.0.12You can see the IP using:
kubectl get pods -o wideExample:
NAME READY STATUS IP NODE
api 1/1 Running 10.244.0.10 node-1
web 1/1 Running 10.244.0.11 node-2This is extremely important.
Don't assume:
api → 10.244.0.10will always remain true.
If the Pod is deleted and recreated:
Old Pod
10.244.0.10
↓
Deleted
New Pod
10.244.0.25The IP may change.
That's one reason we use Services.
We'll cover that in Chapter 7.
You already saw:
kubectl run nginx --image=nginxThis creates a Pod.
Check it:
kubectl get podsExample:
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 30sIn real Kubernetes work, you'll frequently use YAML.
Create:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80Save as:
pod.yamlThen:
kubectl apply -f pod.yamlCheck:
kubectl get podsLet's break it down.
apiVersion#apiVersion: v1Specifies the API version for the resource.
For a basic Pod:
v1kind#kind: PodTells Kubernetes:
I am creating a Pod.
metadata#metadata:
name: nginxProvides identifying information.
Here:
Name = nginxspec#spec:Defines the desired configuration of the Pod.
containers#containers:
- name: nginx
image: nginx:latestDefines the container(s) inside the Pod.
containerPort#You may see:
ports:
- containerPort: 80This documents that the container is expected to use port 80.
Important:
containerPortdoes not automatically expose the application outside the cluster.
We'll use a Service to expose applications.
Pods have a lifecycle.
A simplified view:
Pending
↓
Running
↓
Succeededor:
Pending
↓
Running
↓
FailedLet's understand these.
When a Pod is:
Pendingit means it hasn't reached the running state yet.
Possible reasons include:
Example:
NAME READY STATUS
api 0/1 PendingYou would investigate with:
kubectl describe pod apiEspecially check the Events section.
STATUS
Runningmeans the Pod has been successfully placed on a node and its containers are running or in the process of being started.
Example:
api 1/1 RunningA Pod can complete successfully.
For example, a one-time task:
Run database migration
↓
Task completes
↓
SucceededThis is more common with Jobs than long-running web applications.
If the containers terminate unsuccessfully and Kubernetes doesn't restart them into a successful state according to the Pod's configuration, the Pod can end up in a failed state.
For example:
Run script
↓
Error
↓
FailedCrashLoopBackOff?#You'll encounter this constantly in Kubernetes troubleshooting.
Suppose your application starts:
Application starts
↓
Application crashes
↓
Kubernetes restarts it
↓
Application crashes again
↓
Restart
↓
CrashKubernetes gradually backs off between restart attempts.
You may see:
CrashLoopBackOffIt essentially tells you:
The container keeps crashing and Kubernetes is repeatedly trying to restart it with increasing delays.
Debug it using:
kubectl logs <pod>and:
kubectl describe pod <pod>kubectl logs --previous#This is extremely useful for crashing containers.
Suppose the container:
starts → crashes → restartsYou can inspect the logs from the previous container instance:
kubectl logs <pod> --previousThis can reveal why the previous process crashed.
Pods have a restart policy.
Common values:
Always
OnFailure
NeverRestart the container when it terminates.
Common for long-running workloads.
Restart when the container exits unsuccessfully.
Don't restart the container automatically.
We'll explore this more when we study Jobs and Deployments.
This is very important.
You might create:
Pod
└── Node.jsBut if that Pod dies, you don't necessarily have the robust application management you'd want.
Instead, production applications usually use:
Deployment
↓
ReplicaSet
↓
PodsFor example:
Deployment
↓
ReplicaSet
↓
┌───────┬───────┬───────┐
Pod 1 Pod 2 Pod 3The Deployment says:
"I want 3 copies."
The controllers work to maintain that state.
Imagine you manually create:
Pod 1
Pod 2
Pod 3What happens when Pod 2 dies?
You would have to manage the replacement yourself.
Instead:
Deployment
↓
Desired replicas = 3
↓
Pod 1
Pod 2
Pod 3If Pod 2 disappears:
Pod 1
Pod 3Kubernetes works toward:
Pod 1
Pod 3
Pod 4This is why Deployments are normally used for stateless applications.
This is another concept you must remember.
Pods are not permanent machines.
A Pod may be:
Created
↓
Running
↓
DeletedAnd a replacement Pod may have:
For example:
api-abc123dies.
Replacement:
api-xyz789So applications shouldn't depend on a specific Pod identity.
This raises an important question.
If Pods are ephemeral:
"Where should my database data go?"
Not directly inside the container's writable filesystem if you need it to survive Pod replacement.
Kubernetes provides persistent storage mechanisms such as:
PersistentVolume
PersistentVolumeClaim
StorageClassWe'll cover these later.
Every Pod generally gets its own IP.
Suppose:
Frontend Pod
10.244.0.10
Backend Pod
10.244.0.11The Kubernetes networking model aims to allow Pods to communicate across nodes without requiring manual NAT between Pod addresses.
Conceptually:
Frontend Pod
│
│
↓
Kubernetes Network
│
↓
Backend PodThe exact implementation depends on the cluster's CNI/network plugin.
Imagine:
Node 1
└── Frontend Pod
10.244.0.10
Node 2
└── Backend Pod
10.244.1.20Kubernetes networking allows the Pods to communicate across nodes.
Frontend
│
└──────── Kubernetes network ────────┐
↓
Backend PodWe'll go deep into this in the networking chapter.
Let's look at a conceptual example:
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: my-app
- name: sidecar
image: log-agentNow:
Pod
├── app container
└── sidecar containerBoth share the Pod's network namespace.
A sidecar is a helper container that runs alongside the main application.
Example:
Pod
├── Node.js Application
└── Log CollectorThe application generates logs.
The sidecar processes or forwards them.
Another pattern:
Pod
├── Application
└── ProxyThe proxy might handle networking concerns.
Sidecars are useful, but don't put unrelated applications together just because Kubernetes allows multiple containers in a Pod.
Containers in the same Pod can also share a Kubernetes volume.
Conceptually:
Pod
├── App Container
│
├── Sidecar Container
│
└── Shared VolumeBoth containers can mount the same volume.
Example:
App
↓
/shared/logs
↑
SidecarWe'll study volumes separately.
Another useful Pod concept is an Init Container.
An init container runs before the main application containers.
Example:
Pod
│
├── Init Container
│ ↓
│ Prepare environment
│
└── Application Container
↓
Start applicationFor example, an init container might:
Once the init container successfully finishes, the main container can start.
Kubernetes can check application health.
Three important probes:
Startup Probe
Readiness Probe
Liveness ProbeWe'll study these in depth later.
Conceptually:
Application
↓
Health checks
↓
KubernetesFor example:
Readiness = "Can I send traffic to you?"
Liveness = "Are you still alive?"
Startup = "Have you finished starting?"A Pod's containers can have resource requirements.
For example:
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"This tells Kubernetes about:
"I need approximately this much to be scheduled."
"Don't allow this container to use beyond this configured limit for that resource."
This becomes very important for scheduling and autoscaling.
We'll cover it in detail later.
Suppose you have:
Node.js APIYou create:
Docker ImageThen Kubernetes creates:
Pod
└── Node.js ContainerIf you want three instances:
Deployment
↓
ReplicaSet
↓
┌──────────┬──────────┬──────────┐
Pod 1 Pod 2 Pod 3
│ │ │
Node.js Node.js Node.jsThen a Service provides stable access:
Service
↓
┌────────┼────────┐
↓ ↓ ↓
Pod 1 Pod 2 Pod 3This is the architecture you'll build repeatedly.
Let's create a Pod.
Create:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80Save it as:
nginx-pod.yamlkubectl apply -f nginx-pod.yamlkubectl get podsYou should see:
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 ...kubectl describe pod nginxLook for:
Node:
IP:
Containers:
Image:
State:
Events:kubectl logs nginxNginx may not produce much output initially. That's okay.
kubectl exec -it nginx -- /bin/bashIf /bin/bash isn't available in a particular image, use:
kubectl exec -it nginx -- /bin/shThen:
lsTry:
cat /etc/os-releaseExit:
exitThis is a useful experiment.
Delete the Pod:
kubectl delete pod nginxThen:
kubectl get podsThe Pod will be gone.
Why?
Because you created a standalone Pod.
There isn't a Deployment telling Kubernetes:
"I require one Pod to always exist."
This experiment demonstrates why production applications generally use Deployments.
Remember this:
POD
│
┌──────────┴──────────┐
│ │
Container Container
(usually (optional
main app) sidecar)
│ │
└──────────┬──────────┘
│
Shared Network
│
Pod IPAnd:
Deployment
↓
ReplicaSet
↓
Pods
↓
Containers| Concept | Meaning |
|---|---|
| Pod | Smallest deployable Kubernetes unit |
| Container | Runs application inside Pod |
| Pod IP | Network identity of the Pod |
| Multi-container Pod | Multiple tightly coupled containers |
| Sidecar | Helper container alongside main container |
| Init container | Runs initialization before main containers |
| Pending | Pod isn't running yet |
| Running | Pod is running |
| Succeeded | Pod completed successfully |
| Failed | Pod completed unsuccessfully |
| CrashLoopBackOff | Container repeatedly crashes/restarts |
| Deployment | Usually manages application Pods |
| Ephemeral | Pods can be replaced at any time |
A Pod is the smallest deployable unit in Kubernetes and contains one or more containers that share networking and can share storage.
Yes.
Pod
├── App
└── SidecarNormally no. Containers in the same Pod share the Pod's network namespace and IP.
Not simultaneously within a normal Kubernetes cluster network.
No. Pods are ephemeral and replacement Pods can receive different IP addresses.
A Deployment provides higher-level management such as maintaining replicas, rolling updates, and replacing failed Pods.
It indicates a container is repeatedly failing and Kubernetes is repeatedly restarting it with increasing delays between attempts.
Start with:
kubectl get pods
kubectl logs <pod>
kubectl logs <pod> --previous
kubectl describe pod <pod>Don't think:
"I have 3 containers."Think:
"I have 3 Pods,
each containing my application container."And in production:
Deployment
↓
3 replicas
↓
┌────┬────┬────┐
Pod Pod Pod
↓ ↓ ↓
App App AppThat mental model will make the next chapter much easier.
Now we'll learn the Kubernetes object you'll use far more often than standalone Pods:
Deployment
↓
ReplicaSet
↓
PodsWe'll cover:
replicaskubectl rolloutMark it as complete to track your mastery.