This repository defines the runtime orchestration layer for Ferrum. This repository is responsible for:
- distributed runtime orchestration
- container networking
- Kubernetes deployment management
- observability infrastructure
- autoscaling configuration
- failure injection testing
- production readiness configuration
- persistent infrastructure configuration
- service discovery
- local cloud simulation
- CI/CD deployment integration
This repository does not contain application business logic.
Instead, it manages the operational environment required for the gateway and worker services to function as a distributed platform.
The infrastructure evolved from a simple Docker Compose runtime into a Kubernetes-orchestrated distributed system with:
- autoscaling
- observability
- failure recovery
- retry handling
- dead letter queues
- rolling deployments
- persistent volumes
- readiness/liveness probes
- Prometheus metrics
- structured logging
- production-safe deployment pattern
┌────────────────────┐
│ Client │
└─────────┬──────────┘
│
▼
┌──────────────────────────┐
│ Gateway │
│ FastAPI Service │
│ Horizontal Autoscaling │
└─────────┬────────────────┘
│
┌─────────────────┴──────────────────┐
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ PostgreSQL │ │ Redis │
│ Persistent State │ │ Queue + Cache │
└──────────────────┘ └────────┬─────────┘
│
▼
┌────────────────────┐
│ Worker │
│ Async Consumer Pool│
│ Horizontal Scaling │
└─────────┬──────────┘
│
┌────────────────────────┴────────────────────┐
▼ ▼
┌──────────────────────┐ ┌────────────────────┐
│ Retry Queue Handling │ │ Dead Letter Queue │
└──────────────────────┘ └────────────────────┘
▼
External Webhook Endpoints
┌────────────────────────────────────────────┐
│ Observability │
└────────────────────────────────────────────┘
Prometheus → Metrics Collection
Grafana → Dashboards
Kubernetes → Health Monitoring
Structured Logs → Failure Analysis
| Component | Responsibility |
|---|---|
| Docker Compose | Local orchestration |
| Kubernetes | Container orchestration |
| Minikube | Local Kubernetes cluster |
| PostgreSQL | Persistent database |
| Redis | Queue + cache layer |
| Prometheus | Metrics scraping |
| Grafana | Visualization dashboards |
| HPA | Horizontal pod autoscaling |
| PVC | Persistent database storage |
| ConfigMaps | Environment configuration |
| Secrets | Credential management |
| Deployments | Replica orchestration |
| Services | Internal networking |
| Probes | Health verification |
infra/
├── README.md
├── docker-compose.yml
├── k8s
│ ├── config
│ │ ├── ferrum-config.yaml
│ │ ├── grafana-datasource-config.yaml
│ │ ├── postgres-init.yaml
│ │ └── prometheus-config.yaml
│ ├── hpa
│ │ ├── gateway-hpa.yaml
│ │ └── worker-hpa.yaml
│ ├── namespace
│ │ └── namespace.yaml
│ ├── pdb
│ │ ├── gateway-pdb.yaml
│ │ └── worker-pdb.yaml
│ ├── pvc
│ │ └── postgres-pvc.yaml
│ ├── secret
│ │ └── postgres-secret.yaml
│ └── services
│ ├── gateway.yaml
│ ├── grafana.yaml
│ ├── postgres.yaml
│ ├── prometheus.yaml
│ ├── redis.yaml
│ └── worker.yaml
├── new.md
├── postgres
│ └── init.sh
├── prometheus.yml
└── tests
├── k6-chaos.js
└── load-test.js
The infrastructure repository progressively introduced production-grade platform engineering concepts.
All services execute inside Docker containers.
Benefits achieved:
- reproducible environments
- isolated dependencies
- deterministic deployments
- portable runtimes
- simplified orchestration
Ferrum evolved from a single-process application into a distributed service topology.
Final runtime topology:
- gateway service
- worker service
- Redis queue
- PostgreSQL database
- Prometheus monitoring
- Grafana visualization
Each service became independently deployable and scalable.
All infrastructure is declared through:
- Docker Compose
- Kubernetes manifests
- ConfigMaps
- Secrets
- HPA definitions
This enabled:
- reproducible deployments
- deterministic environments
- version-controlled infrastructure
- rollback capability
- operational consistency
The project introduced real orchestration concepts:
| Kubernetes Concept | Purpose |
|---|---|
| Pod | execution unit |
| Deployment | replica management |
| ReplicaSet | pod replication |
| Service | internal networking |
| Namespace | isolation |
| ConfigMap | configuration injection |
| Secret | credential injection |
| PVC | persistent storage |
| HPA | autoscaling |
| Probes | health monitoring |
Ferrum added full metrics instrumentation.
Observability stack:
- Prometheus
- Grafana
- structured logs
- latency histograms
- queue delay metrics
- throughput metrics
- failure counters
This transformed the system from:
"hope it works"
into:
measurable operational visibility
Phase 9 introduced deliberate infrastructure failures.
Injected failures:
- pod deletion
- Redis outages
- PostgreSQL outages
- latency injection
- retry storms
- webhook failures
This validated:
- autoscaling
- retries
- recovery behavior
- queue durability
- graceful degradation
The final phase implemented:
- readiness probes
- liveness probes
- rolling deployments
- graceful shutdowns
- resource requests
- resource limits
- persistent storage
- autoscaling stability
This transitioned the system from:
works locally
into:
operationally survivable
Ferrum supports two execution environments.
| Mode | Purpose |
|---|---|
| Docker Compose | local development |
| Kubernetes (Minikube) | orchestration simulation |
Install:
- Docker Desktop
- Docker Compose
Verify:
docker --version
docker compose versionCreate .env:
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=postgres
DB_HOST=postgres
DB_PORT=5432
DB_NAME=ferrum_db
DB_USER=ferrum_user
DB_PASSWORD=password
REDIS_HOST=redis
REDIS_PORT=6379
GITHUB_ORG=ferrum-webhooks
GATEWAY_REPO=ferrum-webhook-gateway
WORKER_REPO=ferrum-webhook-worker
IMAGE_TAG=latestdocker compose upOr rebuild:
docker compose up --builddocker psExpected:
- gateway
- worker
- postgres
- redis
- prometheus
| Service | URL |
|---|---|
| Gateway | http://localhost:8000 |
| Prometheus | http://localhost:9090 |
| PostgreSQL | localhost:5432 |
| Redis | localhost:6379 |
Gateway metrics:
http://localhost:8000/metrics
Worker metrics:
http://localhost:8001/metrics
Install:
- Docker Desktop
- kubectl
- Minikube
Verify:
kubectl version --client
minikube versionminikube startVerify:
kubectl get nodesExpected:
STATUS = Ready
Ferrum runs in an isolated namespace.
kubectl apply -f k8s/namespace/namespace.yamlVerify:
kubectl get namespacesExpected:
ferrum
Environment variables are injected using ConfigMaps.
kubectl apply -f k8s/config/Verify:
kubectl get configmap ferrum-config -n ferrum
kubectl get configmap postgres-init -n ferrum
kubectl get configmap prometheus-config -n ferrumCreate Postgres secret:
kubectl apply -f k8s/secret/postgres-secret.yamlRequired for pulling private images from GitHub Container Registry.
kubectl create secret docker-registry ghcr-secret \
--docker-server=ghcr.io \
--docker-username=<github-username> \
--docker-password=<github-token> \
-n ferrumVerify:
kubectl get secrets -n ferrumkubectl apply -f k8s/pvc/postgres-pvc.yamlVerify:
kubectl get pvc -n ferrumexport $(cat .env | xargs)
kubectl apply -f k8s/services/postgres.yaml
kubectl apply -f k8s/services/redis.yaml
kubectl apply -f k8s/services/prometheus.yaml
kubectl apply -f k8s/services/grafana.yaml
envsubst < k8s/services/gateway.yaml | kubectl apply -f -
envsubst < k8s/services/worker.yaml | kubectl apply -f -
kubectl apply -f k8s/hpa/gateway-hpa.yaml
kubectl apply -f k8s/hpa/worker-hpa.yamlThis creates: This creates:
- deployments
- services
- pods
- autoscalers
- networking
- persistent storage
Create a load test configmap:
kubectl create configmap k6-test \
--from-file=tests/load-test.js \
-n ferrumRun it:
kubectl run k6 \
--rm -i --tty \
--image=grafana/k6 \
--restart=Never \
-n ferrum \
--overrides='
{
"spec": {
"containers": [
{
"name": "k6",
"image": "grafana/k6",
"command": ["k6", "run", "/scripts/load-test.js"],
"volumeMounts": [
{
"name": "scripts",
"mountPath": "/scripts"
}
]
}
],
"volumes": [
{
"name": "scripts",
"configMap": {
"name": "k6-test"
}
}
]
}
}'Expected result would look something like:
█ TOTAL RESULTS
HTTP
http_req_duration..............: avg=368.2ms min=39.5ms med=318.97ms max=2.21s p(90)=603.9ms p(95)=704.65ms
{ expected_response:true }...: avg=368.2ms min=39.5ms med=318.97ms max=2.21s p(90)=603.9ms p(95)=704.65ms
http_req_failed................: 0.00% 0 out of 8179
http_reqs......................: 8179 135.360515/s
EXECUTION
iteration_duration.............: avg=368.25ms min=39.55ms med=319.04ms max=2.21s p(90)=603.92ms p(95)=704.72ms
iterations.....................: 8179 135.360515/s
vus............................: 50 min=50 max=50
vus_max........................: 50 min=50 max=50
NETWORK
data_received..................: 1.9 MB 31 kB/s
data_sent......................: 1.7 MB 28 kB/skubectl create configmap k6-chaos-script \
--from-file=./tests/k6-chaos.js \
-n ferrumRun it:
run k6-chaos \
--image=grafana/k6 \
--restart=Never \
--namespace ferrum \
--overrides='
{
"spec": {
"containers": [
{
"name": "k6",
"image": "grafana/k6",
"command": ["k6"],
"args": ["run", "/scripts/k6-chaos.js"],
"volumeMounts": [
{
"name": "k6-script",
"mountPath": "/scripts"
}
]
}
],
"volumes": [
{
"name": "k6-script",
"configMap": {
"name": "k6-chaos-script"
}
}
]
}
}'kubectl get pods -n ferrum -w
kubectl get hpa -n ferrum -wGet service info:
kubectl get svc -n ferrumOR, to open directly:
minikube service gateway -n ferrumcurl -X POST http://<url:port>/webhooks \
-H "Content-Type: application/json" \
-d '{
"url":"https://webhook.site/your-id",
"event_type":"test"
}'curl -X POST http://<url:port>/events \
-H "Content-Type: application/json" \
-d '{
"payload":{"hello":"world"},
"event_type":"test"
}'Metrics collected:
| Metric | Purpose |
|---|---|
| gateway_requests_total | throughput |
| gateway_request_latency_seconds | latency |
| worker_events_processed_total | worker throughput |
| worker_queue_delay_seconds | queue backlog |
| worker_delivery_latency_seconds | outbound webhook latency |
| worker_delivery_failures_total | failure rate |
| end_to_end_latency_seconds | complete pipeline latency |
Dashboards visualize:
- request throughput
- p95 latency
- queue delays
- worker throughput
- delivery failures
- CPU usage
- memory usage
- autoscaling events
| Parameter | Value |
|---|---|
| Virtual Users | 50 |
| Requests Processed | 8,179 |
| Throughput | 135 req/s |
| Failure Rate | 0% |
| Metric | Value |
|---|---|
| Average Latency | 368ms |
| Median Latency | 318ms |
| p90 Latency | 603ms |
| p95 Latency | 704ms |
| Max Latency | 2.21s |
Gateway scaled dynamically:
1 pod → 5 pods
Worker scaled dynamically:
1 pod → 2 pods
Kubernetes automatically:
- created new replicas
- distributed load
- terminated excess pods after cooldown
This validated:
- HPA configuration
- CPU-based scaling
- replica reconciliation
- rolling pod scheduling
Phase 9 intentionally destabilized the infrastructure.
Purpose:
- validate resilience
- measure recovery behavior
- observe cascading failures
- test retry mechanisms
kubectl delete pod <gateway-pod> -n ferrumKubernetes automatically:
- detected replica loss
- scheduled replacement pod
- recreated container
- restored service availability
Observed behavior:
| Metric | Result |
|---|---|
| Recovery Time | ~10–20 seconds |
| Manual Intervention | none |
| Data Loss | none |
kubectl delete pod redis-xxxxx -n ferrumDuring outage:
- gateway enqueue operations failed
- worker BRPOP operations blocked
- retries accumulated
After Redis recovery:
- queue resumed automatically
- workers continued processing
- no cluster corruption occurred
kubectl delete pod postgres-xxxxx -n ferrumDuring outage:
- gateway DB writes failed
- worker delivery persistence failed
- requests returned errors
After recovery:
- PVC preserved data
- database restarted intact
- services resumed normally
This validated persistent volume correctness.
Worker delivery path intentionally delayed.
Observed:
- queue delay growth
- increased p95 latency
- HPA scaling events
- backlog accumulation
Metrics confirmed:
Higher queue delay → higher worker scaling
This validated:
- autoscaling sensitivity
- queue observability
- resilience under degraded performance
Webhook endpoints intentionally returned:
HTTP 500
Worker:
- retried failed deliveries
- applied exponential backoff
- prevented immediate retry storms
- eventually routed failed events into DLQ
Metrics observed:
- increased failure counters
- increased retry counters
- growing DLQ size
Phase 10 stabilized the infrastructure.
Added:
readinessProbe:
httpGet:
path: /
port: 8000Effect:
- pods only received traffic after startup completion
- prevented connection-refused windows
Added:
livenessProbe:
httpGet:
path: /
port: 8000Effect:
- Kubernetes restarted unhealthy containers automatically
- improved long-running stability
Added:
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"Effect:
- enabled proper HPA calculations
- prevented uncontrolled resource consumption
- improved scheduling stability
Validated:
kubectl rollout restart deployment gateway -n ferrumObserved:
- zero downtime restarts
- staggered pod replacement
- uninterrupted traffic handling
Observed during scaling:
- old pods entered Terminating state
- active requests completed
- replacements became ready before deletion
This validated production-safe deployment behavior.
Examples encountered:
- image pull failures
- secret mismatches
- DB authentication failures
- PVC misconfiguration
- startup race conditions
- autoscaling instability
Without metrics:
- queue delays were invisible
- retries were invisible
- scaling behavior was invisible
- latency regressions were invisible
Prometheus and Grafana transformed debugging from guessing into measurement.
Kubernetes continuously attempts to restore desired state.
Observed repeatedly during:
- pod deletion
- autoscaling
- rolling updates
- crash recovery
The system became resilient because:
- multiple replicas existed
- queues decoupled services
- retries handled transient failures
- probes detected unhealthy pods
- PVCs preserved persistent state
Reliability came from layering:
- metrics
- retries
- probes
- autoscaling
- persistence
- observability
- deployment strategies
No single feature made the system production-ready.
✅ Dockerized services
✅ Kubernetes orchestration
✅ Namespace isolation
✅ Persistent storage
✅ Autoscaling
✅ Rolling deployments
✅ Health probes
✅ Redis queueing
✅ Retry infrastructure
✅ Dead letter queues
✅ Prometheus monitoring
✅ Grafana dashboards
✅ Structured logging
✅ Failure recovery
✅ CI/CD integration
✅ GHCR deployments
| Capability | Result |
|---|---|
| Throughput Tested | 135 req/s |
| Requests Processed | 8,179 |
| HTTP Failure Rate | 0% |
| Gateway Autoscaling | 1 → 5 pods |
| Worker Autoscaling | 1 → 2 pods |
| p95 Latency | ~704ms |
| Recovery From Pod Failure | automatic |
| Recovery From Redis Failure | automatic |
| Recovery From PostgreSQL Failure | successful with PVC |
| Zero Downtime Rolling Deployments | validated |
Single-process backend app
Observable distributed cloud-native platform
The project evolved from:
- backend development
into:
- platform engineering
- DevOps
- distributed systems engineering
- resilience engineering
- cloud-native infrastructure
- production operations
| Phase | Focus |
|---|---|
| Phase 1 | Core FastAPI gateway |
| Phase 2 | PostgreSQL integration |
| Phase 3 | Async worker architecture |
| Phase 4 | Dockerization |
| Phase 5 | Observability + metrics |
| Phase 6 | CI/CD + GHCR |
| Phase 7 | Kubernetes orchestration |
| Phase 8 | Autoscaling + load testing |
| Phase 9 | Failure injection + resilience |
| Phase 10 | Production readiness |
Ferrum Infrastructure evolved from:
containers running locally
into:
a resilient distributed infrastructure platform
By the end of the project, the system demonstrated:
- orchestration
- observability
- autoscaling
- failure recovery
- deployment automation
- production-safe operations
- measurable resilience
- cloud-native architecture patterns
This repository now represents a full-stack infrastructure engineering project rather than simple local container orchestration.