Practical Applications and Examples
The real test of production deployment knowledge comes when you’re deploying actual applications with real users, real data, and real consequences for downtime. I’ve deployed everything from simple web APIs to complex microservice architectures, and each application type has taught me something new about production requirements.
The most valuable lesson I’ve learned: every application is different, but the patterns for reliable deployment are surprisingly consistent.
Web Application Deployment
Here’s how I deploy a typical Node.js web application with all the production requirements:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: production
spec:
replicas: 5
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
spec:
containers:
- name: web-app
image: web-app:v2.1.0
ports:
- containerPort: 3000
- containerPort: 9090
name: metrics
env:
- name: NODE_ENV
value: production
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database_url
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 3000
readinessProbe:
httpGet:
path: /ready
port: 3000
securityContext:
runAsNonRoot: true
runAsUser: 1000
---
apiVersion: v1
kind: Service
metadata:
name: web-app-service
spec:
selector:
app: web-app
ports:
- port: 80
targetPort: 3000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-app-ingress
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- app.example.com
secretName: web-app-tls
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-app-service
port:
number: 80
Microservices Architecture
Microservices deployments require coordination between multiple services. Here’s a typical e-commerce setup:
# API Gateway
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
spec:
replicas: 3
selector:
matchLabels:
app: api-gateway
template:
metadata:
labels:
app: api-gateway
spec:
containers:
- name: api-gateway
image: api-gateway:v1.1.0
env:
- name: USER_SERVICE_URL
value: http://user-service
- name: PRODUCT_SERVICE_URL
value: http://product-service
- name: ORDER_SERVICE_URL
value: http://order-service
---
# User Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: user-service:v1.3.0
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: user-db-secret
key: url
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: auth-secret
key: jwt_secret
Database Deployment
Databases require special consideration for persistence and backups:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: database
spec:
serviceName: postgres-headless
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15-alpine
env:
- name: POSTGRES_DB
value: myapp_production
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-credentials
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-credentials
key: password
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
resources:
requests:
memory: "2Gi"
cpu: "1000m"
limits:
memory: "4Gi"
cpu: "2000m"
volumeClaimTemplates:
- metadata:
name: postgres-storage
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: fast-ssd
resources:
requests:
storage: 100Gi
---
# Database Backup
apiVersion: batch/v1
kind: CronJob
metadata:
name: postgres-backup
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: postgres:15-alpine
command:
- /bin/bash
- -c
- |
pg_dump -h postgres -U $POSTGRES_USER -d $POSTGRES_DB > /backup/backup-$(date +%Y%m%d).sql
aws s3 cp /backup/backup-$(date +%Y%m%d).sql s3://backups/
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-credentials
key: username
- name: POSTGRES_DB
value: myapp_production
restartPolicy: OnFailure
Background Jobs
Background job processing requires different deployment patterns:
apiVersion: apps/v1
kind: Deployment
metadata:
name: job-worker
spec:
replicas: 3
selector:
matchLabels:
app: job-worker
template:
metadata:
labels:
app: job-worker
spec:
containers:
- name: worker
image: job-worker:v1.0.0
env:
- name: REDIS_URL
value: redis://redis-service:6379
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: app-secrets
key: database_url
- name: WORKER_CONCURRENCY
value: "5"
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "400m"
CI/CD Pipeline Integration
I integrate deployment with CI/CD pipelines for automated, reliable deployments:
name: Deploy to Production
on:
push:
tags: ['v*']
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build and push images
run: |
docker build -t $ECR_REGISTRY/web-app:$GITHUB_SHA ./web-app
docker build -t $ECR_REGISTRY/user-service:$GITHUB_SHA ./user-service
docker push $ECR_REGISTRY/web-app:$GITHUB_SHA
docker push $ECR_REGISTRY/user-service:$GITHUB_SHA
- name: Security scan
run: |
trivy image --exit-code 1 --severity HIGH,CRITICAL \
$ECR_REGISTRY/web-app:$GITHUB_SHA
- name: Deploy to production
run: |
kubectl set image deployment/web-app \
web-app=$ECR_REGISTRY/web-app:$GITHUB_SHA
kubectl rollout status deployment/web-app --timeout=300s
- name: Run smoke tests
run: |
curl -f https://api.example.com/health
Blue-Green Deployment
For zero-downtime deployments, I use blue-green strategies:
#!/bin/bash
NEW_VERSION=$1
CURRENT_COLOR=$(kubectl get service production-service -o jsonpath='{.spec.selector.color}')
if [ "$CURRENT_COLOR" = "blue" ]; then
NEW_COLOR="green"
else
NEW_COLOR="blue"
fi
# Deploy new version to inactive color
kubectl set image deployment/app-$NEW_COLOR app=myapp:$NEW_VERSION
kubectl rollout status deployment/app-$NEW_COLOR --timeout=300s
# Health check
if curl -f http://localhost:8080/health; then
# Switch traffic
kubectl patch service production-service -p \
'{"spec":{"selector":{"color":"'$NEW_COLOR'"}}}'
echo "Traffic switched to $NEW_COLOR"
else
echo "Health check failed"
exit 1
fi
These practical examples demonstrate how to apply production deployment concepts to real applications. Each application type has specific requirements, but the underlying patterns of reliability, scalability, and observability remain consistent.
Next, we’ll explore advanced techniques including service mesh, advanced deployment strategies, and enterprise-grade operational patterns.