Understanding Pods
A Pod is the smallest deployable unit in Kubernetes. It represents a single instance of a running process in your cluster. A Pod encapsulates one or more containers that share the same network namespace (IP address and ports), storage volumes, and lifecycle.
Pod Key Characteristics
- Shared Network: All containers in a Pod share the same IP address and port space, communicating via localhost
- Shared Storage: Containers in a Pod can access shared volumes for data exchange
- Co-scheduling: All containers in a Pod are scheduled on the same node
- Ephemeral: Pods are not designed to be durable — they can be terminated and replaced at any time
- Atomic Unit: Kubernetes manages the entire Pod, not individual containers within it
Single-Container Pod
# single-container-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-web-app
labels:
app: web
environment: development
annotations:
description: "A simple web application pod"
spec:
containers:
- name: web
image: node:20-alpine
command: ["node", "server.js"]
ports:
- containerPort: 3000
name: http
protocol: TCP
env:
- name: NODE_ENV
value: "production"
- name: PORT
value: "3000"
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 15
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
restartPolicy: Always
Multi-Container Pod (Sidecar Pattern)
# sidecar-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: web-with-logging
labels:
app: web
spec:
containers:
# Main application container
- name: web-app
image: my-web-app:1.0
ports:
- containerPort: 3000
volumeMounts:
- name: shared-logs
mountPath: /var/log/app
# Sidecar: log collector
- name: log-collector
image: fluentd:v1.16
volumeMounts:
- name: shared-logs
mountPath: /var/log/app
readOnly: true
- name: fluentd-config
mountPath: /fluentd/etc
# Init container: runs before main containers
initContainers:
- name: init-db-check
image: busybox:1.36
command: ['sh', '-c', 'until nc -z db-service 5432; do echo waiting for db; sleep 2; done']
volumes:
- name: shared-logs
emptyDir: {}
- name: fluentd-config
configMap:
name: fluentd-config
Deployments
A Deployment provides declarative updates for Pods and ReplicaSets. You describe a desired state in a Deployment, and the Deployment controller changes the actual state to the desired state at a controlled rate. Deployments manage ReplicaSets, which in turn manage Pods.
# production-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
labels:
app: api-server
version: v2
spec:
replicas: 3
revisionHistoryLimit: 10
selector:
matchLabels:
app: api-server
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # Max extra pods during update
maxUnavailable: 0 # Zero downtime — all existing pods stay until new ones are ready
template:
metadata:
labels:
app: api-server
version: v2
spec:
containers:
- name: api
image: myregistry/api-server:2.1.0
ports:
- containerPort: 8080
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-credentials
key: url
- name: REDIS_URL
valueFrom:
configMapKeyRef:
name: app-config
key: redis-url
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /readyz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30
periodSeconds: 10
terminationGracePeriodSeconds: 60
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- api-server
topologyKey: kubernetes.io/hostname
Rolling Updates and Rollbacks
# Update the image (triggers a rolling update)
kubectl set image deployment/api-server api=myregistry/api-server:2.2.0
# Watch the rollout progress
kubectl rollout status deployment/api-server
# View rollout history
kubectl rollout history deployment/api-server
# View details of a specific revision
kubectl rollout history deployment/api-server --revision=3
# Rollback to the previous version
kubectl rollout undo deployment/api-server
# Rollback to a specific revision
kubectl rollout undo deployment/api-server --to-revision=2
# Pause a rollout (for canary-style testing)
kubectl rollout pause deployment/api-server
# Resume a paused rollout
kubectl rollout resume deployment/api-server
# Scale a deployment
kubectl scale deployment/api-server --replicas=5
Pod Lifecycle
| Phase | Description |
|---|---|
| Pending | Pod accepted but containers not yet created (image pulling, scheduling) |
| Running | Pod bound to a node, all containers created, at least one running |
| Succeeded | All containers terminated successfully and will not restart |
| Failed | All containers terminated, at least one terminated in failure |
| Unknown | Pod state cannot be obtained (usually node communication failure) |
Health Checks: Probes
Kubernetes uses three types of probes to determine container health and readiness:
- Liveness Probe: Determines if a container is running. If it fails, kubelet kills the container and applies the restart policy.
- Readiness Probe: Determines if a container is ready to serve traffic. Failing pods are removed from Service endpoints.
- Startup Probe: Determines if a container application has started. Disables liveness/readiness checks until it succeeds — useful for slow-starting applications.
Key Takeaways
- Pods are the smallest deployable unit — they contain one or more containers sharing network and storage
- Deployments manage ReplicaSets to ensure the desired number of Pod replicas are running
- Rolling updates provide zero-downtime deployments with easy rollback capability
- Always configure resource requests/limits and health probes for production workloads
- Use pod anti-affinity to spread replicas across nodes for high availability