Chapter 4: Pods & Deployments
Authored by syscook.dev
What are Pods and Deployments?
Pods are the smallest deployable units in Kubernetes, representing one or more containers that share storage, network, and lifecycle. Deployments are higher-level abstractions that manage ReplicaSets and provide declarative updates to pods, ensuring your application runs reliably with the desired number of replicas.
Key Concepts:
- Pods: Basic execution units containing one or more containers
- Deployments: Controllers that manage pod replicas and updates
- ReplicaSets: Lower-level controllers that maintain desired pod count
- Pod Lifecycle: States and transitions pods go through
- Container Specs: Detailed container configuration and requirements
- Update Strategies: Rolling updates, blue-green deployments, canary releases
Why Use Pods and Deployments?
1. Container Orchestration
Pods provide a logical host for containers, sharing resources and networking.
# Example: Multi-container pod
apiVersion: v1
kind: Pod
metadata:
name: web-app-pod
labels:
app: web-app
tier: frontend
spec:
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
env:
- name: ENV
value: "production"
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
volumeMounts:
- name: web-content
mountPath: /usr/share/nginx/html
- name: log-processor
image: fluent/fluent-bit:1.8
env:
- name: FLB_LOG_LEVEL
value: "info"
volumeMounts:
- name: web-content
mountPath: /var/log/nginx
volumes:
- name: web-content
emptyDir: {}
restartPolicy: Always
Pod Configuration Explanation:
containers
: Array of containers to run in the podports
: Ports to expose from containersenv
: Environment variables for containersresources
: CPU and memory requests and limitsvolumeMounts
: Mount points for volumesvolumes
: Shared storage for containersrestartPolicy
: What happens when container exits
2. High Availability and Scaling
Deployments ensure your application runs with the desired number of replicas and handles failures automatically.
# Example: Production deployment with scaling
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-deployment
namespace: production
labels:
app: web-app
version: v1.0
spec:
replicas: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 2
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
version: v1.0
spec:
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
env:
- name: ENV
value: "production"
- name: LOG_LEVEL
value: "info"
Deployment Configuration Explanation:
replicas
: Number of pod replicas to maintainstrategy
: Update strategy (RollingUpdate, Recreate)rollingUpdate
: Configuration for rolling updatesmaxUnavailable
: Maximum pods that can be unavailable during updatemaxSurge
: Maximum pods that can be created above desired replicas
selector
: Label selector to identify managed podstemplate
: Pod template for creating new podslivenessProbe
: Health check to determine if container is alivereadinessProbe
: Health check to determine if container is ready to serve traffic
3. Zero-Downtime Updates
Deployments support rolling updates with automatic rollback capabilities.
# Example: Rolling update deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-deployment
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
How to Use Pods and Deployments?
1. Basic Pod Configuration
Single Container Pod
# Example: Simple web server pod
apiVersion: v1
kind: Pod
metadata:
name: simple-web-pod
labels:
app: web-server
environment: development
spec:
containers:
- name: nginx
image: nginx:1.20
ports:
- containerPort: 80
protocol: TCP
env:
- name: NGINX_HOST
value: "localhost"
- name: NGINX_PORT
value: "80"
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d
readOnly: true
volumes:
- name: nginx-config
configMap:
name: nginx-config
restartPolicy: Always
terminationGracePeriodSeconds: 30
Multi-Container Pod
# Example: Web application with sidecar containers
apiVersion: v1
kind: Pod
metadata:
name: web-app-with-sidecars
labels:
app: web-app
tier: frontend
spec:
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
env:
- name: ENV
value: "production"
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
volumeMounts:
- name: web-content
mountPath: /usr/share/nginx/html
- name: nginx-logs
mountPath: /var/log/nginx
- name: log-collector
image: fluent/fluent-bit:1.8
env:
- name: FLB_LOG_LEVEL
value: "info"
- name: FLB_INPUT
value: "tail"
- name: FLB_OUTPUT
value: "elasticsearch"
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
volumeMounts:
- name: nginx-logs
mountPath: /var/log/nginx
readOnly: true
- name: metrics-collector
image: prom/node-exporter:latest
ports:
- containerPort: 9100
resources:
requests:
memory: "32Mi"
cpu: "50m"
limits:
memory: "64Mi"
cpu: "100m"
volumes:
- name: web-content
emptyDir: {}
- name: nginx-logs
emptyDir: {}
restartPolicy: Always
2. Advanced Pod Configuration
Init Containers
# Example: Pod with init containers
apiVersion: v1
kind: Pod
metadata:
name: web-app-with-init
labels:
app: web-app
spec:
initContainers:
- name: wait-for-database
image: busybox:1.35
command: ['sh', '-c']
args:
- |
until nc -z database-service 5432; do
echo "Waiting for database..."
sleep 2
done
echo "Database is ready!"
resources:
requests:
memory: "32Mi"
cpu: "50m"
limits:
memory: "64Mi"
cpu: "100m"
- name: download-config
image: busybox:1.35
command: ['sh', '-c']
args:
- |
wget -O /shared/config.json https://config-server/config.json
echo "Configuration downloaded!"
volumeMounts:
- name: shared-data
mountPath: /shared
resources:
requests:
memory: "32Mi"
cpu: "50m"
limits:
memory: "64Mi"
cpu: "100m"
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
volumeMounts:
- name: shared-data
mountPath: /etc/nginx/conf.d
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
volumes:
- name: shared-data
emptyDir: {}
restartPolicy: Always
Pod Security Context
# Example: Pod with security context
apiVersion: v1
kind: Pod
metadata:
name: secure-web-pod
labels:
app: web-app
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
volumeMounts:
- name: tmp
mountPath: /tmp
- name: var-cache
mountPath: /var/cache/nginx
- name: var-run
mountPath: /var/run
volumes:
- name: tmp
emptyDir: {}
- name: var-cache
emptyDir: {}
- name: var-run
emptyDir: {}
restartPolicy: Always
3. Deployment Configuration
Basic Deployment
# Example: Basic deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-deployment
namespace: production
labels:
app: web-app
version: v1.0
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
version: v1.0
spec:
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
env:
- name: ENV
value: "production"
- name: LOG_LEVEL
value: "info"
Advanced Deployment with Probes
# Example: Deployment with comprehensive health checks
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-deployment
namespace: production
labels:
app: web-app
version: v1.0
spec:
replicas: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 2
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
version: v1.0
spec:
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /health
port: 80
httpHeaders:
- name: Custom-Header
value: "health-check"
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
successThreshold: 1
startupProbe:
httpGet:
path: /startup
port: 80
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 30
successThreshold: 1
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
env:
- name: ENV
value: "production"
- name: LOG_LEVEL
value: "info"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/conf.d
readOnly: true
- name: logs-volume
mountPath: /var/log/nginx
volumes:
- name: config-volume
configMap:
name: nginx-config
- name: logs-volume
emptyDir: {}
restartPolicy: Always
terminationGracePeriodSeconds: 30
Deployment with Node Affinity
# Example: Deployment with node affinity and anti-affinity
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-deployment
namespace: production
spec:
replicas: 5
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- amd64
- key: node-type
operator: In
values:
- web
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web-app
topologyKey: kubernetes.io/hostname
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
4. Update Strategies
Rolling Update Strategy
# Example: Rolling update deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-deployment
spec:
replicas: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 2
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
Recreate Strategy
# Example: Recreate strategy deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: database-deployment
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: database
template:
metadata:
labels:
app: database
spec:
containers:
- name: postgres
image: postgres:13
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: "myapp"
- name: POSTGRES_USER
value: "user"
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: postgres-pvc
Practical Examples
1. Complete Web Application Deployment
Step 1: Create ConfigMap and Secret
#!/bin/bash
# create-config-secret.sh
# Create ConfigMap
kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
namespace: production
data:
default.conf: |
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
location /ready {
access_log off;
return 200 "ready\n";
add_header Content-Type text/plain;
}
}
EOF
# Create Secret
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
namespace: production
type: Opaque
data:
database-url: cG9zdGdyZXM6Ly91c2VyOnBhc3N3b3JkQGRhdGFiYXNlOjU0MzIvbXlhcHA=
api-key: YWJjZGVmZ2hpams=
EOF
echo "ConfigMap and Secret created successfully!"
Step 2: Create Deployment
#!/bin/bash
# create-deployment.sh
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-deployment
namespace: production
labels:
app: web-app
version: v1.0
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
version: v1.0
spec:
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
env:
- name: ENV
value: "production"
- name: LOG_LEVEL
value: "info"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database-url
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/conf.d
readOnly: true
- name: logs-volume
mountPath: /var/log/nginx
volumes:
- name: config-volume
configMap:
name: nginx-config
- name: logs-volume
emptyDir: {}
restartPolicy: Always
terminationGracePeriodSeconds: 30
EOF
echo "Deployment created successfully!"
Step 3: Create Service
#!/bin/bash
# create-service.sh
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: web-app-service
namespace: production
labels:
app: web-app
spec:
selector:
app: web-app
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
EOF
echo "Service created successfully!"
2. Blue-Green Deployment
Step 1: Create Blue Deployment
#!/bin/bash
# create-blue-deployment.sh
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-blue
namespace: production
labels:
app: web-app
version: blue
spec:
replicas: 3
selector:
matchLabels:
app: web-app
version: blue
template:
metadata:
labels:
app: web-app
version: blue
spec:
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
EOF
echo "Blue deployment created successfully!"
Step 2: Create Green Deployment
#!/bin/bash
# create-green-deployment.sh
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-green
namespace: production
labels:
app: web-app
version: green
spec:
replicas: 3
selector:
matchLabels:
app: web-app
version: green
template:
metadata:
labels:
app: web-app
version: green
spec:
containers:
- name: web-server
image: nginx:1.21
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
EOF
echo "Green deployment created successfully!"
Step 3: Switch Traffic
#!/bin/bash
# switch-traffic.sh
# Switch service to green deployment
kubectl patch service web-app-service -n production -p '{"spec":{"selector":{"version":"green"}}}'
echo "Traffic switched to green deployment!"
# Verify the switch
kubectl get pods -n production -l app=web-app
kubectl get service web-app-service -n production
3. Canary Deployment
Step 1: Create Stable Deployment
#!/bin/bash
# create-stable-deployment.sh
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-stable
namespace: production
labels:
app: web-app
version: stable
spec:
replicas: 9
selector:
matchLabels:
app: web-app
version: stable
template:
metadata:
labels:
app: web-app
version: stable
spec:
containers:
- name: web-server
image: nginx:1.20
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
EOF
echo "Stable deployment created successfully!"
Step 2: Create Canary Deployment
#!/bin/bash
# create-canary-deployment.sh
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-canary
namespace: production
labels:
app: web-app
version: canary
spec:
replicas: 1
selector:
matchLabels:
app: web-app
version: canary
template:
metadata:
labels:
app: web-app
version: canary
spec:
containers:
- name: web-server
image: nginx:1.21
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
EOF
echo "Canary deployment created successfully!"
Step 3: Monitor and Promote
#!/bin/bash
# monitor-canary.sh
# Monitor canary deployment
kubectl get pods -n production -l app=web-app
kubectl logs -n production -l app=web-app,version=canary
# Check metrics (if monitoring is set up)
kubectl top pods -n production -l app=web-app
# Promote canary to stable
kubectl patch deployment web-app-stable -n production -p '{"spec":{"template":{"spec":{"containers":[{"name":"web-server","image":"nginx:1.21"}]}}}}'
echo "Canary promoted to stable!"
Best Practices
1. Resource Management
# Good: Always specify resource requests and limits
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
2. Health Checks
# Good: Comprehensive health checks
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
3. Security Configuration
# Good: Security context configuration
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
Common Pitfalls and Solutions
1. Missing Resource Limits
# ❌ Bad: No resource limits
spec:
containers:
- name: web-server
image: nginx:1.20
# ✅ Good: Proper resource limits
spec:
containers:
- name: web-server
image: nginx:1.20
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
2. Inadequate Health Checks
# ❌ Bad: No health checks
spec:
containers:
- name: web-server
image: nginx:1.20
# ✅ Good: Proper health checks
spec:
containers:
- name: web-server
image: nginx:1.20
livenessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 5
periodSeconds: 5
3. Poor Update Strategy
# ❌ Bad: No update strategy
spec:
replicas: 3
selector:
matchLabels:
app: web-app
# ✅ Good: Proper update strategy
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
selector:
matchLabels:
app: web-app
Conclusion
Pods and Deployments are fundamental building blocks of Kubernetes applications. By understanding:
- What pods and deployments are and their purposes
- Why they're essential for container orchestration and application management
- How to configure them properly with health checks, resource limits, and update strategies
You can create robust, scalable, and maintainable applications in Kubernetes. Proper configuration ensures that your applications run reliably, scale effectively, and update safely in production environments.
Next Steps
- Practice with different deployment strategies
- Learn about services and networking
- Move on to Chapter 5: Services & Networking
This tutorial is part of the Kubernetes Mastery series by syscook.dev