Introduction

Pods are the fundamental building blocks of Kubernetes. Understanding how to create, manage, and troubleshoot pods is essential for anyone working with Kubernetes. In this comprehensive guide, I’ll walk you through everything you need to know about Kubernetes pods, from basic creation to advanced troubleshooting techniques.

Whether you’re just starting with Kubernetes or looking to deepen your understanding, this guide covers both imperative (command-line) and declarative (YAML-based) approaches to pod management.

What is a Kubernetes Pod?

A Pod is the smallest deployable unit in Kubernetes. Think of it as a wrapper around one or more containers that share:

  • Network namespace (same IP address)
  • Storage volumes
  • Configuration data

Key characteristics:

  • Each pod has a unique IP address
  • Containers within a pod communicate via localhost
  • Pods are ephemeral - they can be created and destroyed dynamically
  • Usually contains one container (best practice), but can host multiple tightly-coupled containers

Prerequisites

Before we begin, ensure you have:

  • kubectl installed (Kubernetes command-line tool)
  • minikube or access to a Kubernetes cluster
  • Basic understanding of containers and Docker
  • Terminal/command-line access

Installation verification:

kubectl version --client
minikube version

Part 1: Creating Pods - The Imperative Way

The imperative approach uses direct kubectl commands. It’s quick for testing and learning, but not ideal for production environments.

Creating Your First Pod

The simplest way to create a pod:

kubectl run firstpod --image=nginx:latest

This command:

  • Creates a pod named “firstpod”
  • Uses the nginx:latest image from Docker Hub
  • Automatically pulls the image if not present locally

Viewing Pod Information

List all pods:

kubectl get pods
kubectl get pods -o wide  # Shows more details including IP and Node

Expected output:

NAME       READY   STATUS    RESTARTS   AGE   IP           NODE
firstpod   1/1     Running   0          30s   172.17.0.3   minikube

Understanding the output:

  • READY: Shows running containers vs total containers (1/1 means 1 container running out of 1)
  • STATUS: Current state (Pending, Running, Succeeded, Failed, Unknown)
  • RESTARTS: Number of times the container has restarted
  • AGE: Time since pod creation
  • IP: Pod’s internal IP address
  • NODE: Which node the pod is running on

Troubleshooting Pods

When things go wrong, these commands are your best friends:

1. Describe Pod (Detailed Information):

kubectl describe pod firstpod

This shows:

  • Pod metadata and labels
  • Container specifications
  • Events (creation, scheduling, pulling images, errors)
  • Resource requests and limits
  • Volume mounts
  • Network settings

2. View Pod Logs:

kubectl logs firstpod

For real-time log streaming:

kubectl logs -f firstpod  # -f follows/tails the logs

If pod has multiple containers:

kubectl logs firstpod -c container-name

3. Execute Commands in Pod:

Run a single command:

kubectl exec firstpod -- ls /usr/share/nginx/html
kubectl exec firstpod -- cat /etc/nginx/nginx.conf

4. Interactive Shell Access:

Enter the pod with bash:

kubectl exec -it firstpod -- bash

Or with sh (if bash is not available):

kubectl exec -it firstpod -- /bin/sh

Inside the pod, you can:

# Check running processes
ps aux

# View network configuration
apt update && apt install -y net-tools iputils-ping
ifconfig
ip addr

# Test connectivity
ping 8.8.8.8
curl localhost

# Exit the pod
exit
# Or use: CTRL+P+Q (detach without stopping)

Deleting Pods

kubectl delete pod firstpod

Important Note: While the imperative way is great for learning and quick tests, it has limitations:

  • No version control
  • Difficult to reproduce
  • Hard to share configurations
  • Not suitable for production

This is where the declarative approach shines.

Part 2: Creating Pods - The Declarative Way (YAML)

The declarative approach uses YAML files to define pod specifications. This is the recommended approach for production environments.

Basic Pod Definition

Create a file named pod1.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: firstpod
  labels:
    app: frontend
    tier: web
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80
    env:
    - name: USER
      value: "admin"
    - name: ENVIRONMENT
      value: "development"

Understanding the YAML structure:

  • apiVersion: API version (v1 for core objects like Pods)
  • kind: Type of Kubernetes object (Pod, Deployment, Service, etc.)
  • metadata: Data about the pod
    • name: Unique identifier for the pod
    • labels: Key-value pairs for organizing and selecting pods
  • spec: Specification of desired state
    • containers: List of containers in the pod
      • name: Container name
      • image: Container image (from Docker Hub or private registry)
      • ports: Ports to expose
      • env: Environment variables

Creating Pod from YAML

kubectl apply -f pod1.yaml

Verify creation:

kubectl get pods
kubectl describe pod firstpod

Advanced Pod Configuration

Pod with Resource Limits:

apiVersion: v1
kind: Pod
metadata:
  name: resource-pod
spec:
  containers:
  - name: nginx
    image: nginx:latest
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
    ports:
    - containerPort: 80

Understanding resources:

  • requests: Minimum resources guaranteed to the container
  • limits: Maximum resources the container can use
  • CPU: Measured in millicores (1000m = 1 CPU core)
  • Memory: Measured in bytes (Mi = Mebibytes, Gi = Gibibytes)

Pod with Multiple Containers:

apiVersion: v1
kind: Pod
metadata:
  name: multi-container-pod
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80
  - name: sidecar
    image: busybox
    command: ['sh', '-c', 'while true; do echo "Sidecar running"; sleep 10; done']

Pod with Volume Mount:

apiVersion: v1
kind: Pod
metadata:
  name: volume-pod
spec:
  containers:
  - name: nginx
    image: nginx:latest
    volumeMounts:
    - name: html-volume
      mountPath: /usr/share/nginx/html
  volumes:
  - name: html-volume
    emptyDir: {}

Updating Pods

Important: Pods are immutable. You cannot update most pod specifications after creation. To make changes:

  1. Delete the existing pod
  2. Modify the YAML file
  3. Recreate the pod
kubectl delete -f pod1.yaml
# Edit pod1.yaml
kubectl apply -f pod1.yaml

Alternative: Use Deployments (covered in next post) which handle updates gracefully.

Pod Lifecycle and States

Understanding pod states is crucial for troubleshooting:

1. Pending

  • Pod accepted by Kubernetes
  • Not yet scheduled to a node
  • Waiting for resources or image pull

2. Running

  • Pod bound to a node
  • All containers created
  • At least one container is running

3. Succeeded

  • All containers terminated successfully
  • Will not be restarted

4. Failed

  • All containers terminated
  • At least one container failed

5. Unknown

  • Pod state cannot be determined
  • Usually due to node communication issues

Common Status Issues:

ImagePullBackOff:

Reason: Image pull failed
Solutions:
- Check image name and tag
- Verify registry credentials
- Ensure network connectivity

CrashLoopBackOff:

Reason: Container keeps crashing
Solutions:
- Check application logs
- Verify container command
- Review resource limits
- Check liveness/readiness probes

Pending:

Reason: Cannot be scheduled
Solutions:
- Check node resources
- Verify node selectors/affinity
- Review taints and tolerations

Best Practices for Production

1. Always Use Declarative Approach

  • Store YAML files in version control (Git)
  • Enable code review and collaboration
  • Track changes over time

2. Use Meaningful Labels

metadata:
  labels:
    app: myapp
    version: v1.2.0
    environment: production
    team: backend

3. Set Resource Requests and Limits

  • Prevents resource starvation
  • Enables better scheduling
  • Protects against resource exhaustion

4. Implement Health Checks

spec:
  containers:
  - name: nginx
    image: nginx:latest
    livenessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 30
      periodSeconds: 10
    readinessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 5

5. Use Namespaces for Organization

kubectl create namespace development
kubectl apply -f pod1.yaml -n development

6. Never Run Pods Directly in Production

  • Use Deployments for stateless applications
  • Use StatefulSets for stateful applications
  • Use DaemonSets for node-level services
  • Use Jobs for batch processing

Common kubectl Commands Cheatsheet

# Create pod
kubectl run mypod --image=nginx:latest
kubectl apply -f pod.yaml

# List pods
kubectl get pods
kubectl get pods -o wide
kubectl get pods --all-namespaces
kubectl get pods -n namespace-name

# Describe pod
kubectl describe pod mypod

# Logs
kubectl logs mypod
kubectl logs -f mypod
kubectl logs mypod -c container-name

# Execute commands
kubectl exec mypod -- ls /
kubectl exec -it mypod -- bash

# Delete pod
kubectl delete pod mypod
kubectl delete -f pod.yaml

# Port forwarding
kubectl port-forward mypod 8080:80

# Copy files
kubectl cp mypod:/path/to/file ./local-file
kubectl cp ./local-file mypod:/path/to/file

# Watch pods
kubectl get pods -w

Troubleshooting Scenarios

Scenario 1: Pod Stuck in Pending

# Check pod events
kubectl describe pod mypod

# Check node resources
kubectl top nodes

# Check if nodes are ready
kubectl get nodes

Scenario 2: Container Keeps Restarting

# Check logs
kubectl logs mypod --previous

# Check events
kubectl describe pod mypod

# Check resource usage
kubectl top pod mypod

Scenario 3: Cannot Access Pod

# Verify pod is running
kubectl get pod mypod

# Check pod IP
kubectl get pod mypod -o wide

# Test connectivity
kubectl exec -it mypod -- curl localhost

# Port forward to test
kubectl port-forward mypod 8080:80

Real-World Example: Nginx Web Server

Let’s create a complete example with best practices:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-webserver
  labels:
    app: nginx
    tier: frontend
    environment: production
spec:
  containers:
  - name: nginx
    image: nginx:1.21-alpine
    ports:
    - containerPort: 80
      name: http
      protocol: TCP
    resources:
      requests:
        memory: "64Mi"
        cpu: "100m"
      limits:
        memory: "128Mi"
        cpu: "200m"
    livenessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 30
      periodSeconds: 10
    readinessProbe:
      httpGet:
        path: /
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 5
    env:
    - name: NGINX_HOST
      value: "example.com"
    - name: NGINX_PORT
      value: "80"

Deploy and test:

kubectl apply -f nginx-webserver.yaml
kubectl get pods -w
kubectl port-forward nginx-webserver 8080:80
# Open browser: http://localhost:8080

Next Steps

Now that you understand pods, you’re ready to explore:

  • Deployments: Managing multiple pod replicas with rolling updates
  • Services: Exposing pods to network traffic
  • ConfigMaps & Secrets: Managing configuration and sensitive data
  • Persistent Volumes: Adding storage to pods

Conclusion

Pods are the foundation of Kubernetes workloads. While you’ll rarely create standalone pods in production (preferring Deployments instead), understanding pod concepts is crucial for:

  • Debugging application issues
  • Understanding Kubernetes architecture
  • Working with higher-level abstractions
  • Troubleshooting production problems

Key Takeaways:

  • Use declarative YAML for reproducibility
  • Always set resource limits
  • Implement health checks
  • Use labels for organization
  • Prefer Deployments over standalone pods in production

Happy clustering! 🚀

Resources