Containers, Kubernetes, microservices, and modern infrastructure patterns
Cloud native architecture has become the default approach for modern software infrastructure. Containerization, microservices, and Kubernetes have transformed how applications are built, deployed, and operated. Understanding these patterns is essential for anyone building or running production software systems.
This article covers the cloud native landscape: container fundamentals, container orchestration with Kubernetes, microservices patterns, service mesh, and the 12-factor app methodology.
Containers package applications with their dependencies, providing consistency across environments:
Container vs VM:
VM: Guest OS + Libraries + App (heavy, slow)
Container: App + Libraries only (lightweight, fast)
A container is a process isolated from other processes but sharing the kernel
Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]
Build and run:
docker build -t myapp:latest .
docker run -p 8080:8080 myapp:latest
Store and distribute container images:
Kubernetes (K8s) automates deployment, scaling, and management of containerized applications.
┌─────────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ │
│ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ Master │ │ Worker Nodes │ │
│ │ (Control) │ │ │ │
│ │ - API Server │ │ ┌──────┐ ┌──────┐ │ │
│ │ - Scheduler │ │ │ Pod │ │ Pod │ │ │
│ │ - etcd │──────────│ └──────┘ └──────┘ │ │
│ │ - Controller│ │ ┌──────┐ ┌──────┐ │ │
│ └─────────────┘ │ │ Pod │ │ Pod │ │ │
│ │ └──────┘ └──────┘ │ │
│ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Pod: Basic deployable unit (one or more containers)
Deployment: Declarative updates for Pods
Service: Stable network endpoint for Pods
ConfigMap: Configuration data (key-value pairs)
Secret: Sensitive data (base64 encoded)
PersistentVolume: Persistent storage
Namespace: Virtual cluster for resource isolation
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:latest
ports:
- containerPort: 8080
resources:
limits:
memory: "256Mi"
cpu: "500m"
Service (ClusterIP - internal):
apiVersion: v1
kind: Service
metadata:
name: myapp-svc
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 8080
type: ClusterIP
Ingress (external access):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp-svc
port:
number: 80
Microservices decompose applications into small, independent services that communicate via APIs:
| Aspect | Monolith | Microservices |
|---|---|---|
| Deployment | Single unit | Independent per service |
| Scaling | Scale entire app | Scale hot services |
| Technology | Single stack | Polyglot |
| Team autonomy | Limited | High |
| Complexity | Low initial | High (distributed) |
| Debugging | Easier | Harder (distributed) |
Client → API Gateway → [Service A]
→ [Service B]
→ [Service C]
API Gateway responsibilities:
- Request routing
- Authentication/Authorization
- Rate limiting
- Request/Response transformation
- API versioning
A service mesh adds infrastructure capabilities (observability, security, reliability) without modifying application code:
| Feature | Istio | Linkerd |
|---|---|---|
| Complexity | High | Lower |
| Performance | Moderate | Better |
| Adoption | Higher | Growing |
| Best For | Large, complex deployments | Simpler needs |
Without service mesh:
Service A → → → Service B
With service mesh:
Service A → [Sidecar] → [Sidecar] → Service B
↓
Service Mesh Control Plane
Each pod gets a sidecar proxy that intercepts all network traffic
Best practices for cloud native applications:
Pipeline stages:
1. Build: Compile code, run tests
2. Containerize: Build Docker image, tag with commit SHA
3. Scan: Security scan for vulnerabilities
4. Push: Push to container registry
5. Deploy: Update Kubernetes manifests, apply to cluster
Tools:
- CI: GitHub Actions, GitLab CI, Jenkins
- Security: Trivy, Snyk, Clair
- Registry: ECR, GCR, Harbor
GitOps workflow:
1. Developer commits to Git repository
2. CI pipeline builds and pushes container image
3. CI updates Kubernetes manifests in Git (image tag)
4. ArgoCD detects drift from desired state
5. ArgoCD syncs cluster to match Git state
Result: Git is source of truth; cluster state converges to Git
Serverless abstracts even infrastructure management:
Traditional: Container → Kubernetes → Cluster Management
Serverless: Function → Platform (automatic scaling, billing per invocation)
Providers:
- AWS Lambda
- Google Cloud Functions
- Azure Functions
- Knative (self-hosted serverless on Kubernetes)
Without circuit breaker:
Service A → Service B → [DOWN]
→ A waits for timeout
→ Resources exhausted
→ A also fails
With circuit breaker:
Service A → [Circuit Breaker] → Service B
↓
Closed (normal) → Open (failing) → Half-open (test)
Closed: Requests pass through
Open: Requests fail fast (return error immediately)
Half-open: Allow test requests through
Liveness probe: Is the process running?
- If fails: Restart the container
- For crashed processes
Readiness probe: Is the service ready to receive traffic?
- If fails: Remove from service endpoints
- For initialization, dependencies unavailable
Startup probe: Is the container done starting?
- For slow-starting containers
- Disables liveness during startup
Cloud native architecture has matured significantly. Containers provide consistent packaging. Kubernetes has won the orchestration wars. Microservices patterns are well-understood. Service mesh adds capabilities without code changes.
The key principles remain: build for resilience, design for observability, automate everything, and embrace the twelve-factor methodology. Cloud native isn't a goal in itself—it's a set of patterns that enable the agility and reliability modern applications demand.