Production-ready ML inference service with gRPC interface and automated canary deployment strategy using Envoy proxy.
- Overview
- Architecture
- Canary Deployment Strategy
- Prerequisites
- Quick Start
- Deployment
- Testing
- Monitoring
- Rollback
This project implements a machine learning inference service with:
- gRPC API for high-performance predictions
- Multi-version support (v1.0.0 and v2.0.0)
- Canary deployment with gradual traffic shifting
- Envoy proxy for intelligent load balancing
- Health checks for automatic failover
- CI/CD pipeline with GitHub Actions
βββββββββββββββ
β Client β
ββββββββ¬βββββββ
β
β
βββββββββββββββββββββββββββββββββββ
β Envoy Proxy (50051) β
β βββββββββββββββββββββββββββββ β
β β Weighted Load Balancer β β
β β - v1: 90% β 50% β 0% β β
β β - v2: 10% β 50% β 100% β β
β βββββββββββββββββββββββββββββ β
ββββββββββ¬ββββββββββββββββ¬βββββββββ
β β
βββββββββββ βββββββββββ
β v1.0.0 β β v2.0.0 β
β Model β β Model β
βββββββββββ βββββββββββ
Canary deployment is a progressive rollout strategy that reduces risk by gradually shifting traffic from an old version to a new version. Named after the "canary in a coal mine" practice, it allows you to detect issues early with minimal user impact.
We use a three-stage canary rollout:
- v1.0.0: 90% traffic (stable baseline)
- v2.0.0: 10% traffic (canary)
- Duration: Monitor for errors, latency, accuracy
- Decision point: If metrics are good β proceed to Stage 2
- v1.0.0: 50% traffic
- v2.0.0: 50% traffic
- Duration: Collect more data with balanced traffic
- Decision point: If metrics remain stable β proceed to Stage 3
- v1.0.0: 0% traffic (deprecated)
- v2.0.0: 100% traffic (new baseline)
- Result: Complete migration to new version
- v1.0.0: 100% traffic (back to stable)
- v2.0.0: 0% traffic (disabled)
- Trigger: Any critical issues detected
β
Risk Mitigation: Problems affect only a small percentage of users initially
β
Data-Driven: Make decisions based on real production metrics
β
Fast Rollback: Instant revert to previous version if needed
β
Zero Downtime: Both versions run simultaneously
β
A/B Testing: Compare model performance in production
- Docker and Docker Compose
- Python 3.11+
- Git
# Clone the repository
git clone <your-repo-url>
cd ml_grpc_service
# Run setup script
chmod +x setup.sh
./setup.shThis will:
- Install Python dependencies
- Generate gRPC proto files
- Create ML models (v1 and v2)
- Set up project structure
# Build both model versions
chmod +x build_versions.sh
./build_versions.shVerify images:
docker images | grep ml-grpc-serviceExpected output:
ml-grpc-service v2.0.0 ...
ml-grpc-service v1.0.0 ...
# Start Envoy proxy and both gRPC servers
docker compose -f docker-compose.envoy.yaml up -d
# Check services are running
docker psYou should see three containers:
ml-envoy(Envoy proxy)grpc-server-v1(Model v1.0.0)grpc-server-v2(Model v2.0.0)
# Run test client
python -m client.clientExecute canary stages manually:
# Stage 1: 10% traffic to v2
./canary_deploy.sh 10
# Wait and monitor metrics...
# If good, proceed to Stage 2
# Stage 2: 50% traffic to v2
./canary_deploy.sh 50
# Continue monitoring...
# If stable, proceed to Stage 3
# Stage 3: 100% traffic to v2
./canary_deploy.sh 100The GitHub Actions workflow automates the entire process:
# Trigger manually with specific stage
workflow_dispatch:
inputs:
stage: '10' # or '50', '100', 'rollback'Workflow Steps:
- Checkout code
- Build Docker images
- Start services with docker-compose
- Run canary deployment script
- Execute traffic tests
- Verify metrics
Secrets Required:
MODEL_VERSION: Version tag for modelsCLOUD_TOKEN: Authentication token (if deploying to cloud)
# Push to main/master triggers automated deployment
git push origin main
# Or manually trigger with GitHub UI:
# Actions β Deploy Canary ML Service β Run workflow
# Select stage: 10, 50, 100, or rollback# Test canary traffic routing
python test_canary.pyThis script:
- Sends 100 prediction requests
- Counts responses from each version
- Verifies traffic distribution matches weights
- Reports success/failure
Example output:
Testing Canary Deployment...
Sending 100 requests...
v1.0.0: 89 requests (89%)
v2.0.0: 11 requests (11%)
β
Traffic distribution matches expected 90/10 split
# Single prediction test
python -m client.client
# Check which version handled the request (look for version in logs)
docker logs grpc-server-v1
docker logs grpc-server-v2Access real-time metrics:
# Open in browser
http://localhost:9901
# Key endpoints:
# - /stats: All metrics
# - /clusters: Cluster health status
# - /config_dump: Current configuration# View cluster health
curl http://localhost:9901/clusters
# View traffic stats
curl http://localhost:9901/stats | grep cluster.serviceEnvoy automatically performs gRPC health checks:
- Interval: 10 seconds
- Timeout: 5 seconds
- Unhealthy threshold: 2 consecutive failures
- Healthy threshold: 2 consecutive successes
Unhealthy services are automatically removed from rotation.
# Envoy logs
docker logs ml-envoy
# gRPC server logs
docker logs grpc-server-v1
docker logs grpc-server-v2
# Follow logs in real-time
docker logs -f ml-envoyIf issues are detected at any stage:
# Immediately return 100% traffic to v1.0.0
./canary_deploy.sh rollbackTrigger rollback if you observe:
- β Error rate increase (>1% errors)
- β Latency spikes (>500ms p95)
- β Model accuracy degradation
- β Health check failures
- β Resource exhaustion (memory/CPU)
Add to CI/CD pipeline:
# In deploy.yml, add health check after deployment
- name: Health Check
run: |
if ! python health_check.py; then
echo "Health check failed, rolling back..."
./canary_deploy.sh rollback
exit 1
fiEdit envoy.yaml to modify:
- Traffic weights (default: 100/0)
- Health check intervals
- Timeouts
- Load balancing policy
weighted_clusters:
clusters:
- name: service_v1
weight: 90 # Adjust this
- name: service_v2
weight: 10 # Adjust thisUpdate model versions in:
docker-compose.envoy.yaml: Environment variablesbuild_versions.sh: Docker build argsDockerfile: MODEL_FILE argument