Two parallel tracks: - Track 1: fxt CLI -> gRPC -> JobSpawner (PostgreSQL) -> K8sDispatcher -> GPU Jobs - Track 2: S3 checkpoints -> model loader -> promotion manager -> serving Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5.4 KiB
Training Pipeline & Model Deployment Design
Date: 2026-02-27 Status: Approved Tracks: Two independent parallel tracks
Overview
Wire the complete training-to-serving pipeline on Kapsule. Track 1 handles training job dispatch (fxt CLI → gRPC → PostgreSQL → K8s GPU Jobs). Track 2 handles model serving and promotion (S3 checkpoints → model loader → inference → operator-gated promotion).
Both tracks share S3 (foxhunt-models/) as the handoff point.
Track 1: Training Pipeline
Goal
fxt train start tft ES.FUT --epochs 50 creates a real GPU training job on Kapsule.
Flow
fxt train start tft ES.FUT --epochs 50
→ gRPC StartTraining (ml_training_service:50053)
→ service.rs handler → JobSpawner::spawn_batch() → PostgreSQL
→ In-process queue consumer (tokio::spawn, 5s poll)
→ JobSpawner::get_next_pending_job()
→ K8sDispatcher::dispatch() → batch/v1 Job
├── training container (GPU, train_baseline_rl/supervised)
└── uploader sidecar (S3 → foxhunt-models/)
→ Job completion callback → update status in PostgreSQL
Existing Code
| Component | File | Status |
|---|---|---|
| fxt train start | bin/fxt/src/commands/train/start.rs |
Done (sends gRPC) |
| fxt train status | bin/fxt/src/commands/train/status.rs |
Done |
| fxt train list | bin/fxt/src/commands/train/list.rs |
Done |
| K8sDispatcher | services/ml_training_service/src/k8s_dispatcher.rs |
Done (builds Jobs) |
| JobSpawner | services/ml_training_service/src/job_spawner.rs |
Done (PostgreSQL CRUD) |
| Job template | infra/k8s/training/job-template.yaml |
Done (reference only) |
Changes Needed
-
Wire gRPC handler to JobSpawner:
service.rsStartTraining handler must callJobSpawner::spawn_batch()instead of returning a stub response. -
Add queue consumer loop: In
main.rs,tokio::spawna loop that pollsget_next_pending_job()every 5s and callsK8sDispatcher::dispatch(). -
Job completion callback: The uploader sidecar already has
CALLBACK_ENDPOINT. Add a gRPC or HTTP endpoint in ml_training_service that receives completion notifications and callsJobSpawner::update_job_status(). -
Deploy training-output-pvc: Currently only
training-data-pvcis deployed. Needtraining-output-pvcfor job artifact staging. -
PostgreSQL schema: Deploy
batch_jobsandchild_jobstables. Add sqlx migration. -
Docker image: Rebuild ml-training-service image with kube-rs K8sDispatcher compiled in.
K8s Resources
ml-training-serviceDeployment (exists, needs redeploy with new image)training-data-pvc(exists, 10Gi scw-bssd)training-output-pvc(new, needs creation)s3-credentialsSecret (exists)scw-registrySecret (exists)gpu-trainingnode pool (Scaleway, autoscales 0→N)
Track 2: Model Serving & Validation
Goal
Trained model checkpoints deploy to a serving endpoint with operator-gated promotion and automatic rollback.
Flow
Training job completes → uploader sidecar → S3 (foxhunt-models/)
→ Callback to ml_training_service
→ PromotionManager::register_completion()
├── No active model → auto-register
└── Compare metrics → PendingPromotion / NoImprovement
→ fxt model promote <model-id> (operator approval)
→ DeploymentPipeline::deploy()
├── Rolling update
├── Health check (inference smoke test)
└── Auto-rollback on failure
Existing Code
| Component | File | Status |
|---|---|---|
| S3ModelLoader | crates/model_loader/src/lib.rs |
Done (S3 + LRU cache + versioning) |
| PromotionManager | services/ml_training_service/src/promotion_manager.rs |
Done (metric comparison, pending/active tracking) |
| DeploymentPipeline | services/ml_training_service/src/deployment_pipeline.rs |
Done (rolling update, health check, rollback) |
| ValidationPipeline | services/ml_training_service/src/validation_pipeline.rs |
Exists |
Changes Needed
-
fxt model commands: Add
fxt model promote,fxt model list,fxt model statusCLI subcommands. -
Wire promotion callback: Uploader sidecar completion → PromotionManager::register_completion(). Extract metrics from training output.
-
Model serving deployment: K8s Deployment that loads active model from S3 via S3ModelLoader and serves predictions via gRPC.
-
Validation test: Send sample market data to inference endpoint, verify prediction response shape and latency.
-
Proto additions: Add
PromoteModel,ListModels,GetModelStatusRPCs to ml_training proto.
Shared Infrastructure
| Resource | Status | Notes |
|---|---|---|
| PostgreSQL | Running in foxhunt ns | Needs schema migration |
| S3 foxhunt-models | Exists | Bucket + credentials |
| training-data-pvc | Deployed | 10Gi, read-only for jobs |
| training-output-pvc | Needs creation | Staging for job artifacts |
| scw-registry secret | Deployed | Image pull auth |
| gpu-training pool | Configured | Autoscales 0→N |
Decision Log
| Decision | Choice | Rationale |
|---|---|---|
| Job dispatch path | DB-backed (JobSpawner) | Full history, batch orchestration, rollback |
| Queue consumer | In-process tokio task | Zero additional infra, simple |
| Track split | Training vs Serving | Independent concerns, parallel development |
| Promotion gating | Operator approval | Production safety for HFT system |