The pipeline runs as a multi-container stack. This document explains the image build, service composition, and how to extend it.
The single application image hosts all batch jobs. It's based on python:3.13-slim (matches pyproject.toml requires-python = ">=3.13") and is built in three stages:
flowchart TD
classDef stage fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
classDef file fill:#fff8e1,stroke:#f9a825,color:#5d4037
classDef final fill:#e8f5e9,stroke:#2e7d32,color:#1b5e20
A["python:3.13-slim"]:::stage
B["+ uv, Java JRE, psql, mongosh, curl"]:::stage
C["+ pyproject.toml → uv sync"]:::stage
D["+ project source<br/>(src/, scripts/, utils/, tests/)"]:::file
E["+ jars/postgresql.jar"]:::file
F["+ docker/entrypoint.sh"]:::file
G["CMD [entrypoint.sh]"]:::final
A --> B --> C --> D
A --> B --> C --> E
A --> B --> C --> F
D --> G
E --> G
F --> G
- Java JRE — PySpark requires a JVM
- psql — used by backup/restore and
monitor_logs.shhealth probes - mongosh — used by
docker_dev.shandmonitor_logs.shMongoDB checks - curl — Prometheus / Pushgateway health probes
make build # via Makefile
docker compose build app # direct
docker build -t bike-store-app docker/ # rawSix services on one monitoring network. Profiles separate long-running infrastructure from on-demand batch jobs.
flowchart LR
classDef db fill:#3367d6,stroke:#1a53b3,color:#ffffff
classDef monitor fill:#0f9d58,stroke:#0b8043,color:#ffffff
classDef viz fill:#f4b400,stroke:#d09200,color:#000000
classDef job fill:#ff6f00,stroke:#c43e00,color:#ffffff
PG[("postgres:16-alpine<br/>bike_store database")]:::db
MGO[("mongo:7<br/>source data")]:::db
PGW["pushgateway<br/>(prom/pushgateway)"]:::monitor
PROM["prometheus<br/>(prom/prometheus)"]:::monitor
GRAF["grafana<br/>auto-provisioned dashboards"]:::viz
APP["app<br/>(batch jobs, jobs profile)"]:::job
APP -->|"JDBC writes"| PG
APP -->|"pymongo reads"| MGO
APP -->|"HTTP push metrics"| PGW
PGW -->|"scrape every 15s"| PROM
PROM -->|"PromQL queries"| GRAF
| Service | Image | Port | Healthcheck |
|---|---|---|---|
postgres |
postgres:16-alpine |
5432 | pg_isready |
mongodb |
mongo:7 |
27017 | mongosh ping |
pushgateway |
prom/pushgateway |
9091 | HTTP /-/healthy |
prometheus |
prom/prometheus |
9090 | HTTP /-/healthy |
grafana |
grafana/grafana |
3000 | HTTP /api/health |
app |
local (docker/Dockerfile) |
— | jobs profile (on-demand) |
Only app uses profiles. app is in the jobs profile, so it does not start with make up — it's launched on demand with make pipeline, make etl, etc.
services:
app:
profiles: ["jobs"]
command: ["entrypoint.sh"] # dispatches to the requested job| Service | URL | Default credentials |
|---|---|---|
| Grafana | http://localhost:3000 | admin / ${GRAFANA_ADMIN_PASSWORD} |
| Prometheus | http://localhost:9090 | none |
| Pushgateway | http://localhost:9091 | none |
| Volume | Backed by | Survives docker compose down? |
|---|---|---|
postgres_data |
/var/lib/postgresql/data |
yes |
mongodb_data |
/data/db |
yes |
prometheus_data |
/prometheus |
yes |
grafana_data |
/var/lib/grafana |
yes |
Use make clean to remove containers + volumes, or make prune to nuke everything including images and build cache.
Dispatches the docker compose run app <command> invocation to the correct script. Acts as the bridge between compose services and the project scripts.
flowchart TD
classDef entry fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
classDef cmd fill:#fff8e1,stroke:#f9a825,color:#5d4037
classDef default fill:#e8f5e9,stroke:#2e7d32,color:#1b5e20
A["docker compose run app <cmd>"]:::entry
B{{"Which command?"}}:::default
C["pipeline → ETL + PL/pgSQL + GX"]:::cmd
D["etl → scripts/python/mongo_to_postgres.py"]:::cmd
E["dq-loops → scripts/python/plpgsql_loops_tests.py"]:::cmd
F["dq-gx → scripts/python/run_gx.py"]:::cmd
G["inspect-schema → scripts/python/inspect_schema.py"]:::cmd
H["monitor-logs → scripts/monitor_logs.sh"]:::cmd
I["log-cleanup → scripts/log_cleanup.sh"]:::cmd
J["shell → bash interactive"]:::cmd
K["Default → run as Python script"]:::default
A --> B
B -->|pipeline| C
B -->|etl| D
B -->|dq-loops| E
B -->|dq-gx| F
B -->|inspect-schema| G
B -->|monitor-logs| H
B -->|log-cleanup| I
B -->|shell| J
B -->|anything else| K
Excludes local-only files from the build context:
__pycache__/,.venv/,.env(secrets).git/(history)logs/,reports/(artifacts)tests/generic/loops/*.sqlis not excluded (PL/pgSQL test files are loaded into the container for the dq-loops job)
- Add the service block to
docker-compose.ymlin themonitoringnetwork - Add a
healthcheck:(so dependent services wait for it) - Document in docs/ARCHITECTURE.md Container Topology section
- Add a
cmd_<jobname>branch todocker/entrypoint.sh - Add a
make <jobname>target in the Makefile - Document in docs/run_book.md