mayinx/devops-nginx-exam
DevOps/MLOps Nginx API Gateway for a containerized ML sentiment service: FastAPI backends (api-v1 scaled x3 + api-v2 debug) behind Nginx as Reverse Proxy with HTTPS/TLS termination, basic auth, rate limiting, load balancing, header-based A/B routing, and Prometheus/Grafana observability.
🏛️ MLOps Exam Project: Sentiment API Gateway "The Fortress"
Scalable • Secure • Observable deployment with Nginx + Docker Compose
🎭 Tech Stack
🐋 Docker / Compose | 🛡️ Nginx (Gateway, TLS, Auth, LB, Rate Limit, A/B) | 🐍 FastAPI (v1 + v2) | 🔥 Prometheus | 📊 Grafana
🎯 What this project demonstrates (Exam Objectives)
This repository implements the exam requirements:
- Reverse Proxy: Nginx is the single entry point for
/predict. - Load Balancing:
api-v1runs as 3 replicas behind an Nginx upstream. - HTTPS: TLS termination on Nginx with self-signed certs; HTTP redirects to HTTPS.
- Access Control:
/predictprotected by Basic Auth. - Rate Limiting:
/predictlimited to protect the backend. - A/B Testing:
api-v2is used only when headerX-Experiment-Group: debugis present. - Monitoring (Bonus): Nginx metrics → exporter → Prometheus → Grafana.
🏗️ Architecture (Requests + Metrics)
[ CLIENT ]
|
HTTPS :443
|
+---------v----------+
| 🛡️ NGINX GATEWAY |
| TLS / Auth / RL / |
| LB / A/B routing |
+----+----------+----+
| |
| +-------------------+
| |
v v
+-------------------+ +-------------------+
| 🐍 api-v1 (x3) | | 🐍 api-v2 (debug) |
| load-balanced | | header-triggered |
+-------------------+ +-------------------+
Metrics (pull-based; internal status is NOT published to host):
┌────────────────────────┐
│ 🎨 Grafana dashboards │ :3000
│ queries Prometheus API │
└───────────┬────────────┘
│ Prometheus query API (READ)
v
(1) scrape_interval
┌───────────────────────────────────────────┐
│ 🔥 Prometheus │ :9090
│ schedules scrapes + scrapes reporter │
│ + stores time series │
└───────────────┬───────────────────────────┘
│ (2) HTTP GET /metrics (PULL)
v
┌───────────────────────┐
│ 📊 nginx_exporter │ :9113
│ converts Nginx stats │
└───────────┬───────────┘
│ (3) HTTP GET /nginx_status (PULL)
v
┌───────────────────────────┐
│ 🛡️ NGINX :8081 │
│ /nginx_status (stub) │
│ allow: 127.0.0.1 + RFC1918│
└───────────────────────────┘
📁 Project Structure (high level)
.
├── deployments/
│ ├── nginx/
│ │ ├── Dockerfile
│ │ ├── nginx.conf
│ │ ├── .htpasswd
│ │ └── certs/ (generated locally)
│ └── prometheus/
│ └── prometheus.yml
├── model/
│ └── model.joblib
├── src/
│ └── api/
│ ├── requirements.txt
│ ├── v1/ (FastAPI app + Dockerfile)
│ └── v2/ (FastAPI app + Dockerfile)
├── tests/
│ └── run_tests.sh
├── docker-compose.yml
├── Makefile🚀 Quick Start
1) Generate TLS certificates (self-signed)
make gen-certs2) Start the full stack (includes api-v1 scaled to 3)
make start-project
make links3) Run the exam validation - expected all green of course ;-)
make test4) Stop everything
make stop-project🔐 API Usage
✅ Default call (routes to v1)
curl -s -X POST "https://localhost/predict" \
--cacert ./deployments/nginx/certs/nginx.crt \
--user admin:admin \
-H "Content-Type: application/json" \
-d '{"sentence": "Oh yeah, that was soooo cool!"}'🧪 A/B debug route (forces v2)
curl -s -X POST "https://localhost/predict" \
--cacert ./deployments/nginx/certs/nginx.crt \
--user admin:admin \
-H "X-Experiment-Group: debug" \
-H "Content-Type: application/json" \
-d '{"sentence": "Oh yeah, that was soooo cool!"}'🚦 Rate limiting behavior (expected)
A burst of requests should produce a mix of 200 and 503 once the limit is exceeded.
The automated test suite (make test) includes a burst step and checks that the service remains available.
📊 Monitoring (Bonus)
- Exporter: http://localhost:9113/metrics
- Prometheus: http://localhost:9090
- Grafana: http://localhost:3000 (admin / admin)
In Prometheus, check /targets → exporter should be UP.
✅ Make targets (most useful)
make start-project— build + start full stack (api-v1 scaled to 3)make stop-project— stop stackmake test— runtests/run_tests.sh(grader entry point)make logs— follow logsmake links— print local URLs
⚖️ Notes on portability (why the Nginx allowlist is broad in /nginx_status (see nginx.config)
The internal-only metrics endpoint (listen 8081 → /nginx_status) is not published to the host. It is meant to be reachable only inside the Docker network (for the exporter), not from the public/host side.
To keep this portable across different Docker/Compose subnets, the allowlist uses RFC1918 private ranges (commonly used by Docker bridge networks) plus loopback:
- 127.0.0.1 (inside-container calls)
- 172.16.0.0/12 and 192.168.0.0/16 (RFC1918 private ranges)
RFC1918 explicitly defines the private blocks, including 172.16/12, and 192.168/16:
https://www.rfc-editor.org/rfc/rfc1918.txt
APPENDIX: Original Exam Brief:
Instructions pour l'Examen / Exam Instructions
🇫🇷 Version Française
Examen MLOps : Déploiement Avancé avec Nginx 🚀
Contexte
Pour cet examen, vous allez mettre en œuvre une architecture MLOps robuste et sécurisée. Le cœur du projet est d'utiliser Nginx comme une API Gateway pour servir un modèle de Machine Learning via une API FastAPI. Vous devrez non seulement rendre le service fonctionnel, mais aussi implémenter des fonctionnalités avancées essentielles en production : scalabilité, sécurité, et stratégies de déploiement modernes.
Objectifs du Projet
Votre mission est de configurer une architecture conteneurisée complète qui remplit les objectifs suivants :
-
Proxy Inverse (Reverse Proxy) : Nginx doit agir comme le seul point d'entrée et router le trafic vers les services API appropriés.
-
Équilibrage de Charge (Load Balancing) : L'API principale (
api-v1) doit être déployée en plusieurs instances (3 répliques) pour garantir la haute disponibilité et la répartition de la charge. -
Sécurité HTTPS : Toutes les communications externes doivent être chiffrées via HTTPS. Vous générerez des certificats auto-signés pour cela. Le trafic HTTP simple devra être automatiquement redirigé vers HTTPS.
-
Contrôle d'Accès : L'accès au point de terminaison de prédiction (
/predict) doit être protégé par une authentification basique (nom d'utilisateur / mot de passe). -
Limitation de Débit (Rate Limiting) : Pour protéger l'API contre les surcharges, l'endpoint
/predictdoit limiter le nombre de requêtes (ex: 10 requêtes/seconde par IP). -
A/B Testing : Vous déploierez deux versions de l'API.
api-v1: La version standard.api-v2: Une version "debug" qui retourne des informations supplémentaires.- Nginx devra router le trafic vers
api-v2uniquement si la requête contient l'en-tête HTTPX-Experiment-Group: debug. Sinon, le trafic doit aller versapi-v1.
-
Monitoring (Bonus) : Mettre en place une stack de monitoring avec Prometheus et Grafana pour collecter et visualiser les métriques de Nginx.
Architecture Cible
Le schéma suivant illustre l'architecture complète que vous devez construire. Nginx sert de passerelle centrale, gérant le trafic vers les différentes versions de l'API et exposant les métriques pour le monitoring.
graph TD
subgraph "Utilisateur"
U[Client] -->|Requête HTTPS| N
end
subgraph "Infrastructure Conteneurisée (Docker)"
N[Nginx Gateway] -->|Load Balancing| V1
N -->|"A/B Test (Header)"| V2
subgraph "API v1 (Scalée)"
V1[Upstream: api-v1]
V1_1[Replica 1]
V1_2[Replica 2]
V1_3[Replica 3]
V1 --- V1_1
V1 --- V1_2
V1 --- V1_3
end
subgraph "API v2 (Debug)"
V2[Upstream: api-v2]
end
subgraph "Stack de Monitoring"
N -->|/nginx_status| NE[Nginx Exporter]
NE -->|Métriques| P[Prometheus]
P -->|Source de données| G[Grafana]
U_Grafana[Admin] -->|Consulte Dashboards| G
end
end
style N fill:#269539,stroke:#333,stroke-width:2px,color:#fff
style G fill:#F46800,stroke:#333,stroke-width:2px,color:#fff
style P fill:#E6522C,stroke:#333,stroke-width:2px,color:#fff
Structure Cible du Projet
Voici l'arborescence de fichiers que vous devez obtenir à la fin :
.
├── Makefile
├── README.md
├── README_student.md
├── data
│ └── tweet_emotions.csv
├── deployments
│ ├── nginx
│ │ ├── Dockerfile
│ │ ├── certs
│ │ │ ├── nginx.crt
│ │ │ └── nginx.key
│ │ └── nginx.conf
│ └── prometheus
│ └── prometheus.yml
├── docker-compose.yml
├── model
│ └── model.joblib
├── src
│ ├── api
│ │ ├── requirements.txt
│ │ ├── v1
│ │ │ ├── Dockerfile
│ │ │ └── main.py
│ │ └── v2
│ │ ├── Dockerfile
│ │ └── main.py
│ └── gen_model.py
└── tests
└── run_tests.shLivrables
Vous devez soumettre une archive .zip ou .tar.gz contenant l'intégralité de votre projet, incluant :
- Tous les
Dockerfilesnécessaires pour construire les images de vos services. - Le fichier
docker-compose.ymlorchestrant tous les services (Nginx, api-v1, api-v2, monitoring). - Le fichier
nginx.confcomplet avec toutes les directives requises. - Les fichiers de configuration et de sécurité (
.htpasswd, certificats SSL,prometheus.yml). - Le code source des deux versions de l'API.
- Un
Makefileavec des commandes claires pourstart-project,stop-project, ettest. - Un script de test (
tests/run_tests.sh) qui valide automatiquement les fonctionnalités clés.
Critères d'Évaluation
Important : La validation finale de votre projet se fera en exécutant la commande make test. Celle-ci doit s'exécuter sans erreur et tous les tests doivent passer avec succès.
- Fonctionnalité : Toutes les fonctionnalités (de 1 à 6) sont implémentées et fonctionnent correctement.
- Qualité du Code : Les fichiers de configuration (
nginx.conf,docker-compose.yml) sont clairs, commentés si nécessaire, et bien structurés. - Reproductibilité : Le projet peut être lancé sans erreur avec
make start-project. - Automatisation : Le
Makefileet le script de test sont efficaces et permettent de valider le projet facilement. - Clarté de la Documentation : Le
README.mdprincipal explique clairement l'architecture et l'utilisation du projet.
Bon courage ! 🚀
🇬🇧 English Version
MLOps Exam: Advanced Deployment with Nginx 🚀
Context
For this exam, you will implement a robust and secure MLOps architecture. The core of the project is to use Nginx as an API Gateway to serve a Machine Learning model via a FastAPI API. You will not only make the service functional but also implement advanced features essential for production: scalability, security, and modern deployment strategies.
Project Objectives
Your mission is to set up a complete containerized architecture that meets the following objectives:
-
Reverse Proxy: Nginx must act as the single point of entry and route traffic to the appropriate API services.
-
Load Balancing: The main API (
api-v1) must be deployed in multiple instances (3 replicas) to ensure high availability and load distribution. -
HTTPS Security: All external communications must be encrypted via HTTPS. You will generate self-signed certificates for this purpose. Plain HTTP traffic must be automatically redirected to HTTPS.
-
Access Control: Access to the prediction endpoint (
/predict) must be protected by basic authentication (username/password). -
Rate Limiting: To protect the API from overload, the
/predictendpoint must limit the number of requests (e.g., 10 requests/second per IP). -
A/B Testing: You will deploy two versions of the API.
api-v1: The standard version.api-v2: A "debug" version that returns additional information.- Nginx must route traffic to
api-v2only if the request contains theX-Experiment-Group: debugHTTP header. Otherwise, traffic should be routed toapi-v1.
-
Monitoring (Bonus): Set up a monitoring stack with Prometheus and Grafana to collect and visualize Nginx metrics.
Target Architecture
The following diagram illustrates the complete architecture you need to build. Nginx acts as a central gateway, managing traffic to the different API versions and exposing metrics for monitoring.
graph TD
subgraph "User"
U[Client] -->|HTTPS Request| N
end
subgraph "Containerized Infrastructure (Docker)"
N[Nginx Gateway] -->|Load Balancing| V1
N -->|"A/B Test (Header)"| V2
subgraph "API v1 (Scaled)"
V1[Upstream: api-v1]
V1_1[Replica 1]
V1_2[Replica 2]
V1_3[Replica 3]
V1 --- V1_1
V1 --- V1_2
V1 --- V1_3
end
subgraph "API v2 (Debug)"
V2[Upstream: api-v2]
end
subgraph "Monitoring Stack"
N -->|/nginx_status| NE[Nginx Exporter]
NE -->|Metrics| P[Prometheus]
P -->|Data Source| G[Grafana]
U_Grafana[Admin] -->|View Dashboards| G
end
end
style N fill:#269539,stroke:#333,stroke-width:2px,color:#fff
style G fill:#F46800,stroke:#333,stroke-width:2px,color:#fff
style P fill:#E6522C,stroke:#333,stroke-width:2px,color:#fff
Target Project Structure
Here is the file tree you should aim to have at the end:
.
├── Makefile
├── README.md
├── README_student.md
├── data
│ └── tweet_emotions.csv
├── deployments
│ ├── nginx
│ │ ├── Dockerfile
│ │ ├── certs
│ │ │ ├── nginx.crt
│ │ │ └── nginx.key
│ │ └── nginx.conf
│ └── prometheus
│ └── prometheus.yml
├── docker-compose.yml
├── model
│ └── model.joblib
├── src
│ ├── api
│ │ ├── requirements.txt
│ │ ├── v1
│ │ │ ├── Dockerfile
│ │ │ └── main.py
│ │ └── v2
│ │ ├── Dockerfile
│ │ └── main.py
│ └── gen_model.py
└── tests
└── run_tests.shDeliverables
You must submit a .zip or .tar.gz archive containing your entire project, including:
- All necessary
Dockerfilesto build the images for your services. - The
docker-compose.ymlfile orchestrating all services (Nginx, api-v1, api-v2, monitoring). - The complete
nginx.conffile with all required directives. - Configuration and security files (
.htpasswd, SSL certificates,prometheus.yml). - The source code for both API versions.
- A
Makefilewith clear commands forstart-project,stop-project, andtest. - A test script (
tests/run_tests.sh) that automatically validates the key features.
Evaluation Criteria
Important: The final validation of your project will be done by running the make test command. It must run without errors, and all tests must pass successfully.
- Functionality: All features (1 through 6) are implemented and work correctly.
- Code Quality: Configuration files (
nginx.conf,docker-compose.yml) are clear, commented where necessary, and well-structured. - Reproducibility: The project can be launched without errors using
make start-project. - Automation: The
Makefileand test script are effective and allow for easy project validation. - Documentation Clarity: The main
README.mdclearly explains the project's architecture and usage.
Good luck! 🚀