Highly Available Containerized Web App with Centralized Monitoring and Logging
This project is a simple Flask web app with PostgreSQL.
It runs multiple replicas with Docker Compose, uses NGINX as a reverse proxy, and includes monitoring, centralized logging, and CI/CD.
- Python Flask
- PostgreSQL
- Docker Compose
- NGINX
- Prometheus
- Grafana
- Loki
- Promtail
- Node Exporter
- cAdvisor
- GitHub Actions
- Flask API
- PostgreSQL database
- 3 app replicas
- NGINX load balancing and rate limiting
- Prometheus and Grafana for metrics
- Loki and Promtail for logs
- Node Exporter and cAdvisor for host/container metrics
- GitHub Actions CI/CD
- PostgreSQL backup script
cp .env.example .env
docker compose up -d --build- App:
http://127.0.0.1/ - Grafana:
http://127.0.0.1:3000 - Prometheus:
http://127.0.0.1:9090 - Loki health check:
http://127.0.0.1:3100/ready - NGINX exporter:
http://127.0.0.1:9113/metrics
Grafana login:
- user:
admin - password:
admin
curl http://127.0.0.1/health
curl http://127.0.0.1/ready
curl http://127.0.0.1/api/visits
curl http://127.0.0.1/api/messagesYou can also run:
bash scripts/smoke_test.shDefault mode is round robin.
Check:
for i in $(seq 1 6); do
curl -s -D - http://127.0.0.1/ -o /dev/null | grep X-App-Instance
donePowerShell alternative:
1..6 | ForEach-Object { (Invoke-WebRequest http://127.0.0.1/ -UseBasicParsing).Headers["X-App-Instance"] }If you want least connections:
docker compose -f docker-compose.yml -f docker-compose.leastconn.yml up -d --buildAfter that, run the load balancing check again, because Docker Compose recreates containers when switching the mode.
To return to the default round robin mode:
docker compose up -d --buildPrometheus collects metrics from:
app1app2app3nginx-exporternode-exportercadvisor
Grafana dashboards:
Flask App DashboardInfrastructure Overview
Logs are viewed in Grafana Explore through the Loki datasource.
In Explore, switch the datasource from Prometheus to Loki first.
Example Loki query in Grafana Explore:
{compose_service=~".+"}
docker compose --profile loadtest run --rm --no-deps loadtesterbash scripts/backup_postgres.shWorkflow file:
.github/workflows/ci-cd.yml
The pipeline:
- validates the project
- starts the stack
- runs the smoke test
- publishes the app image on push to
main
docker compose downFull cleanup:
docker compose down -v