01. Overview & the golden path
Outcome
By the end of this chapter you can describe the whole platform on one page: the four planes it is built from, the invariants that never change, the golden path a model travels from data to production, and the phased order in which we build it. Every later chapter fills in one phase of this map.
The guiding rule, adopted from docs/00, is the fewest moving parts that deliver reproducibility, honest evaluation, scheduled/on-demand workflows, and observable operations — and no more. We deliberately reject an enterprise control-plane build (durable orchestration engine, hash-chained release ledgers, a bespoke broker) because it costs more to build and operate than a small ML team can sustain and buys guarantees we do not yet need.
## The four planes
The platform is four planes plus a thin dashboard. Everything else follows.
| Plane | Responsibility | Azure building block |
|---|---|---|
| Execution | Run every workflow as an ephemeral, image-pinned task | Azure Container Apps Jobs |
| Model lifecycle | Track experiments, register versions, store artifacts | Self-hosted MLflow (ACA App + Postgres + Blob) |
| Operational state | Record status/output/error for every run, with batch granularity | Generic results DB (Postgres) |
| Serving | Optional online HTTP inference at an exact model version | Azure Container Apps Apps |
flowchart TD
DASH["Dashboard (ACA App, Entra)<br/>catalog + launcher + links"]
JOBS["ACA Jobs (execution)<br/>train / eval / batch / task"]
MLF["Self-hosted MLflow<br/>registry + tracking"]
RDB["Results DB<br/>run state"]
BLOB["Blob<br/>artifacts"]
OBS["Grafana / Log Analytics<br/>dashboards"]
DASH -->|reads status| JOBS
DASH -->|deep-links| MLF
DASH -->|deep-links| OBS
JOBS -->|read model version| MLF
JOBS -->|write runs| RDB
JOBS -->|large payloads| BLOB
MLF --> BLOB
The dashboard is a read-and-launch surface over these planes; it holds no authoritative state of its own.
## Fixed invariants
These hold across every chapter. Changing any of them is an architecture decision, not an implementation detail (docs/00).
- ACA Jobs are the execution plane — every workflow (train, eval, batch, ad-hoc) runs as an ephemeral Job from a pinned image digest, scaled to zero when idle. A code deploy is just a Job-definition image bump, so it can never strand a stale worker on old code.
- No workflow control-plane service — linear multi-step workflows are one script in one Job. No Durable Functions, no orchestration engine.
- No application broker by default — no Service Bus, Redis broker, or Celery fleet in the baseline. Fan-out is parent/child rows in the results DB.
- Self-hosted MLflow is the tracking + model registry, pinned to an exact version — the registered version number is the canonical model identity.
- A generic results DB is the run store — one table records status/output/ error for every job, with parent/child rows for batch granularity.
- MLflow is scoped to model lifecycle — batch inference only reads a pinned version; its state lives in the results DB, not as MLflow runs.
- GitHub Actions is CI/CD only — build/test/scan images and update Job/App definitions. Never a scheduler or orchestrator.
- Least-privilege managed identities; OIDC for CI — each workload has its own identity with minimal roles; no shared broad identity, no secrets in images.
- Distributed/multi-GPU training is an admission-gated exception — Azure ML
commandjobs against min-zero clusters, logging to the same MLflow.
## The golden path
A single path a model travels from data to production. Every step is an ACA workload, every model is a registry version, every run is a results-DB record, and every human action is audited.
flowchart TD
DATA["tracked dataset"]
TRAIN["train Job (ACA)"]
VER["MLflow run + registered version"]
EVAL["eval Job (ACA)<br/>metrics + results-DB record"]
PROMOTE["promote version"]
BATCH["batch Job (ACA, scheduled/manual)<br/>reads models:/name/version<br/>parent/child result rows"]
SERVE["serving App (ACA, optional)<br/>loads models:/name/version<br/>/health reports version"]
OBS["dashboard + Grafana + alerts"]
DATA --> TRAIN --> VER --> EVAL --> PROMOTE
PROMOTE --> BATCH
PROMOTE --> SERVE
BATCH --> OBS
SERVE --> OBS
## The phased build — and how the course maps to it
We build in the phase order of docs/07, where each phase is independently useful. The course chapter that implements each phase is shown alongside.
| Phase | What ships | Useful because | Chapter |
|---|---|---|---|
| 0 — Foundation | Registry, ACA env + Log Analytics, Postgres (mlflow + results), storage, Key Vault, Grafana, identities; self-hosted MLflow |
Everything has a home and an identity | 02 |
| 1 — Reproducible training + registry | train/eval ACA Jobs logging to MLflow + results-DB records | Reproducible models with recoverable lineage | 03 |
| 2 — Results DB + first workflow | results-DB module + one scheduled/batch workflow (parent/child + continuation) | The operational backbone exists and is exercised | 04 |
| 3 — Serving + promotion/rollback | serving App + version-based promotion/rollback | Models reach consumers with safe rollback | 05 |
| 4 — Observability + dashboard | alerts, Grafana, catalog/launcher dashboard | The team can see and launch everything | 06 |
| 5 — LLM artifacts | pyfunc packaging + evaluator reusing the same paths | An LLM ships through existing machinery | 07 |
| Exc. — Multi-GPU | admission-gated Azure ML path | Distributed training without derailing the baseline | 08 |
| Upg. — Broker | Celery-as-a-library on KEDA-triggered ACA Jobs + Redis | Only if fan-out routinely exceeds a few hundred units | 09 |
Chapter 10 integrates the whole golden path end to end.
## How to read the rest of the course
Each chapter is structured the same way, so the build stays predictable:
- Outcome — what you can do when the chapter is done.
- Design — the decisions from the relevant
docs/document, in brief. - Build in
projects/ml-platform/— the modules, images, IaC, or scripts the chapter adds to the project (the source is authored in the project, not the notebook). - Golden-path position — where this chapter’s slice sits in the diagram above.
- Acceptance evidence — what demonstrates the slice actually works (never “a local demo ran”).
- Extensions — what the production contract asks for that this MVP defers, and the
docs/section that specifies it.
Next: 02 — Platform foundation stands up the footprint every later phase depends on.