https://github.com/atkaridarshan04/docker-stack
A complete containerized DevOps stack with Flask, MySQL, Nginx, and Monitoring Stack
https://github.com/atkaridarshan04/docker-stack
alloy blackbox-exporter docker flask grafana loki mysql nginx prometheus
Last synced: 2 months ago
JSON representation
A complete containerized DevOps stack with Flask, MySQL, Nginx, and Monitoring Stack
- Host: GitHub
- URL: https://github.com/atkaridarshan04/docker-stack
- Owner: atkaridarshan04
- License: mit
- Created: 2025-10-06T21:30:58.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2026-03-21T06:46:19.000Z (3 months ago)
- Last Synced: 2026-03-21T22:42:59.232Z (3 months ago)
- Topics: alloy, blackbox-exporter, docker, flask, grafana, loki, mysql, nginx, prometheus
- Language: HTML
- Homepage:
- Size: 5.24 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Docker Stack
[](https://www.docker.com/)
[](https://github.com/hadolint/hadolint)
[](https://flask.palletsprojects.com/)
[](https://www.mysql.com/)
[](https://nginx.org/)
[](https://prometheus.io/)
[](https://grafana.com/)
[](https://grafana.com/oss/loki/)
[](https://opensource.org/licenses/MIT)
*A production-style containerized application stack with full observability*
## Overview
This project is a fully containerized application stack built with production practices in mind. It runs a Flask web application backed by MySQL, served through NGINX as the sole public entry point. On top of that, a complete observability layer is wired in — Prometheus collects metrics from every service, Loki aggregates all container logs, and Grafana provides 7 pre-built dashboards covering the full stack.
## 🏗️ Architecture Overview

## Dockerfile Linting
Hadolint is used to lint `app/Dockerfile` against Dockerfile best-practice rules. Configuration lives in `.hadolint.yaml` at the project root.
### Run hadolint
**Docker (no install needed):**
```bash
docker run --rm -i hadolint/hadolint < app/Dockerfile
```

**With the project config applied:**
```bash
docker run --rm -i \
-v "$(pwd)/.hadolint.yaml:/.config/hadolint.yaml" \
hadolint/hadolint < app/Dockerfile
```

**If hadolint is installed locally:**
```bash
hadolint --config .hadolint.yaml app/Dockerfile
```
### Ignored rule
`DL3008` — *Pin versions in apt-get install* — is intentionally ignored.
---
## Prerequisites
- Docker 20.10+ and Docker Compose v2
- Secrets files must exist before starting:
```bash
echo -n "root" > secrets/db_root_pw.txt
echo -n "admin" > secrets/db_admin_pw.txt
```
### Start
```bash
./scripts/start.sh
```
All 10 services start in dependency order. MySQL initializes the schema on first boot (`db/init/01_schema.sql`). Flask waits for MySQL to be healthy before starting. NGINX waits for Flask.
### Stop
```bash
./scripts/stop.sh
```
Containers are removed, all named volumes (data) are preserved. To also wipe data:
```bash
docker compose down -v
```
### Rebuild the Flask image
```bash
docker compose build flask-app
docker compose up -d flask-app
```
### View logs
```bash
docker compose logs -f # all services
docker compose logs -f flask-app mysql # specific services
```
### Check service status
```bash
docker compose ps
```
---
## Access
| Interface | URL | Credentials |
|-----------|-----|-------------|
| Application | http://localhost | — |
| Grafana | http://localhost:3000 | `admin` / `admin` |
| Prometheus | http://localhost:9090 | — |
| Alloy UI | http://localhost:12345 | — |
| cAdvisor | http://localhost:8080 | — |
| mysqld-exporter | http://localhost:9104/metrics | — |
| Blackbox Exporter | http://localhost:9115 | — |
---
## Observability
### Metrics
Prometheus scrapes 6 targets every 15 seconds with 15-day retention:
| Job | Source | What it measures |
|-----|--------|-----------------|
| `flask-app` | Flask `/metrics` | Request rate, latency (p50/p95/p99), error rate per endpoint |
| `cadvisor` | cAdvisor | Per-container CPU, memory, network, filesystem |
| `mysqld-exporter` | mysqld-exporter | Query throughput, connections, InnoDB buffer pool, slow queries |
| `blackbox-http` | Blackbox → NGINX | HTTP uptime, status code, response time phases |
| `blackbox-exporter` | Blackbox self | Exporter health |
| `prometheus` | Prometheus self | Scrape health, TSDB stats |
Alloy also collects host-level metrics (CPU, memory, disk, network) via its built-in node exporter and pushes them to Prometheus via remote_write.
### Logs
Alloy tails all container logs via the Docker socket and ships them to Loki with `container` and `service` labels. MySQL slow query log gets special treatment — multiline entries are reassembled and the `query_time` label is extracted for filtering.
### Dashboards
7 pre-provisioned Grafana dashboards, auto-loaded on startup:
| Dashboard | Data Source | What's inside |
|-----------|-------------|---------------|
| **Stack Overview** | Prometheus + Loki | Single-pane-of-glass — all service health, links to every other dashboard |
| **Flask Application** | Prometheus | Request rate, error rate, p50/p95/p99 latency, per-endpoint breakdown |
| **Docker Containers** | Prometheus | Per-container CPU, memory, network — links to logs |
| **MySQL** | Prometheus + Loki | Query throughput by type, connections, InnoDB, slow query log panel |
| **Container Logs** | Loki | Live log viewer, log volume, MySQL slow log, journal errors |
| **Node Exporter Full** | Prometheus | Full host system metrics |
| **Prometheus Blackbox Exporter** | Prometheus | HTTP probe status, response time breakdown by phase |
Dashboards are cross-linked — container metrics panels link directly to Container Logs filtered to that container.
---
## Secrets
Database credentials are managed via Docker Secrets — never plain environment variables.
```
secrets/
├── db_root_pw.txt # MySQL root password
└── db_admin_pw.txt # MySQL app user password (used by Flask + mysqld-exporter)
```
See [secrets/README.md](./secrets/README.md).
---
## Project Structure
```
docker-stack/
├── docker-compose.yml
├── .hadolint.yaml # Hadolint Dockerfile linting config
├── app/ # Flask application
│ ├── Dockerfile
│ ├── app.py
│ ├── requirements.txt
│ └── templates/index.html
├── configs/ # All service configs (mounted read-only)
│ ├── nginx/default.conf
│ ├── prometheus/prometheus.yml
│ ├── loki/loki.yml
│ ├── alloy/config.alloy
│ ├── blackbox/blackbox.yml
│ └── grafana/provisioning/
│ ├── datasources/ # Prometheus + Loki auto-wired
│ └── dashboards/json/ # 7 pre-built dashboards
├── db/init/01_schema.sql # MySQL schema, auto-run on first start
├── secrets/ # Never committed — gitignored
│ ├── db_root_pw.txt
│ └── db_admin_pw.txt
└── scripts/
├── start.sh # docker compose up -d
└── stop.sh # docker compose down (volumes preserved)
```
---
## Screenshots
### Application

### Prometheus Targets

### Alloy
### Grafana