-
Notifications
You must be signed in to change notification settings - Fork 35
Module 4.md
By the end of this module, you'll have:
- ✅ High-performance API Gateway written in Go (~17MB vs ~900MB Python)
- ✅ Production-ready reverse proxy with request forwarding
- ✅ Complete observability stack (structured logging + Prometheus metrics)
- ✅ Request ID tracking for distributed tracing
- ✅ Graceful shutdown handling for zero-downtime deployments
- ✅ Backend health monitoring and automatic failover
- ✅ Polyglot microservices architecture (Go + Python)
Real-World Impact:
- 67% reduction in memory usage vs Python-only architecture
- Sub-millisecond request routing overhead
- 10x faster startup times for rapid scaling
- Professional-grade observability for production monitoring
- Separation of concerns: Go for I/O, Python for ML
By the end of this module, you will:
- ✅ Build a production-ready API Gateway in Go
- ✅ Understand polyglot architecture (Go + Python)
- ✅ Implement structured logging and metrics
- ✅ Deploy Go services to Kubernetes
- ✅ Monitor multi-language microservices
| Aspect | Go Gateway | Python Alternative |
|---|---|---|
| Image Size | ~17MB | ~900MB |
| Memory Usage | ~64MB | ~200MB |
| Startup Time | ~1 second | ~5-10 seconds |
| CPU Efficiency | High (compiled) | Lower (interpreted) |
| Best For | Routing, I/O | ML, Data Science |
Key Insight: Use the right tool for each job!
- Go: Lightweight gateway/API layer
- Python: ML inference where libraries matter
- Completed Module 3 (Kubernetes deployment)
- Go 1.21+ installed
- Docker and kind running
- kubectl configured
# macOS
brew install go
# Verify
go versionGoal: Build a complete API Gateway in Go with all essential features.
cd modules/module-4/starter
# Open the file
gateway.go
# Find and fill in 20 TODOs
# Look for: // YOUR CODE HERE
# Download dependencies
go mod download
# Build and test locally (ensure ML service is running)
export BACKEND_URL=http://localhost:3000
go run gateway.go
# In another terminal, test it
curl http://localhost:8080/health
curl http://localhost:8080/metrics # Prometheus metrics
curl -X POST http://localhost:8080/predict \
-H "Content-Type: application/json" \
-d '{"text":"Go is fast!"}'
# Validate your work
./tests/test_gateway.shKey TODOs (20 total):
Configuration & Metrics (3 TODOs):
- Complete configuration loading
- HTTP request counter metric
- HTTP request duration metric
Middleware (3 TODOs): 4. Request ID middleware 5. Logging middleware completion 6. Metrics recording
Handlers (4 TODOs): 7. Create handler and register routes 8. Validate HTTP method in health handler 9. Backend health check request 10. Backend health status in response
Proxy Logic (6 TODOs): 11. Read request body 12. Create backend request 13. Copy headers to backend 14. Send backend request with metrics 15. Copy response headers 16. Copy status code and body
Server Setup (4 TODOs): 17. Setup structured logging 18. Create HTTP server 19. Start server in goroutine 20. Graceful shutdown
# Return to module-4 root
cd ..
# Build Docker image
docker build -t api-gateway:v1 .
# Load into kind
kind load docker-image api-gateway:v1 --name mlops-workshop# Ensure ML service is running
kubectl get svc sentiment-api-service
# Deploy gateway
kubectl apply -f deployment.yaml
# Check deployment
kubectl get all -l app=api-gateway
# Port-forward to test
kubectl port-forward svc/api-gateway-service 8080:80
# Test
curl http://localhost:8080/health
curl -X POST http://localhost:8080/predict \
-H "Content-Type: application/json" \
-d '{"text":"Kubernetes + Go!"}'cd starter
./tests/test_gateway.sh
# If all pass:
🎉 ALL TESTS PASSED!- HTTP Server: Creating and configuring http.Server
- Handlers: Request handling functions
- Routing: ServeMux for URL pattern matching
- Context: Request-scoped values
- Request Forwarding: Proxying requests to backend
- Header Propagation: Copying headers between requests
- Timeout Handling: Setting client and server timeouts
- Error Handling: Graceful error responses
- Structured Logging: JSON logs with log/slog
- Metrics: Prometheus instrumentation
- Request Tracking: Correlation IDs (X-Request-ID)
- Middleware: Composable request processing
- Graceful Shutdown: Clean termination on SIGTERM
- Logging: Structured JSON logs for parsing
- Metrics: HTTP request counters and duration histograms
- Tracing: Request ID propagation
- Health Checks: Backend availability monitoring
Without Gateway (Python only):
Python Service (10 replicas × 1Gi = 10Gi memory)
Cost: High
With Gateway (Go + Python):
Go Gateway (5 replicas × 64Mi = 320Mi)
↓
Python ML Service (3 replicas × 1Gi = 3Gi)
Total: 3.3Gi vs 10Gi = 67% reduction!
| Layer | Language | Responsibility | Scales Based On |
|---|---|---|---|
| Gateway | Go | Routing, auth | Request count |
| ML Service | Python | Inference | CPU usage |
# Local development
go mod download # Download dependencies
go run gateway.go # Run locally
go build -o gateway gateway.go # Build binary
# Docker
docker build -t api-gateway:v1 .
kind load docker-image api-gateway:v1 --name mlops-workshop
# Kubernetes
kubectl apply -f deployment.yaml
kubectl get pods -l app=api-gateway
kubectl logs -l app=api-gateway -f
kubectl port-forward svc/api-gateway-service 8080:80Symptoms:
go build gateway.go
# Error: package prometheus is not in GOROOT
Root Cause: Dependencies not downloaded
Solutions:
Step 1: Download dependencies
# Ensure you're in the starter directory
cd modules/module-4/starter
# Download all dependencies
go mod download
# Verify modules
go mod verify
# Tidy up (remove unused)
go mod tidyStep 2: Check Go version
go version
# Should be >= 1.21
# If too old, upgrade Go
brew upgrade go Step 3: Clear cache if corrupted
# Clean mod cache
go clean -modcache
# Re-download
go mod downloadSymptoms:
gateway.go:45:2: syntax error: unexpected }
Root Cause: Incomplete TODO or syntax mistake
Solutions:
Check compilation:
# Build to see all errors
go build gateway.go
# Run with verbose errors
go build -v gateway.goUse go fmt:
# Auto-format code (helps catch syntax issues)
go fmt gateway.go
# Check for common mistakes
go vet gateway.goSymptoms:
Error: dial tcp: lookup sentiment-api-service: no such host
Root Causes:
- Backend service not running
- Wrong service name or namespace
- DNS resolution issues
Solutions:
Check 1: Verify backend is running
# Check if service exists
kubectl get svc sentiment-api-service
# Check if pods are ready
kubectl get pods -l app=sentiment-api
# If not running, deploy it first (Module 3)
cd ../module-3
kubectl apply -f deployment.yamlCheck 2: Test backend connectivity
# Port-forward backend
kubectl port-forward svc/sentiment-api-service 3000:80
# Test in another terminal
curl http://localhost:3000/healthCheck 3: Verify service name in gateway
# Check BACKEND_URL environment variable
kubectl get deployment api-gateway -o yaml | grep BACKEND_URL
# Should be: http://sentiment-api-service:80Check 4: Check gateway logs
# View logs
kubectl logs -l app=api-gateway --tail=50
# Look for connection errors
kubectl logs -l app=api-gateway | grep -i "error\|fail"Symptoms:
curl http://localhost:8080/predict
# HTTP 502 Bad Gateway
Root Cause: Backend service is down or returning errors
Solutions:
Step 1: Check backend health
# Direct backend test
kubectl port-forward svc/sentiment-api-service 3000:80
curl http://localhost:3000/healthStep 2: Check gateway logs
# View detailed logs
kubectl logs -l app=api-gateway -f
# Look for proxy errors
kubectl logs -l app=api-gateway | grep proxyStep 3: Verify backend response
# Exec into gateway pod
kubectl exec -it <gateway-pod> -- sh
# Test from inside pod
wget -qO- http://sentiment-api-service:80/healthStill stuck? Check the solution file
# Navigate to module
cd modules/module-4/starter
# Download dependencies
go mod download
# Run locally (ensure backend is running)
export BACKEND_URL=http://localhost:3000
go run gateway.go
# In another terminal, test
curl http://localhost:8080/health# Build Docker image
docker build -t api-gateway:v1 .
# Build with specific tag
docker build -t api-gateway:v1.0.0 .
# Run locally
docker run -p 8080:8080 \
-e BACKEND_URL=http://host.docker.internal:3000 \
api-gateway:v1
# Check image size
docker images api-gateway:v1
# Inspect layers
docker history api-gateway:v1
# Load into kind
kind load docker-image api-gateway:v1 --name mlops-workshop# Apply deployment
kubectl apply -f deployment.yaml
# Get all resources
kubectl get all -l app=api-gateway
# Get pods with details
kubectl get pods -l app=api-gateway -o wide
# Describe deployment
kubectl describe deployment api-gateway
# View logs
kubectl logs -l app=api-gateway
# Follow logs
kubectl logs -l app=api-gateway -f
# View logs from specific container
kubectl logs <pod-name> -c api-gateway
# Exec into pod
kubectl exec -it <pod-name> -- sh
# Port-forward
kubectl port-forward svc/api-gateway-service 8080:80
# Scale manually
kubectl scale deployment api-gateway --replicas=3
# Restart deployment
kubectl rollout restart deployment api-gateway
# Check rollout status
kubectl rollout status deployment api-gateway
# View rollout history
kubectl rollout history deployment api-gateway# Check if gateway is running
ps aux | grep gateway
# Check port usage
lsof -i :8080 # macOS
# Test locally
curl http://localhost:8080/health
curl http://localhost:8080/metrics
# Test with verbose output
curl -v http://localhost:8080/health
# Test request ID
curl -H "X-Request-ID: test-123" http://localhost:8080/health
# Check Go environment
go env
# Check dependencies
go list -m all
# Why is package included?
go mod why github.com/prometheus/client_golang
# Dependency graph
go mod graph | grep prometheus# View Prometheus metrics
curl http://localhost:8080/metrics
# Filter specific metrics
curl http://localhost:8080/metrics | grep http_requests_total
# Parse metrics
curl -s http://localhost:8080/metrics | \
grep http_requests_total | \
grep method
# Watch metrics change
watch -n 1 'curl -s http://localhost:8080/metrics | grep http_requests_total'# Install hey
go install github.com/rakyll/hey@latest
# Basic load test
hey -n 1000 -c 10 http://localhost:8080/health
# POST requests
hey -n 1000 -c 10 -m POST \
-H "Content-Type: application/json" \
-d '{"text":"load test"}' \
http://localhost:8080/predict
# With custom duration
hey -z 30s -c 20 http://localhost:8080/health
# Save results
hey -n 1000 -c 10 http://localhost:8080/health > results.txt
# Using Apache Bench
ab -n 1000 -c 10 http://localhost:8080/health# Stop running gateway
pkill gateway
# Delete Kubernetes resources
kubectl delete -f deployment.yaml
# Delete by label
kubectl delete all -l app=api-gateway
# Remove Docker image
docker rmi api-gateway:v1
# Clean Go cache
go clean -cache
go clean -modcache
# Remove built binaries
rm gateway gateway-linuxIf you get stuck, a complete reference implementation is available in solution/:
-
gateway_solution.go- All TODOs completed with detailed comments
Note: Try to complete the exercise on your own first!
Once you've completed the exercise and tests pass:
→ Module 5: Kubeflow Pipelines
In Module 5, you'll build ML pipelines for training automation!
- ✅ Go HTTP Server: Building production HTTP services
- ✅ Reverse Proxy: Forwarding requests to backend services
- ✅ Structured Logging: JSON logs for observability
- ✅ Metrics: Prometheus instrumentation
- ✅ Middleware: Composable request processing
- ✅ Graceful Shutdown: Clean termination
- ✅ Polyglot Architecture: Right tool for each job
- Use Go for I/O-bound, routing, and gateway layers
- Use Python for ML inference and data science
- Always implement structured logging
- Instrument code with Prometheus metrics
- Propagate request IDs for tracing
- Handle graceful shutdown
- Set appropriate timeouts
- Test backend connectivity in health checks
This configuration is suitable for production ML APIs that need:
- High Performance: Low latency, high throughput
- Resource Efficiency: Minimal memory footprint
- Observability: Structured logs and metrics
- Reliability: Health checks and graceful shutdown
- Scalability: Independent scaling of gateway and ML service
Having issues? Check the Troubleshooting section or review the solution file!
| Previous | Home | Next |
|---|---|---|
| ← Module 3: Kubernetes Deployment | 🏠 Home | Module 5: Kubeflow Pipelines & Model Serving → |
MLOps Workshop | GitHub Repository