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.