Kubernetes Core Concepts

Pods: The Smallest Deployable Unit

A Pod is the smallest deployable unit Kubernetes manages. Before learning Deployments, Services, scaling, rollouts, or troubleshooting, you need to understand what a Pod is and what Kubernetes is actually running.

What this lesson covers

This lesson introduces Pods as the basic workload unit in Kubernetes.

By the end, you should understand:

  • What a Pod is
  • How a Pod relates to a container
  • Why Kubernetes usually manages Pods through higher-level objects
  • How to create a simple Pod
  • How to inspect Pod status
  • How to view Pod logs
  • How to exec into a Pod
  • How to expose a Pod locally for testing
  • How to delete a Pod
  • Why manually created Pods are not usually how production workloads are managed
Field note: Kubernetes does not run containers by themselves. It runs containers inside Pods. That distinction matters.

The short version

A Pod is a wrapper around one or more containers.

Most beginner examples use one container per Pod, but a Pod can contain multiple containers when those containers need to be tightly coupled and share the same network and storage context.

In normal application deployments, you usually do not create standalone Pods directly. You create a higher-level object like a Deployment, and that Deployment creates and manages Pods for you.

Pod vs container

A container is the running application process created from an image.

A Pod is the Kubernetes object that holds that container.

Container:
  The application process and its runtime environment.

Pod:
  The Kubernetes wrapper around one or more containers.

If Kubernetes is managing a containerized application, it is doing that through a Pod.

What a Pod provides

A Pod gives containers a shared execution environment.

Containers in the same Pod share:

  • The same network namespace
  • The same Pod IP address
  • The ability to communicate over localhost
  • Shared volumes, if configured
  • The same scheduling lifecycle

That last point is important. Containers in the same Pod are scheduled together. They are meant to be tightly related.

Field note: Do not put unrelated applications into the same Pod. A Pod is not a mini server where you install a pile of services. It is for tightly coupled containers that should live and die together.

Why most Pods have one container

Most application Pods contain one main application container.

That keeps the model simple:

  • One application process
  • One container image
  • One set of logs
  • One primary lifecycle

Multi-container Pods exist, but they are usually used for helper patterns such as sidecars, proxies, log shippers, or tightly coupled support containers.

Pods are disposable

Pods are not meant to be long-lived pets. They are meant to be replaceable.

A Pod can disappear because:

  • The node failed
  • The Pod was deleted
  • A Deployment rolled out a new version
  • A health check failed
  • The scheduler moved workload elsewhere
  • The cluster needed to reclaim resources

This is why Kubernetes uses higher-level controllers like Deployments to keep the desired number of Pods running.

Field note: If a Pod dies, Kubernetes may replace it, but the replacement is a new Pod. Do not design around a specific Pod name or Pod IP staying forever.

Before you start the lab

This lab assumes:

  • Docker Desktop is running
  • Your kind cluster exists
  • kubectl is installed
  • Your current context is kind-stealth-k8s-lab

Check your context:

kubectl config current-context

You should see:

kind-stealth-k8s-lab

Check your node:

kubectl get nodes

If your cluster no longer exists, recreate it:

kind create cluster --name stealth-k8s-lab

Step 1: Create a simple Pod imperatively

The fastest way to create a simple Pod is with kubectl run.

kubectl run nginx-pod-lab --image=nginx:latest

This tells Kubernetes to create a Pod named nginx-pod-lab using the nginx:latest container image.

What this command does

  • Creates a Pod object
  • Uses the nginx container image
  • Asks Kubernetes to schedule the Pod onto a node
  • Starts the container inside the Pod

This is called an imperative command because you directly told Kubernetes to create something from the command line.

Step 2: List Pods

Run:

kubectl get pods

You should see something like:

NAME            READY   STATUS    RESTARTS   AGE
nginx-pod-lab   1/1     Running   0          30s

What to look for

  • READY: How many containers are ready compared to how many are expected.
  • STATUS: The current Pod phase or status summary.
  • RESTARTS: How many times the container restarted.
  • AGE: How long the Pod has existed.

For this simple Pod, 1/1 means one container is expected and one container is ready.

Step 3: Show more detail with wide output

Run:

kubectl get pods -o wide

This gives you more information, usually including:

  • Pod IP
  • Node where the Pod is running
  • Readiness gates, if any

In a local kind cluster, the node name will usually be something like:

stealth-k8s-lab-control-plane

Step 4: Describe the Pod

Run:

kubectl describe pod nginx-pod-lab

The describe output is one of your most useful troubleshooting views.

What to look for

  • Pod name and namespace
  • Node placement
  • Pod IP
  • Container image
  • Container state
  • Restart count
  • Events at the bottom

The events section often tells you what Kubernetes did: scheduled the Pod, pulled the image, created the container, and started the container.

Field note: When a Pod is broken, always check the bottom of kubectl describe pod. The events section often tells you exactly what Kubernetes tried to do.

Step 5: View Pod logs

Run:

kubectl logs nginx-pod-lab

nginx may not show much until it receives traffic. That is normal.

Logs come from the container running inside the Pod. If a Pod has multiple containers, you may need to specify which container you want logs from.

Step 6: Exec into the Pod

Open a shell inside the container:

kubectl exec -it nginx-pod-lab -- /bin/sh

Inside the container, run:

hostname
ps
ls
exit

This shows that you can inspect the running container through Kubernetes.

This is useful for learning and emergency inspection, but you should not treat containers like traditional servers that you manually repair from the inside.

Step 7: Port-forward to the Pod

Use port-forwarding to test the nginx Pod from your local browser:

kubectl port-forward pod/nginx-pod-lab 8080:80

Keep that PowerShell window open. Then open a browser and go to:

http://localhost:8080

You should see the nginx welcome page.

Press Ctrl+C in PowerShell to stop the port-forward session.

Step 8: Check logs again after traffic

After visiting the nginx page, check logs again:

kubectl logs nginx-pod-lab

You should now see nginx access log entries.

Step 9: View the Pod as YAML

Kubernetes resources are API objects. You can view the Pod in YAML:

kubectl get pod nginx-pod-lab -o yaml

The output will be long. For now, look for these major sections:

  • apiVersion
  • kind
  • metadata
  • spec
  • status

What these sections mean

  • apiVersion: Which Kubernetes API version this object uses.
  • kind: What type of Kubernetes object this is.
  • metadata: Name, namespace, labels, and system-managed information.
  • spec: The desired configuration for the Pod.
  • status: What is currently happening with the Pod.
Field note: Kubernetes resources usually have a spec and a status. The spec is what you asked for. The status is what Kubernetes reports is actually happening.

Step 10: Create a Pod from YAML

Imperative commands are useful for quick testing, but Kubernetes work usually moves toward YAML files.

Create a new file named:

pod-lab.yaml

Paste this into the file:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-yaml-pod-lab
  labels:
    app: nginx-yaml-pod-lab
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80

Apply the file:

kubectl apply -f pod-lab.yaml

Check the Pod:

kubectl get pods

You should now see both Pods:

nginx-pod-lab
nginx-yaml-pod-lab

Step 11: Compare the two Pods

Describe the YAML-created Pod:

kubectl describe pod nginx-yaml-pod-lab

Then view its YAML:

kubectl get pod nginx-yaml-pod-lab -o yaml

The important point is that both methods created a Pod object. The YAML method is more repeatable because the desired configuration is saved in a file.

Step 12: Delete the first Pod

Delete the Pod you created imperatively:

kubectl delete pod nginx-pod-lab

Check Pods:

kubectl get pods

Notice that the Pod does not come back.

Why it does not come back

You created a standalone Pod. There is no Deployment or controller watching it and saying, “Keep one copy running.”

When you delete a standalone Pod, it is gone.

Field note: This is why production workloads are usually managed by Deployments or other controllers. A controller keeps the desired number of Pods running.

Step 13: Delete the YAML-created Pod

Delete it using the YAML file:

kubectl delete -f pod-lab.yaml

Confirm it is gone:

kubectl get pods

This removes the object defined in the YAML file.

Common Pod statuses

As you work with Pods, you will see different status values. Some common ones include:

  • Pending: Kubernetes accepted the Pod, but it has not started running yet.
  • Running: The Pod is assigned to a node and at least one container is running.
  • Succeeded: Containers completed successfully and will not restart.
  • Failed: Containers terminated with failure.
  • CrashLoopBackOff: A container keeps crashing and Kubernetes is backing off before restarting it again.
  • ImagePullBackOff: Kubernetes cannot pull the container image.

The status alone does not always tell the full story. Use describe, logs, and events to understand what is happening.

Quick troubleshooting flow for Pods

When a Pod does not work, start with:

kubectl get pods
kubectl get pods -o wide
kubectl describe pod <pod-name>
kubectl logs <pod-name>
kubectl get events --sort-by=.metadata.creationTimestamp

This usually answers:

  • Does the Pod exist?
  • Is it running?
  • Which node is it on?
  • Did the image pull successfully?
  • Did the container start?
  • Is the app crashing?
  • What did Kubernetes report in events?

What you just learned

In this lesson, you:

  • Created a Pod with kubectl run
  • Listed Pods
  • Used wide output
  • Described a Pod
  • Viewed Pod logs
  • Used exec for inspection
  • Used port-forward for local testing
  • Viewed a Pod as YAML
  • Created a Pod from YAML
  • Deleted standalone Pods
  • Learned why controllers matter
Bottom line: A Pod is the smallest deployable unit in Kubernetes, but standalone Pods are not usually how production applications are managed. Pods are usually created and maintained by controllers such as Deployments.

Check your understanding

Use these questions to test whether the Pod concepts made sense.

  1. What is the smallest deployable unit Kubernetes manages?
  2. Does Kubernetes run containers directly by themselves, or inside Pods?
  3. Can a Pod contain more than one container?
  4. When should multiple containers be placed in the same Pod?
  5. Why are Pods considered disposable?
  6. What does READY 1/1 mean for a Pod?
  7. What command gives detailed troubleshooting information about a Pod?
  8. Where should you look in describe output when a Pod fails to start?
  9. What is the difference between spec and status?
  10. Why does a standalone Pod not come back after you delete it?
  11. Why is YAML useful for creating Kubernetes resources?
  12. What are two commands you would run when troubleshooting a broken Pod?
Answer key
  1. A Pod.
  2. Kubernetes runs containers inside Pods.
  3. Yes.
  4. When the containers are tightly coupled and need to share the same network or storage context.
  5. Because they can be deleted, replaced, rescheduled, or recreated as part of normal Kubernetes operation.
  6. One container is expected and one container is ready.
  7. kubectl describe pod <pod-name>.
  8. The events section at the bottom.
  9. spec is the desired configuration. status is what Kubernetes reports is currently happening.
  10. Because no controller is managing it and recreating it.
  11. YAML makes the desired configuration repeatable and reviewable.
  12. Examples: kubectl describe pod <pod-name>, kubectl logs <pod-name>, kubectl get events, kubectl get pods -o wide.
← Previous: kubectl Basics Series index Next: Deployments and ReplicaSets →