# Workloads and Pod Basics

> Chapter 6 of the Courseiva CNCF-CKA curriculum — https://courseiva.com/learn/cncf-cka/workloads-and-pod-basics

**Official objective:** Workloads & Scheduling - 15% — Understand Pods and their lifecycle.

## Introduction

Kubernetes manages applications by wrapping them in small, disposable packages called Pods. This concept solves the problem of how to reliably run, monitor, and replace software processes across a cluster of computers. For the CKA exam, understanding Pods is the foundation of everything else — without it, you cannot grasp Deployments, Services, or scaling.

## The Shipping Container Port Analogy

You and your friend decide to ship a car and a motorbike from New York to London. First, each vehicle must be placed into its own secure, standard-sized shipping container. This container is the 'Pod' — it holds exactly one vehicle (or a few tightly-packed items) and is the smallest unit that the crane on the ship (the Kubernetes scheduler) can manage.

If you tried to ship the car loose on the deck, it would slide around, get damaged, and be impossible to track. The container protects it, gives it a unique ID, and makes loading and unloading predictable. Similarly, a Kubernetes Pod is a sealed, logical box that holds one or more closely related application processes (like your car).

In the port, you might group two containers together on a flatbed truck — that is a 'Deployment', which ensures the right number of containers are running at all times. If a container springs a leak (the app crashes), the port crane replaces it with an identical new container. The Pod is not the ship or the truck — it is the container itself. The Pod's lifecycle mirrors the container's journey: it is requested, loaded, moves, runs, and finally is unloaded and destroyed. No port worker ever touches your car directly; they only handle the Pod.

## Core explanation

A Pod is the smallest, most basic unit that Kubernetes (often called 'K8s') can create and manage. Think of it as a single wrapper that holds one or more containers. A container is a lightweight, standalone package that includes everything a piece of software needs to run: code, runtime, system tools, libraries, and settings. Containers are like tiny, portable computers that run an application.

Before Kubernetes came along, system administrators would install applications directly on a physical server. If that server crashed, the application went down with it. If you needed to update the application, you had to log into the server, stop the old version, install the new one, and hope nothing broke along the way. This was slow, error-prone, and hard to scale. Kubernetes and Pods changed the game by automating the process of running containers across many machines (called a 'cluster' — a group of servers working together). 

In a Kubernetes cluster, Pods are the atomic unit of scheduling. 'Scheduling' means deciding which server (called a 'Node') will run the Pod. Each Pod has a unique IP address inside the cluster. Pods can have one or more containers, but they share the same network namespace (they can talk to each other using 'localhost') and the same storage volumes. They are co-located and co-scheduled — they start and stop together.

Why does Kubernetes use Pods instead of running containers directly? There are several reasons. First, a Pod can run multiple helper containers that support the main application. For example, one container might run a web server, while another 'sidecar' container collects logs and sends them to a central logging service. Because they are in the same Pod, they can communicate instantly and share resources. Second, Pods make it easy to ensure consistency: every instance of an application runs in an identical Pod. 

However, Pods are designed to be ephemeral — temporary. They are not meant to be repaired if they fail. If a Pod crashes or its Node dies, Kubernetes does not bring that exact Pod back to life. Instead, it creates a new, identical Pod. This is a fundamental shift in thinking: you do not fix applications; you replace them. This approach is called 'immutable infrastructure'. 

Here are the key characteristics of a Pod that you need to know for the CKA: 

- A Pod always runs on a single Node. It cannot be split across two servers. 
- Pods can contain one container (most common) or multiple containers that work closely together. 
- Each Pod gets its own unique IP address within the cluster. 
- Pods are mortal — they are born, live, and then they die. They are never reborn. If you need a new Pod, Kubernetes creates a fresh one. 
- A Pod defines a 'restart policy' which tells Kubernetes what to do if a container inside the Pod exits. The default is 'Always' — the kubelet (the agent on each Node) will keep restarting the container until the Pod is deleted. 

The lifecycle of a Pod has several phases: Pending (the Pod has been accepted but not yet running on a Node), Running (all containers are operational), Succeeded (all containers finished successfully), Failed (one or more containers exited with a non-zero error code), and Unknown (the state of the Pod cannot be determined, often because the Node is unresponsive). 

To create a Pod, you write a YAML or JSON file. YAML is a human-readable data format used extensively in Kubernetes. This file is called a 'manifest'. It describes exactly what the Pod should contain. You send this manifest to the Kubernetes API server (the brain of the cluster) using the 'kubectl' command-line tool. The API server records the desired state in a database called 'etcd'. Then the scheduler picks a suitable Node, and the kubelet on that Node pulls the container images (the package containing the application code) from a registry (like Docker Hub) and starts the containers. 

For the CKA, you must be comfortable creating, viewing, and deleting Pods. You also need to understand how to check the status of Pods using 'kubectl get pods' and 'kubectl describe pod <pod-name>'. You must know how to write a Pod manifest, including the 'apiVersion', 'kind', 'metadata' (name, labels), and 'spec' (containers, image, ports). Labels are key-value pairs attached to Pods that help you organise and select them.

## Real-world context

Imagine you work as a site reliability engineer at an online retail company. Your team runs a microservice that processes customer orders. Each request comes in as an HTTP message, the service validates the payment, updates the inventory database, and sends a confirmation email. This application is packaged as a container image called 'order-processor:v2'. 

Your job is to ensure that this service runs reliably for thousands of customers every minute. Instead of logging into a single server and starting the application manually, you write a Pod manifest. Here is what happens step by step: 

1. You create a YAML file that names the Pod 'order-worker-1', uses image 'order-processor:v2', exposes port 8080, and sets a restart policy of 'Always'. 
2. You run 'kubectl apply -f order-pod.yaml', which sends the manifest to the Kubernetes API server. 
3. The scheduler looks at the available Nodes (servers) in the cluster and picks one with enough free CPU and memory. 
4. The kubelet on that Node receives the new Pod spec, pulls the container image from a registry (like Docker Hub or a private repository), and starts the container. 
5. The Pod enters the 'Running' phase. Other services in the cluster can now send requests to its IP address on port 8080. 

A few minutes later, the server running 'order-worker-1' suffers a hardware failure. The Node becomes unresponsive, and the kubelet stops sending heartbeats to the control plane. Kubernetes marks the Node as 'NotReady'. The Pod sitting on that Node is stuck in 'Unknown' state. Crucially, Kubernetes does NOT automatically recreate this specific Pod — it waits for you to act or for a higher-level controller (like a Deployment) to replace it. 

Because you used a bare Pod (not a Deployment), the service goes down until you manually delete the old Pod and create a new one. This is why in production, you almost never use bare Pods. Instead, you use a Deployment controller, which manages a set of identical Pods and automatically replaces any that fail. The CKA exam expects you to know the difference between a bare Pod and a controller-managed Pod. 

You then debug the issue. Using 'kubectl describe pod order-worker-1', you see the events: 'Node became unhealthy', 'Pod marked as Unknown'. You delete the Pod with 'kubectl delete pod order-worker-1', and then create a new Pod (or better, a Deployment) to bring the service back. 

In a real, busy cluster, you would also use 'kubectl logs order-worker-1 -c order-processor' to see the application log output. If a container inside the Pod crashes and restarts repeatedly (a 'CrashLoopBackOff' state), you would inspect the logs to find an error, such as a missing database connection string. You would then update the Pod manifest with the correct configuration and reapply it.

## Exam focus

The CKA exam tests your ability to create, manage, and troubleshoot Pods from the command line. You will not be writing long manifest files from scratch every time, but you must understand every field in a basic Pod manifest. Expect scenario-based questions where you read a failing Pod and fix it. 

Here are the exact concepts the exam loves to test about Pods: 

- Pod phases and conditions. You must memorise the five phases: Pending, Running, Succeeded, Failed, Unknown. A common trap: a Pod that is 'Pending' is NOT 'running' — it may be waiting for a container image to download or for a Node to become available. 
- The 'restartPolicy' field. The default is 'Always', but you can set it to 'OnFailure' or 'Never'. If a container exits with a zero code, 'OnFailure' will not restart it. The exam may ask you to predict a Pod's state after a container crashes given a specific restart policy. 
- Liveness, readiness, and startup probes. These are health checks that Kubernetes uses to decide if a container is alive, ready to serve traffic, or still starting up. The exam will test your ability to add these probes to a Pod manifest and understand the consequences of misconfiguration. 
- Resource requests and limits. You can specify minimum CPU and memory a Pod needs (requests) and maximum it can use (limits). The scheduler uses requests to decide where to place Pods. The kubelet enforces limits. If you do not set these, a Pod can consume all resources on a Node and starve other Pods. 
- Pod to Node relationships. A Pod always runs on a single Node. You cannot move a running Pod to a different Node without destroying it and recreating it. 
- Multi-container Pod patterns. The exam expects you to know about sidecar, ambassador, and adapter patterns. A sidecar container adds functionality (like logging) alongside the main container. 

Common traps you must avoid: 

- Thinking Pods are self-healing at the Pod level. They are not. Only controllers like Deployments restart Pods. A bare Pod with 'restartPolicy: Always' will restart its container if it crashes, but if the Node fails, the Pod is gone forever without a controller. 
- Confusing 'kubectl get pods' with 'kubectl get nodes'. 'get pods' shows Pods, not the servers they run on. 
- Forgetting that Pod IPs change. Never hardcode a Pod IP address in another Pod's configuration. Use a Service to provide a stable endpoint. 
- Misunderstanding 'graceful shutdown'. When you delete a Pod, Kubernetes sends a SIGTERM signal to the main process and waits for the 'terminationGracePeriodSeconds' (default 30 seconds) before force-killing it. 

Key definitions to memorise for the exam: 

- 'kubelet': the node agent that runs on every Node and manages Pod lifecycle. 
- 'kube-proxy': a network proxy that runs on each Node and implements part of the Kubernetes Service concept. 
- 'etcd': a distributed key-value store that holds the state of the entire cluster. 
- 'kubectl': the command-line tool used to interact with the Kubernetes API server.

## Step by step

1. **Write the Pod Manifest** — You create a YAML file that defines the Pod's metadata (name, labels) and spec (containers, image, ports, restart policy). This declarative file tells Kubernetes exactly what you want to run.
2. **Submit the Manifest to the API Server** — Using 'kubectl apply -f <filename>', you send the manifest to the Kubernetes API server. The API server validates the spec and stores the desired state in etcd.
3. **Scheduler Picks a Node** — The scheduler component sees the new, unscheduled Pod. It checks resource requests, node availability, taints, and tolerations to choose the most suitable Node. The Pod is then bound to that Node.
4. **Kubelet Starts the Containers** — The kubelet on the chosen Node receives the Pod spec, pulls the container image from the registry if not cached locally, and starts the containers using a container runtime like containerd.
5. **Pod Enters Running Phase** — Once all containers are running and healthy, the Pod transitions to the Running phase. The kubelet reports the status back to the control plane. The Pod can now serve traffic.
6. **Pod Is Deleted or Replaced** — When the Pod's work is done, you run 'kubectl delete pod <name>'. The Pod receives a SIGTERM signal, waits for the terminationGracePeriodSeconds, then is forcefully terminated. The Pod's status becomes Terminating and then it is removed from etcd.

## Comparisons

### Pod vs Deployment

**Pod:**
- Smallest deployable unit in Kubernetes
- Not self-healing; bare Pods do not recover from Node failure
- Single instance of an application

**Deployment:**
- Higher-level controller that manages Pods
- Self-healing; always maintains the desired number of replicas
- Manages multiple Pod instances and supports rolling updates

### Container vs Pod

**Container:**
- Packaged application code with runtime dependencies
- No IP or network namespace on its own in Kubernetes
- Cannot be directly scheduled by Kubernetes

**Pod:**
- Wrapper around one or more containers
- Each Pod has its own IP and network namespace
- Directly scheduled and managed by Kubernetes

### restartPolicy: Always vs restartPolicy: OnFailure

**restartPolicy: Always:**
- Container restarts regardless of exit code (0 or non-zero)
- Default policy if not specified
- Common for web servers that should always be running

**restartPolicy: OnFailure:**
- Container restarts only if exit code is non-zero
- Not the default
- Common for batch jobs that should not restart on success

### Liveness Probe vs Readiness Probe

**Liveness Probe:**
- Checks if the container is still alive
- If fails, kubelet restarts the container
- Used to detect deadlocks or frozen processes

**Readiness Probe:**
- Checks if the container is ready to serve traffic
- If fails, Pod is removed from Service endpoints
- Used to handle temporary unavailability during startup

## Diagram

_This flowchart shows the lifecycle of a Pod from creation to deletion, passing through the API server, scheduler, and kubelet on a Node._

```mermaid
flowchart TD
    A[User creates Pod YAML manifest] --> B[API server stores desired state in etcd]
    B --> C[Scheduler finds suitable Node]
    C --> D[Kubelet on Node pulls container image]
    D --> E[Container runtime starts containers]
    E --> F[Pod enters Running phase]
    F --> G[Application serves traffic]
    G --> H[Pod is deleted or Node fails]
    H --> I[Pod enters Terminating / Unknown]
    I --> J[Pod removed from etcd]
```

## Common misconceptions

- **Misconception:** A Pod is the same as a container. **Reality:** A Pod is a wrapper around one or more containers. One Pod can contain multiple containers that share resources, but a container is just the packaged application code and dependencies. (New learners often conflate the two because a common pattern is one container per Pod. They assume they are interchangeable, but the abstraction layer matters for scheduling and resource sharing.)
- **Misconception:** If a Pod crashes, Kubernetes automatically recreates it. **Reality:** Kubernetes only recreates the Pod if it is managed by a higher-level controller like a Deployment. A bare Pod (created directly) will not be recreated if its Node fails — it will remain in 'Unknown' state until you manually delete and recreate it. (Beginners see the 'restartPolicy: Always' default and assume it applies to the Pod itself, not just the container inside the Pod. They miss that the restart policy only restarts the container on the same Node, not the Pod across Nodes.)
- **Misconception:** You can move a running Pod to another Node without losing it. **Reality:** A running Pod is bound to the Node where it was scheduled. To move it, you must delete it and create a new one on the target Node. There is no 'move' operation in Kubernetes. (People familiar with virtual machine live migration expect similar flexibility. Kubernetes uses a 'schedule once' model — Pod to Node binding is permanent for that Pod's lifecycle. This is a deliberate design choice for simplicity and predictability.)
- **Misconception:** All containers in a Pod can communicate over any port without restriction. **Reality:** Containers in the same Pod share the same network namespace, meaning they share the same IP address and port space. Therefore, they cannot both listen on the same port. They communicate using 'localhost' and must coordinate port usage. (The idea of 'shared resources' is intuitive, but the limitation of a single port space is counterintuitive. Beginners often try to run two web servers both on port 80 inside the same Pod and are confused when it fails.)
- **Misconception:** Pods automatically figure out which Node has the most free space and move there. **Reality:** Pods do not move themselves. The Kubernetes scheduler decides where to place a Pod when it is created. The scheduler considers resource requests, node affinity rules, taints, and tolerations. A running Pod never autonomously 'chooses' to leave its Node. (People anthropomorphise automation, thinking the system 'knows' where to go. In reality, scheduling is a one-time decision made by the scheduler component, not the Pod itself.)

## Key takeaways

- A Pod is the smallest deployable unit in Kubernetes; it wraps one or more containers that share a network namespace and storage.
- Each Pod gets a unique, temporary IP address; never hardcode a Pod IP in configuration because it will change whenever the Pod is recreated.
- A bare Pod (created without a controller like a Deployment) will not be automatically replaced if its Node fails — always use a controller for production workloads.
- The Pod lifecycle has five phases: Pending, Running, Succeeded, Failed, and Unknown, and you must memorise them for the CKA exam.
- Containers inside the same Pod can communicate via localhost, but they cannot use the same port number because they share a port space.
- The restartPolicy field applies to containers within a Pod, not to the Pod itself; if the entire Node goes down, restartPolicy cannot bring the Pod back.

## FAQ

**Can a Pod contain more than one container?**

Yes, a Pod can contain multiple containers. They share the same network namespace and storage volumes, making it easy for them to communicate via localhost and share data. This is common for sidecar patterns like logging or monitoring.

**What is the difference between a Pod and a Deployment?**

A Pod is a single instance of a running application. A Deployment is a higher-level controller that manages a set of identical Pods, ensuring the desired number of replicas are always running, and handles rolling updates and rollbacks.

**How do I view the logs of a container inside a Pod?**

Use 'kubectl logs <pod-name> -c <container-name>'. If the Pod has only one container, you can omit the '-c' flag. This command fetches the stdout and stderr output from the container's process.

**What does the 'Pending' phase mean for a Pod?**

Pending means the Pod has been accepted by the Kubernetes API server but is not yet running. This could be because the container image is still being pulled, the scheduler is still selecting a node, or there are not enough resources available on any node.

**What happens when I delete a Pod?**

Kubernetes sends a SIGTERM signal to the main process (PID 1) inside each container. By default, it waits 30 seconds (the terminationGracePeriodSeconds) before sending SIGKILL to force the process to stop. The Pod is then removed from etcd and its resources are released.

**Why does my Pod stay in 'CrashLoopBackOff'?**

This means a container inside the Pod keeps crashing and restarting. Each restart increases a backoff delay (10, 20, 40 seconds, etc.). Check the logs using 'kubectl logs <pod>' to find the error, such as a missing environment variable or a crash in the application code.

## Check your understanding

1. **What is the smallest deployable unit in Kubernetes?**

   Answer: A Pod is the smallest deployable unit. It wraps one or more containers and is the atomic unit of scheduling.

2. **If you create a bare Pod and the Node it is running on crashes, does Kubernetes automatically recreate the Pod on a healthy Node?**

   Answer: No. A bare Pod is not managed by a controller, so it will not be automatically recreated. You must use a Deployment or other controller for automatic replacement.

3. **What are the five phases of a Pod's lifecycle?**

   Answer: The five phases are: Pending, Running, Succeeded, Failed, and Unknown.

4. **Can two containers inside the same Pod both listen on port 8080?**

   Answer: No, because they share the same network namespace and port space. They cannot use the same port number.

5. **What happens if a container in a Pod with restartPolicy: OnFailure exits with a zero exit code?**

   Answer: The container will not be restarted because OnFailure only triggers a restart on a non-zero exit code.

---

Interactive version with quiz and diagrams: https://courseiva.com/learn/cncf-cka/workloads-and-pod-basics
