Day 48: Kubernetes Basics - Creating Your First Pod ๐ฏ

Welcome back! ๐ Day 48 of the 100 Days Cloud DevOps Challenge, and today we're entering the Kubernetes world! This is container orchestration at scale - moving from Docker to production-grade K8s. Let's orchestrate! ๐
๐ฏ The Mission - Create First Kubernetes Pod
๐ TASK TICKET #DEV-8048 - Kubernetes Pod Creation
Priority: HIGH | Type: K8s Pod Deployment
Server: jump_host | kubectl: Pre-configured
REQUIREMENTS:
1. Pod Name: pod-httpd
2. Image: httpd:latest (exact tag required)
3. Container Name: httpd-container
4. Label: app=httpd_app
VERIFICATION:
- kubectl get pods
- kubectl describe pod pod-httpd
- Pod in Running state
This is your Kubernetes journey beginning! ๐ฏ
๐ค Why Kubernetes?
Docker limitations at scale:
โ Single host deployments
โ Manual scaling
โ No self-healing
โ Manual load balancing
Kubernetes benefits:
โ Multi-host orchestration
โ Auto-scaling
โ Self-healing (automatic restarts)
โ Built-in load balancing
โ Rolling updates
โ Service discovery
Architecture:
Docker World: Kubernetes World:
docker run httpd โ kubectl create pod
Single container โ Pods (1+ containers)
Manual management โ Declarative config
One host โ Cluster of nodes
๐ Kubernetes Pod Fundamentals
What is a Pod?
Smallest deployable unit in K8s
Can contain 1+ containers
Shared network namespace (same IP)
Shared storage volumes
Scheduled together on same node
Pod vs Container:
Container (Docker): Pod (Kubernetes):
โโ Single process โโ 1+ containers
โโ Isolated โโ Shared network/storage
โโ docker run โโ kubectl create
โโ Docker manages โโ K8s orchestrates
๐ ๏ธ Complete Implementation
Method 1: Imperative (Command-line)
Step 1: Verify kubectl Access
# Check kubectl configured
kubectl version --short
# Check cluster connection
kubectl cluster-info
# View cluster nodes
kubectl get nodes
Expected output:
Client Version: v1.28.0
Server Version: v1.28.0
Kubernetes control plane is running at https://...
Step 2: Create Pod Imperatively
# Create pod with all specifications
kubectl run pod-httpd \
--image=httpd:latest \
--labels=app=httpd_app \
--port=80 \
-- /bin/sh -c "httpd-foreground"
# Note: Container name set via --container-port or editing
Problem: Can't set container name imperatively!
Step 3: Better - Dry Run to Generate YAML
# Generate YAML without creating
kubectl run pod-httpd \
--image=httpd:latest \
--labels=app=httpd_app \
--dry-run=client \
-o yaml > pod-httpd.yaml
Edit generated YAML:
vi pod-httpd.yaml
Modify to add container name:
apiVersion: v1
kind: Pod
metadata:
labels:
app: httpd_app
name: pod-httpd
spec:
containers:
- image: httpd:latest
name: httpd-container # Add this line!
ports:
- containerPort: 80
Create from YAML:
kubectl apply -f pod-httpd.yaml
Method 2: Declarative (Recommended)
Step 1: Create Pod YAML Manifest
cat > pod-httpd.yaml << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: pod-httpd
labels:
app: httpd_app
spec:
containers:
- name: httpd-container
image: httpd:latest
ports:
- containerPort: 80
EOF
YAML Breakdown:
apiVersion: v1 # API version for Pod resource
kind: Pod # Resource type
metadata: # Pod metadata
name: pod-httpd # REQUIRED: Pod name
labels: # Key-value pairs for identification
app: httpd_app # REQUIRED: Label app=httpd_app
spec: # Pod specification
containers: # List of containers (minimum 1)
- name: httpd-container # REQUIRED: Container name
image: httpd:latest # REQUIRED: Image with exact tag
ports: # Optional but recommended
- containerPort: 80 # Container listens on port 80
Step 2: Apply the Manifest
# Create pod from YAML
kubectl apply -f pod-httpd.yaml
Expected output:
pod/pod-httpd created
Step 3: Verification
# Check pod status
kubectl get pods
# Detailed pod info
kubectl get pods -o wide
# Full pod description
kubectl describe pod pod-httpd
# Check pod labels
kubectl get pods --show-labels
# Filter by label
kubectl get pods -l app=httpd_app
Expected outputs:
# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-httpd 1/1 Running 0 30s
# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
pod-httpd 1/1 Running 0 30s 10.244.0.5 node01
# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod-httpd 1/1 Running 0 1m app=httpd_app
Step 4: Detailed Verification
# Verify all requirements
echo "=== Pod Verification ==="
echo "1. Pod name:"
kubectl get pod pod-httpd --no-headers | awk '{print " โ", $1}'
echo "2. Image:"
kubectl get pod pod-httpd -o jsonpath='{.spec.containers[0].image}' && echo ""
echo "3. Container name:"
kubectl get pod pod-httpd -o jsonpath='{.spec.containers[0].name}' && echo ""
echo "4. Labels:"
kubectl get pod pod-httpd -o jsonpath='{.metadata.labels.app}' && echo ""
echo "5. Status:"
kubectl get pod pod-httpd -o jsonpath='{.status.phase}' && echo ""
Expected output:
=== Pod Verification ===
1. Pod name:
โ pod-httpd
2. Image:
httpd:latest
3. Container name:
httpd-container
4. Labels:
httpd_app
5. Status:
Running
Step 5: Access the Pod
# Get pod IP
POD_IP=$(kubectl get pod pod-httpd -o jsonpath='{.status.podIP}')
echo "Pod IP: $POD_IP"
# Access from within cluster (if you have access)
kubectl run test-pod --rm -it --image=busybox -- wget -O- http://$POD_IP
# Check pod logs
kubectl logs pod-httpd
# Execute command in pod
kubectl exec pod-httpd -- ps aux
# Interactive shell
kubectl exec -it pod-httpd -- /bin/bash
๐ Understanding Kubernetes Concepts
Pod Lifecycle
Pending โ ContainerCreating โ Running โ Succeeded/Failed
Pending:
โโ Pod accepted by K8s
โโ Waiting for scheduling
โโ Node assignment pending
ContainerCreating:
โโ Pulling image
โโ Starting containers
โโ Initialization
Running:
โโ All containers started
โโ At least one container running
โโ Healthy state
Succeeded/Failed:
โโ Containers terminated
โโ Exit codes recorded
Labels and Selectors
Why labels matter:
# Pods with labels
metadata:
labels:
app: httpd_app
env: production
version: v1.0
# Select pods
kubectl get pods -l app=httpd_app # One label
kubectl get pods -l env=production # Different label
kubectl get pods -l app=httpd_app,env=prod # Multiple labels
Real-world usage:
# Services select pods by label
# Deployments manage pods by label
# Operations target pods by label
# Examples:
kubectl delete pods -l app=httpd_app
kubectl logs -l app=httpd_app
kubectl describe pods -l env=production
Container vs Pod
Key differences:
| Aspect | Docker Container | Kubernetes Pod |
| Smallest unit | Container | Pod (1+ containers) |
| Network | Isolated | Shared within pod |
| Creation | docker run | kubectl create |
| Management | Manual | K8s orchestrates |
| Scaling | Manual | Automatic |
| Updates | Manual | Rolling updates |
๐ก Key Takeaways
โจ Pods are smallest K8s units
โจ kubectl is K8s CLI tool
โจ YAML manifests define resources declaratively
โจ Labels organize and select resources
โจ Declarative approach preferred over imperative
โจ Image tags should be explicit (not :latest in prod)
โจ Container name identifies container within pod
โจ kubectl get/describe for verification
๐ Quick Interview Q&A
Q: What's the difference between a Docker container and a Kubernetes pod?
A: Pod is K8s smallest unit, can have 1+ containers sharing network/storage. Container is single process. Pods enable multi-container patterns (sidecar, ambassador). Docker manages containers, K8s orchestrates pods.
Q: Why use YAML manifests instead of kubectl run?
A: Manifests are declarative (desired state), version controlled, reusable, complete configuration. kubectl run is imperative (one-time command), hard to reproduce, limited options. Production uses manifests (GitOps).
Q: What happens if you don't specify image tag?
A: Defaults to :latest tag. Problem: "latest" changes over time, unpredictable deployments, no version tracking. Production rule: always specify exact version (httpd:2.4.58, not httpd:latest).
Q: How do labels help in Kubernetes?
A: Labels organize resources (key-value pairs). Enable selection (kubectl get -l), grouping (services find pods), filtering (delete by label). Services use selectors to route traffic. Essential for multi-resource management.
Q: Can a pod have multiple containers?
A: Yes! Multi-container patterns: Sidecar (logging, monitoring), Ambassador (proxy), Adapter (transform output). Containers share network (localhost), storage (volumes), lifecycle. Schedule together, scale together.
Q: What's the pod lifecycle?
A: Pending (scheduled) โ ContainerCreating (pulling image) โ Running (healthy) โ Succeeded/Failed (terminated). Check with kubectl get pods. Debugging: kubectl describe shows events, kubectl logs shows output.
๐ Essential kubectl Commands
Pod operations:
# Create
kubectl apply -f pod.yaml
kubectl run pod-name --image=nginx
# View
kubectl get pods
kubectl get pods -o wide
kubectl describe pod pod-name
# Update
kubectl apply -f pod.yaml # Declarative update
kubectl edit pod pod-name # Interactive edit
# Delete
kubectl delete pod pod-name
kubectl delete -f pod.yaml
Debugging:
# Logs
kubectl logs pod-name
kubectl logs pod-name -f # Follow
kubectl logs pod-name --previous # Previous container
# Execute
kubectl exec pod-name -- command
kubectl exec -it pod-name -- /bin/bash
# Events
kubectl get events
kubectl describe pod pod-name # Shows events
Labels:
# Show labels
kubectl get pods --show-labels
# Filter by label
kubectl get pods -l app=httpd_app
# Add/update label
kubectl label pod pod-name env=prod
# Remove label
kubectl label pod pod-name env-
๐ Common Pod Patterns
1. Simple single-container pod:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.24
2. Multi-container pod (sidecar pattern):
apiVersion: v1
kind: Pod
metadata:
name: app-with-logging
spec:
containers:
- name: app
image: myapp:1.0
- name: log-agent
image: fluentd:v1.16
3. Pod with resource limits:
apiVersion: v1
kind: Pod
metadata:
name: resource-pod
spec:
containers:
- name: app
image: nginx
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
4. Pod with environment variables:
apiVersion: v1
kind: Pod
metadata:
name: env-pod
spec:
containers:
- name: app
image: nginx
env:
- name: ENV
value: "production"
- name: LOG_LEVEL
value: "info"
๐ง Troubleshooting
Pod stuck in Pending:
# Check events
kubectl describe pod pod-name
# Common causes:
# - No nodes available
# - Insufficient resources
# - PersistentVolume issues
# Check nodes
kubectl get nodes
kubectl describe node node-name
Pod in CrashLoopBackOff:
# Check logs
kubectl logs pod-name
kubectl logs pod-name --previous
# Common causes:
# - Application crash
# - Wrong command/args
# - Missing dependencies
# Check container status
kubectl describe pod pod-name
ImagePullBackOff:
# Check events
kubectl describe pod pod-name
# Common causes:
# - Typo in image name
# - Image doesn't exist
# - No pull permissions
# - Registry unreachable
# Verify image exists
docker pull httpd:latest
๐ฏ Best Practices
1. Always specify image tags:
# Bad
image: httpd
# Good
image: httpd:2.4.58
2. Use meaningful labels:
labels:
app: httpd_app
component: frontend
version: v1.0
environment: production
3. Set resource limits:
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
4. Add health checks:
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
5. Use namespaces:
# Create in namespace
kubectl apply -f pod.yaml -n production
# Default namespace
kubectl config set-context --current --namespace=production
๐ Final Thoughts
Congratulations! You've created your first Kubernetes pod!
What you accomplished: โ
Created pod with specific name
โ
Used httpd:latest image
โ
Set custom container name
โ
Applied labels for organization
โ
Verified pod is running
Key learnings:
Pods are K8s fundamental building blocks
YAML manifests define desired state
Labels enable resource organization
kubectl is your K8s control tool
Declarative > Imperative
Next steps:
Deployments (manage multiple pods)
Services (expose pods)
ConfigMaps/Secrets (configuration)
Persistent volumes (storage)
This is your Kubernetes journey! ๐
Day: 48/100
Challenge: KodeKloud Cloud DevOps
Date: December 23, 2025
Topic: Kubernetes Pod Creation
Share your K8s learning journey! ๐ฏ




