Skip to main content
Kubernetes beginner Lesson 2 of 8

Pods and Workloads

Understand pods, containers, labels, selectors, and how Kubernetes schedules and manages workload lifecycles.

Pod Basics

A Pod groups one or more containers together so they can run as a single unit on one node. Every container in a Pod shares the same network namespace (IP + ports) and can share storage volumes.

┌─────────────────────────────────────┐
│  Pod  (shared IP: 10.244.0.5)       │
│                                     │
│  ┌─────────────┐  ┌──────────────┐  │
│  │  app:nginx  │  │  sidecar:log │  │
│  │  port 80    │  │  (read logs) │  │
│  └─────────────┘  └──────────────┘  │
│                                     │
│  shared volume: /var/log/nginx      │
└─────────────────────────────────────┘

Your First Pod Manifest

# pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-nginx
  labels:
    app: my-nginx
    env: dev
spec:
  containers:
    - name: nginx
      image: nginx:1.25
      ports:
        - containerPort: 80
      resources:
        requests:
          cpu: "100m"
          memory: "64Mi"
        limits:
          cpu: "200m"
          memory: "128Mi"
# Apply the pod manifest
kubectl apply -f pod.yaml

# Check it started
kubectl get pods

# Detailed view — events, container status, node assignment
kubectl describe pod my-nginx

# Stream logs
kubectl logs -f my-nginx

# Open an interactive shell
kubectl exec -it my-nginx -- bash

# Delete the pod
kubectl delete pod my-nginx
# or
kubectl delete -f pod.yaml

Multi-Container Pod (Sidecar Pattern)

# pod-sidecar.yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-with-sidecar
spec:
  volumes:
    - name: shared-logs
      emptyDir: {}

  containers:
    - name: app
      image: nginx:1.25
      volumeMounts:
        - name: shared-logs
          mountPath: /var/log/nginx

    - name: log-shipper
      image: busybox:1.36
      command: ["sh", "-c", "tail -f /logs/access.log"]
      volumeMounts:
        - name: shared-logs
          mountPath: /logs

Both containers communicate over localhost since they share the same network namespace.

Labels and Selectors

Labels are the primary way Kubernetes objects find and relate to each other.

# Applying labels to a pod
metadata:
  name: api-server
  labels:
    app: api          # what app
    version: v2       # which version
    env: production   # which environment
    tier: backend     # which tier
# List pods with their labels
kubectl get pods --show-labels

# Filter pods by label
kubectl get pods -l app=api
kubectl get pods -l env=production,tier=backend

# Add a label to a running pod (imperative)
kubectl label pod my-nginx region=us-east

# Remove a label
kubectl label pod my-nginx region-

# Select pods NOT matching a label
kubectl get pods -l 'env!=dev'

Pod Lifecycle

Pending → Running → Succeeded / Failed

           CrashLoopBackOff (if container keeps failing)
# Watch pod status transitions in real time
kubectl get pods --watch

# Check why a pod is in CrashLoopBackOff
kubectl describe pod <name>   # look at Events section
kubectl logs <name> --previous  # logs from previous (crashed) run

Init Containers

Init containers run to completion before main containers start — useful for waiting on databases or seeding config.

apiVersion: v1
kind: Pod
metadata:
  name: app-with-init
spec:
  initContainers:
    - name: wait-for-db
      image: busybox:1.36
      command:
        - sh
        - -c
        - "until nc -z postgres-service 5432; do echo waiting; sleep 2; done"

  containers:
    - name: app
      image: my-api:1.0
      ports:
        - containerPort: 8080

Resource Requests and Limits

resources:
  requests:
    cpu: "250m"      # 0.25 cores guaranteed
    memory: "128Mi"  # 128 MB guaranteed
  limits:
    cpu: "500m"      # max 0.5 cores
    memory: "256Mi"  # max 256 MB (OOMKilled if exceeded)
# Check resource usage for pods
kubectl top pods

# Check resource usage for nodes
kubectl top nodes

Health Probes

spec:
  containers:
    - name: api
      image: my-api:1.0
      livenessProbe:         # restart if this fails
        httpGet:
          path: /healthz
          port: 8080
        initialDelaySeconds: 5
        periodSeconds: 10

      readinessProbe:        # only send traffic when this passes
        httpGet:
          path: /ready
          port: 8080
        initialDelaySeconds: 3
        periodSeconds: 5
ProbeFailure action
livenessProbeRestart the container
readinessProbeRemove from Service endpoints (no traffic)
startupProbeBlock liveness/readiness until startup completes

Learning Outcomes

You should be able to:

  • Write and apply a Pod manifest with kubectl apply
  • Explain the sidecar pattern and when to use it
  • Use labels and selectors to organize and filter resources
  • Configure resource requests/limits and health probes
  • Reason about why Services route to the right Pods

Frequently Asked Questions

What exactly is a Pod in Kubernetes?
A Pod is the smallest deployable unit in Kubernetes. It usually contains one container, but can contain multiple containers that share networking and storage.
Why do we use labels and selectors?
Labels tag objects with key/value metadata. Selectors let controllers (like Deployments and Services) find the Pods they should manage or route traffic to.