Skip to main content

Monolith to Kubernetes Migration

This comprehensive guide covers the complete journey of migrating monolithic applications to a Kubernetes-based microservices architecture.

Overview

Migrating from a monolithic architecture to Kubernetes microservices is a complex transformation that requires careful planning, strategic decomposition, and systematic implementation. This guide provides a complete roadmap for this journey.

Service Decomposition Strategies

1. Domain-Driven Design (DDD) Approach

Bounded Contexts: Identify natural business boundaries within your monolith.

# Example: E-commerce domain decomposition
domains:
- catalog-service: # Product catalog, inventory
- order-service: # Order processing, payments
- user-service: # User management, authentication
- shipping-service: # Shipping, delivery tracking
- notification-service: # Email, SMS notifications

2. Strangler Fig Pattern

Gradual Migration: Replace monolith functionality piece by piece.

# Migration phases
phase1:
- extract: user-authentication
- deploy: user-service
- route: 50% traffic to new service

phase2:
- extract: product-catalog
- deploy: catalog-service
- route: 100% catalog traffic

phase3:
- extract: order-processing
- deploy: order-service
- route: 75% order traffic

3. Database Decomposition

Shared Database → Database per Service:

-- Before: Monolithic database
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(255),
email VARCHAR(255),
order_count INT,
total_spent DECIMAL(10,2)
);

-- After: Service-specific databases
-- user-service database
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(255),
email VARCHAR(255)
);

-- order-service database
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
total_amount DECIMAL(10,2)
);

Kubernetes Deployment Strategies

1. Blue-Green Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service-blue
spec:
replicas: 3
selector:
matchLabels:
app: user-service
version: blue
template:
metadata:
labels:
app: user-service
version: blue
spec:
containers:
- name: user-service
image: user-service:v1.0
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
selector:
app: user-service
version: blue # Switch to 'green' for new version
ports:
- port: 80
targetPort: 8080

2. Canary Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service-canary
spec:
replicas: 1 # Small percentage of traffic
selector:
matchLabels:
app: user-service
version: canary
template:
metadata:
labels:
app: user-service
version: canary
spec:
containers:
- name: user-service
image: user-service:v2.0
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: user-service-ingress
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "10" # 10% traffic
spec:
rules:
- host: user-service.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: user-service-canary
port:
number: 80

3. Rolling Updates

apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
replicas: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # Maximum pods above desired
maxUnavailable: 1 # Maximum pods unavailable
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: user-service:v2.0
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 20

Key Migration Considerations

1. Data Consistency

Event Sourcing Pattern:

# Event store for maintaining data consistency
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: event-store
spec:
serviceName: event-store
replicas: 3
selector:
matchLabels:
app: event-store
template:
metadata:
labels:
app: event-store
spec:
containers:
- name: event-store
image: eventstore/eventstore:latest
ports:
- containerPort: 1113
- containerPort: 2113
volumeMounts:
- name: event-store-data
mountPath: /var/lib/eventstore
volumeClaimTemplates:
- metadata:
name: event-store-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi

2. Service Discovery

Kubernetes Service Discovery:

apiVersion: v1
kind: Service
metadata:
name: user-service
labels:
app: user-service
spec:
selector:
app: user-service
ports:
- name: http
port: 80
targetPort: 8080
type: ClusterIP

3. Configuration Management

ConfigMaps and Secrets:

apiVersion: v1
kind: ConfigMap
metadata:
name: user-service-config
data:
DATABASE_URL: "postgresql://user-service:5432/users"
REDIS_URL: "redis://redis-service:6379"
LOG_LEVEL: "INFO"
---
apiVersion: v1
kind: Secret
metadata:
name: user-service-secrets
type: Opaque
data:
DATABASE_PASSWORD: <base64-encoded-password>
JWT_SECRET: <base64-encoded-jwt-secret>
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
template:
spec:
containers:
- name: user-service
image: user-service:latest
env:
- name: DATABASE_URL
valueFrom:
configMapKeyRef:
name: user-service-config
key: DATABASE_URL
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: user-service-secrets
key: DATABASE_PASSWORD

Case Study: E-commerce Platform Migration

Before: Monolithic Architecture

┌─────────────────────────────────────┐
│ E-commerce App │
│ ┌─────────┬─────────┬─────────┐ │
│ │ Users │ Catalog │ Orders │ │
│ └─────────┴─────────┴─────────┘ │
│ ┌─────────┬─────────┬─────────┐ │
│ │Payment │Shipping │Notification│ │
│ └─────────┴─────────┴─────────┘ │
└─────────────────────────────────────┘

After: Microservices Architecture

┌─────────┐  ┌─────────┐  ┌─────────┐
│ Users │ │ Catalog │ │ Orders │
└─────────┘ └─────────┘ └─────────┘
│ │ │
└────────────┼────────────┘

┌─────────┐ ┌─────────┐ ┌─────────┐
│Payment │ │Shipping │ │Notification│
└─────────┘ └─────────┘ └─────────┘

Migration Timeline

week1-2:
- extract: user-authentication
- deploy: user-service
- test: authentication flows

week3-4:
- extract: product-catalog
- deploy: catalog-service
- test: product browsing

week5-6:
- extract: order-processing
- deploy: order-service
- test: order creation

week7-8:
- extract: payment-processing
- deploy: payment-service
- test: payment flows

week9-10:
- extract: shipping-tracking
- deploy: shipping-service
- test: delivery tracking

week11-12:
- extract: notifications
- deploy: notification-service
- test: email/SMS delivery

Common Challenges and Troubleshooting

1. Database Connection Issues

Problem: Services can't connect to databases after migration.

Solution: Use Kubernetes services for database discovery.

# Database service
apiVersion: v1
kind: Service
metadata:
name: postgres-service
spec:
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
type: ClusterIP

2. Service Communication Failures

Problem: Inter-service communication breaks after migration.

Solution: Implement circuit breakers and retry mechanisms.

# Service mesh configuration (Istio)
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: user-service
spec:
hosts:
- user-service
http:
- route:
- destination:
host: user-service
subset: v1
weight: 90
- destination:
host: user-service
subset: v2
weight: 10
retries:
attempts: 3
perTryTimeout: 2s

3. Performance Degradation

Problem: Services perform worse than the monolith.

Solution: Optimize resource allocation and implement caching.

apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
template:
spec:
containers:
- name: user-service
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
env:
- name: REDIS_CACHE_URL
value: "redis://redis-service:6379"

4. Data Consistency Issues

Problem: Data becomes inconsistent across services.

Solution: Implement saga pattern for distributed transactions.

# Saga orchestrator
apiVersion: apps/v1
kind: Deployment
metadata:
name: saga-orchestrator
spec:
replicas: 3
selector:
matchLabels:
app: saga-orchestrator
template:
metadata:
labels:
app: saga-orchestrator
spec:
containers:
- name: saga-orchestrator
image: saga-orchestrator:latest
env:
- name: EVENT_STORE_URL
value: "eventstore://event-store:1113"

Summary

Successfully migrating from a monolith to Kubernetes microservices requires:

  1. Strategic Planning: Domain-driven decomposition
  2. Gradual Migration: Strangler fig pattern implementation
  3. Proper Tooling: Kubernetes manifests, service mesh, monitoring
  4. Testing Strategy: Comprehensive testing at each phase
  5. Operational Excellence: Monitoring, logging, and troubleshooting

The key is to approach this as an iterative process, not a big-bang migration. Start with the most independent services, establish patterns, and gradually migrate the entire application while maintaining business continuity.