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
- containers: List of containers in the pod
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:
- Delete the existing pod
- Modify the YAML file
- 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! 🚀