All projects

ML Platform

A self-hosted Kubernetes ML platform for scheduled scoring, versioned datasets, model monitoring and governed serving, backed by a PostgreSQL control plane and a separate Go inference gateway.

ML Platform home with health, scheduled work and model drift attention items, populated with synthetic demo data
Repository UI capture, synthetic demo data.

One lifecycle, two planes

ML Platform organizes training, scheduled scoring, data lineage, model quality and serving around a shared project workspace. Each project has identity, roles, quotas and a durable record of the changes requested by its users.

PostgreSQL holds lifecycle intent. Reconcilers drive Kubernetes, Argo Workflows, MLflow and KServe toward it. A separate Go inference gateway governs model predictions, streaming chat and container-function calls, allowing management and serving traffic to scale independently.

Current validation, with explicit boundaries

Reviewed against main at 6d4e9a2 (8 October 2026). These are distinct acceptance checks on a single-node ARM64 kind laboratory, not a unified benchmark or customer deployment. The committed reports record methods, identities and artifact hashes; some raw data and logs remain in external archives.

NYC TLC, local historical-data replay, 8 Oct 20261,000,000
Trips scored and matched to labels100% feedback coverage, zero unmatched rows.
Single node, warm images, Argo overhead included18.95 s
Scheduled scoring pipeline1 CPU / 1 GiB main container; separate monitoring Job took 28.17 s. One recorded execution, not sustained throughput.
Go gateway, final-image acceptance, 7 Oct 2026200/200
Function responses during rolling restartReal function requests with validated IDs and headers. Availability probes, not load-capacity measurement.
Monitoring automation, local artifact, 8 Oct 202612/12
Control-plane release checksMigration 0030, dependency isolation, readiness recovery, SBOM and severity/secrets scans.
EvidenceWhat passedMeasurement boundary
CPU lifecycleTraining → registration/evaluation → real serving; healthy canary, candidate-only rollback and scale-to-zero/reactivationLocal ARM64 artifacts and local auth-none setup. GPU, real OIDC and multi-node resilience are separate gates.
Million-row replayScheduled scoring, versioned predictions, identical rerun bytes and independently checked quality reportHistorical public data, warm images, one node. Model preparation and training happened locally before platform scoring.
Monitoring automationOutput v3 triggered a report; reconciler restart created no duplicate execution. 12/12 control-plane image checks passed.The first dispatch exposed a missing runtime INSERT grant. Owner repair allowed retry; current migration/provisioning includes the grant. Deployed image a3202e3 precedes that provisioning fix.
Go gatewayFinal-artifact soak: 150,000/150,000 requests; rolling restart: 200/200 real function responses; database outage/recoveryThe 500 RPS soak returned 429 caller-debt rejections. Function probes were separate. Successful inference capacity and maximum throughput remain unmeasured.

From a processing date to an inspectable quality report

The NYC TLC case study uses one million cleaned, sampled taxi trips from each of January and February 2025. A fare model trains locally on 200,000 January rows, then enters MLflow with a frozen SHA-256 manifest. The platform owns the subsequent scheduled scoring and monitoring workflow.

  1. 01

    Freeze the execution inputs

    The schedule resolves processing date 2025-02-01 to taxi-features v2. Typed parameters, model and dataset identities persist in an immutable execution snapshot before Argo starts work.

  2. 02

    Score within explicit resource bounds

    The worker verifies input integrity and the model manifest, then scores one million rows in 10,000-row batches. The recorded pipeline takes 18.95 s including Argo overhead, with a 1 CPU / 1 GiB main container and warm images.

  3. 03

    Publish versioned predictions and lineage

    Outputs carry their producer run, pipeline step, input dataset and model identity. An independent rerun publishes v2 at a separate S3 location with identical bytes; replaying its creation key returns the same run.

  4. 04

    Measure quality against recorded fares

    A separate monitoring Job joins every prediction by trip_id: 100% coverage, zero unmatched rows. MAE 2.082 USD, RMSE 4.466 USD and R² 0.920 agree with independent pandas/sklearn calculations. The Job takes 28.17 s in the recorded run.

  5. 05

    Trigger future checks from publication

    A follow-up run publishes v3 and automatically creates monitoring. Publication and its outbox event commit together; a unique rule/dataset intent survives reconciler restart. Feedback is date-matched and frozen, or the execution waits within its deadline.

All four selected features were STABLE at PSI threshold 0.2 (PSI 0.000405–0.007974). That describes these cleaned windows; no drift was injected and STABLE does not rule out every quality problem. Ground truth was withheld before scoring, not collected from live inference. The demonstration schedule is paused.

One platform intent per dataset occurrence is not exactly-once external side effects. Monitoring failure is independent of producer success. Same-DAG dynamic output binding, rolling monitoring windows, online prediction capture and a Feature Store remain outside the demonstrated scope. Read the automation contract.

The web workspace

Current repository captures show schedules, versioned datasets, batch definitions and model-quality reports. The Credit Risk scenario uses synthetic demo data; these screens are separate from the real NYC acceptance evidence above.

Synthetic Credit Risk quality report with feature drift, missing values, feedback coverage, accuracy and macro F1
Model monitoring: distinguish drift, coverage and predictive qualitySynthetic demo. Open the image for the full-size view
Synthetic Credit Risk schedules showing recurring scoring, quality review, timezone and next execution
Schedules: recurring work with recorded execution historySynthetic demo. Open the image for the full-size view
Synthetic prediction dataset showing immutable versions, schema and recorded input, model, run and output lineage
Dataset lineage: inspect the identities behind an outputSynthetic demo. Open the image for the full-size view
Synthetic Credit Risk batch inference definition with pinned input and model versions and Parquet output
Batch inference: bind a model and data to a reproducible runSynthetic demo. Open the image for the full-size view
Synthetic completed training pipeline with DAG, step timeline, model lineage and readable execution logs
Pipeline runs: connect execution steps, logs and model lineageSynthetic demo. Open the image for the full-size view

From training to a governed endpoint

Projects and access

  • Project namespaces, resource quotas and GPU budgets
  • OIDC sign-in with user and group memberships
  • Invoker, viewer, operator and admin roles with fail-closed policy and audit

Data and recurring execution

  • Cron schedules with timezone, concurrency and missed-run policies
  • Typed parameters and immutable execution snapshots
  • S3/MinIO connections, versioned CSV/Parquet datasets and recorded lineage

Batch inference and model quality

  • Pinned model manifests, bounded scoring and versioned prediction outputs
  • PSI and missing-rate drift; regression and classification quality reports
  • Dataset-triggered monitoring with date-matched feedback and restart-safe intent

Training and model lifecycle

  • Argo Workflows jobs and multi-step pipeline DAGs
  • Run logs, step timelines, retry, cancellation and model lineage
  • Evaluation thresholds, candidate/champion promotion and MLflow alias reconciliation

Serving and release control

  • Immutable deployment revisions and manual rollback
  • Canary steps gated on error rate, p95 latency and minimum traffic
  • Automatic rollback when a canary fails its release gates

LLMs and functions

  • Full-commit-pinned Hugging Face versions
  • OpenAI-compatible streaming chat and project GPU quotas
  • Container functions with Knative scaling and JSON invoke endpoints

Inference gateway

  • Go data plane for predict, chat and function traffic; Python rollback option
  • Per-caller API keys, endpoint exposure and request/token limits
  • Caller usage, request IDs and a consistent error contract

Web UI and monitoring

  • React workspace for schedules, datasets, lineage, quality reports and serving
  • Preview consequential changes before applying them
  • Monitor, Grafana, Prometheus and traces from requests through reconcilers

System architecture

The control plane records intent and returns; background reconciliation handles infrastructure. The data plane checks caller access and endpoint state before forwarding traffic. External systems sit behind adapters, keeping lifecycle rules independent of their SDKs. The API/reconcilers remain Python; the chart defaults to a separate Go gateway with a Python rollback option. The CPU path is lab-verified; the vLLM path below represents implemented contracts awaiting GPU acceptance.

ML Platform architecture: a project-scoped web workspace and management API commit lifecycle intent to PostgreSQL. Reconcilers drive Kubernetes, Argo Workflows, MLflow and KServe toward desired state. A separate Go inference gateway governs prediction, streaming chat and function calls. OIDC roles, quotas, audit and telemetry span these boundaries.

Control plane and reconciliation

The API records desired state; asynchronous reconcilers turn that intent into external resources.

Web workspace OIDC + project roles Control plane API. Control plane API commit intent PostgreSQL. PostgreSQL read desired state Reconcilers. Reconcilers apply + observe Kubernetes + Argo (namespaces, quotas, workflow DAGs). Reconcilers apply + observe MLflow + KServe (aliases, immutable serving revisions).

  1. ClientWeb workspaceReact, same-origin session
  2. ControlControl plane APIauthorize, validate, audit
  3. PersistencePostgreSQLlifecycle truth, trace context
  1. ControlReconcilersschedules, runs, publications, rollouts
  2. ServiceKubernetes + Argonamespaces, quotas, workflow DAGs
    ServiceMLflow + KServealiases, immutable serving revisions

Inference data plane

Prediction traffic bypasses the management API. Caller scope, endpoint readiness and budgets are checked at the gateway.

External caller predict, chat, invoke Inference gateway. Inference gateway forward / stream KServe + Knative. KServe + Knative serve MLflow server (classic model inference). KServe + Knative serve vLLM (GPU acceptance pending). KServe + Knative serve Container function (JSON invoke, scale to zero).

  1. ClientExternal callerAPI key or OIDC token
  2. BoundaryInference gatewayGo, endpoint scope, shared budgets
  1. ServiceKServe + Knativerevision routing, canary split
  2. ServiceMLflow serverclassic model inference
    ServicevLLMGPU acceptance pending
    ServiceContainer functionJSON invoke, scale to zero

Scheduled scoring and model quality

Freeze execution identities, publish versioned predictions and trigger an independent monitoring run through a transactional publication event.

Schedule + dataset dispatch Argo run Batch worker. Batch worker publish + commit S3 + dataset catalog. S3 + dataset catalog transactional outbox Monitoring rule + worker. Monitoring rule + worker persist report Model quality report.

  1. ControlSchedule + datasetprocessing date · immutable snapshot
  2. ServiceBatch workerverified model + bounded Parquet scoring
  3. PersistenceS3 + dataset catalogversion · integrity · producer lineage
  1. ControlMonitoring rule + workerpinned reference · date-matched feedback
  2. PersistenceModel quality reportPSI · coverage · predictive metrics

Training to serving

Run lineage, evaluation and promotion govern which artifact becomes an immutable deployment revision.

Job / pipeline register output Model version. Model version acceptance thresholds Evaluation. Evaluation promote Champion. Champion create revision Deployment revision.

  1. ServiceJob / pipelineArgo Workflows, run lineage
  2. PersistenceModel versionMLflow or Hugging Face
  3. AnalyzerEvaluationcandidate or rejected
  1. ControlChampionregistry alias reconciliation
  2. OutputDeployment revisioncanary gates, rollback

Observability

Durable trace context connects API changes to background work. Metrics inform both operations and release decisions.

API, reconcilers, gateway export OTel Collector. OTel Collector route Prometheus (health + revision metrics). OTel Collector route Tempo (request-to-reconciler traces). Prometheus and Tempo inspect Monitor + Grafana.

  1. ServiceAPI, reconcilers, gatewaytraces, metrics, structured logs
  2. ObservabilityOTel Collectorshared telemetry pipeline
  1. ObservabilityPrometheushealth + revision metrics
    ObservabilityTemporequest-to-reconciler traces
  2. OutputMonitor + Grafanahealth, trends, alerts

Architecture notes

  • PostgreSQL owns lifecycle intent; reconcilers own convergence with external systems.
  • The UI calls the platform API rather than Kubernetes, Argo, MLflow or KServe directly.
  • GPU quotas constrain deployment and canary requests; immutable revisions retain runtime settings.
  • CPU lifecycle and scheduled scoring run end to end in the local Kubernetes lab.

A model moves through explicit states

  1. 01

    Create a project and establish access

    The control plane records the project and memberships; the project reconciler targets a dedicated namespace with quotas, limits and network policy.

  2. 02

    Run a training job or pipeline

    A job or DAG becomes desired state. Reconcilers submit Argo workflows and bring run status, steps and failure reasons back into the platform.

  3. 03

    Evaluate and promote a version

    Register an MLflow artifact or Hugging Face version, evaluate it against acceptance thresholds, then promote an eligible candidate. Model-alias reconciliation aligns the registry with platform state.

  4. 04

    Create an immutable serving revision

    An authorized request checks version eligibility, runtime kind and GPU quota, then commits the revision, desired deployment state and audit context to PostgreSQL.

  5. 05

    Reconcile and gate the rollout

    Deployment reconciliation targets KServe readiness. The rollout loop shifts canary traffic, reads revision metrics and advances or rolls back according to its gates.

  6. 06

    Expose an endpoint through the gateway

    Callers use scoped API keys or OIDC tokens. The separate gateway resolves ready endpoints, applies limits, forwards or streams the response and records usage.

Registration, evaluation, promotion, deployment readiness and canary success are separate decisions with their own state transitions.

Access follows the project; traffic follows its plane

OIDC supplies identity. Project membership and a fail-closed policy table govern management operations; the gateway applies caller scope to exposed endpoints. Namespace policy and quotas define the workload boundary behind those application rules.

Management planeInference data plane
  • Browser → same-origin API with signed session and CSRF protection
  • Project policy controls each management operation
  • PostgreSQL owns lifecycle intent and audit
  • Reconcilers drive external systems through typed ports
  • Callers → separate gateway with API key or OIDC token
  • Endpoint exposure and caller scope checked before forwarding
  • Request or token budgets applied to calls
  • Prediction traffic bypasses the management API

Design decisions

Commit intent before touching infrastructure

An API request records desired state and returns. Reconcilers compare that intent with external state and apply deterministic resources, so an interrupted operation can be resumed on a later pass.

Separate management from prediction traffic

The control plane governs projects and lifecycle changes. The inference gateway has its own process and pods, allowing prediction traffic and management operations to scale independently.

Keep domain rules behind ports

Domain and application layers import no frameworks or external SDKs. Kubernetes, Argo, MLflow, KServe, Prometheus and identity sit behind adapters; composition roots wire the implementation.

Preserve the release decision

Immutable revisions bind an artifact to its runtime settings. Canary gates assess the candidate revision's error rate, p95 latency and traffic; a failed gate drives rollback instead of declaring a deployment healthy from readiness alone.

Carry identity and trace context through reconciliation

Lifecycle changes retain actor and trace context in durable state. Audit explains who requested the change, while reconciler spans connect asynchronous work back to that request.

Infrastructure foundation

The platform grew from a local Kubernetes inference service with MLflow, PostgreSQL, MinIO, GitOps and observability. The measurements below belong to that original infrastructure: they describe its load, autoscaling and recovery behavior, separately from the broader platform design.

Historical measurements remain scoped to the original service; the current Go gateway and expanded platform do not inherit its throughput. Original milestone record.

Evidence sliceFoundation resultScope
Load test645,809 requests, 0% errorsk6 against the live cluster; saturated throughput 2,935 req/s at a saturated /predict p95 of 32.9 ms.
Autoscaling2 → 6 replicas in 71sHPA scale-up under load; scale-down back to 2 takes ~230s, stepped rather than immediate.
Recovery timing12–15s pod, ~1.4s driftPod deleted to replacement serving is 12–15s. Argo CD detects and reconciles config drift in ~1.4s, independent of its ~3 min Git poll.
Reproducibility11/11 acceptance, 901sCluster, images and build cache destroyed first, then make local-up → make local-test from the repo alone, proven in M11.
Failure engineering8 faults injected, not simulatedRun against the live cluster with measured detection and recovery, not described in documentation.
Security boundaryNetworkPolicy deny verifiedinference → PostgreSQL directly is denied and confirmed by test, not assumed from the policy YAML; Pod Security Standards: restricted is enforced.

Selected failure drills from the first infrastructure

ScenarioObservedRecovery
Pod crashReplicaSet notices; the surviving replica keeps servingreplacement ready in 12–15s
Invalid model artifactreadiness probe returns 503; pod held out of Service endpointsGit revert
Artifact store outage100% of requests still return 200 while the pod is not readybackground recheck, 0 restarts
Config driftArgo CD marks the app OutOfSync the moment it divergesself-heal in ~1.4s
Bad rolloutmaxUnavailable: 0 keeps old replicas servingGit revert, bad ReplicaSet pruned
Node drain with a stateful pod on itsurviving inference pod absorbs trafficPostgreSQL / MinIO reschedule automatically

Platform stack

Control planePython + FastAPI, PostgreSQL + SQLAlchemy + Alembic
Inference gatewayGo + PostgreSQL budgets + OpenTelemetry; Python rollback runtime
Data and qualityS3/MinIO catalog, bounded batch workers, PSI and feedback metrics
Web workspaceReact + TypeScript, typed OpenAPI client
IdentityOIDC + Keycloak, project roles, signed sessions
TrainingArgo Workflows, jobs and pipeline DAGs
ModelsMLflow registry + Hugging Face Hub
Serving architectureKServe + Knative, MLflow server, vLLM and container functions
ObservabilityOpenTelemetry Collector + Prometheus + Tempo + Grafana
InfrastructureKubernetes + Helm + Argo CD; Terraform for EKS, RDS and S3

Deployment

The control-plane Helm chart is deployed and runtime-verified on the local ARM64 lab. It defaults to two API, gateway and reconciler replicas, with PDBs and Lease-elected reconciliation. The AWS target is designed alongside it, backed by Terraform.

LayerLocal targetAWS design target
ClusterkindEKS
Lifecycle databasePostgreSQLRDS PostgreSQL
ArtifactsMinIOS3
ImagesLocal container imagesECR
IdentityKeycloakOrganization OIDC provider
Ingressingress-nginx + cert-managerALB or ingress + ACM

In short

What is ML Platform?
ML Platform joins training, scheduled batch inference, immutable dataset versions, recorded lineage, model-quality reports and serving in one project-scoped workspace. A Python API and reconcilers persist intent in PostgreSQL; a separate Go gateway governs inference traffic. Local Kubernetes acceptance includes the CPU lifecycle and a million-row historical NYC TLC scoring/monitoring workflow.
What problem does ML Platform solve?
Training a model is only one step in operating it. Teams also need ownership, evaluation rules, release decisions, serving access and a way to recover interrupted infrastructure changes. This platform organizes those concerns around durable lifecycle intent and distinct control and data planes, extending the original Kubernetes inference foundation into a shared ML workspace.

Deep dive