Practical MLOps · Testing, promotion, and rollback layer
CI/CD/CT for Machine Learning: Testing, Promotion and Rollback
CI validates code, data contracts, pipeline components, and model tests. CD promotes a versioned deployment candidate through controlled environments. CT creates a retraining candidate when approved triggers fire. Production safety comes from immutable release identity, independent evaluation, approval rules, progressive delivery, observation, and rollback.
Direct answer
CI validates code, data contracts, pipeline components, and model tests; CD promotes a versioned deployment candidate through controlled environments; CT creates a retraining candidate when approved triggers fire. Production safety comes from immutable release identity, independent evaluation, approval rules, progressive delivery, observation, and rollback — not from retraining automatically.
Change-to-release architecture
- ChangeCode commit, data version, config update
- CI GatesLint, tests, data contracts, model tests
- Build CandidateContainer image + model artifact
- CD GatesSign, validate, smoke test, canary
- ProductionServing with monitoring
- Observe & RollbackCanary metrics, alias rollback
CT triggers re-enter at Change: a monitoring signal or schedule creates a new training run, which goes through the same gates.
CI, CD, CT and the release-unit contract
Continuous Integration (CI) validates code, data contracts, pipeline components, and model tests on every change. The artifact of CI is a validated, versioned candidate — not a deployed model.
Continuous Deployment (CD) promotes a validated candidate through controlled environments (staging, canary, production) with gates at each step. The artifact of CD is a deployed model service with a traceable release identity.
Continuous Training (CT) creates a retraining candidate when approved triggers fire (drift, performance degradation, schedule, new labels). The artifact of CT is a new model candidate that enters the same CI and CD pipeline as any code-driven change.
Release-unit contract
Inputs
- Code commit hash
- Data version ID (DVC or equivalent)
- Environment container image digest
- Pipeline version (IR YAML hash)
- Model version (MLflow registry version + alias)
- Configuration (environment-specific values)
- Evaluation report (metrics, slice checks, thresholds)
Outputs
- Immutable release identity (the tuple of all inputs, hashed)
- Deployed model service with traceable lineage
- Rollback target (previous release identity)
State owned
- Release identity for every deployed model
- Promotion state (candidate, validated, staged, canary, production, rolled back, archived)
- Approval history (who approved, when, based on what evidence)
Failure boundary
A green CI check does not prove a model is production-safe. CI proves the code compiles, tests pass, and contracts hold. CD proves the candidate deploys and survives canary. Neither proves the model is correct for your business context — that requires human judgment and ongoing monitoring.
Continuous integration validation gates
CI gates run on every change and must pass before a candidate is built. Each gate catches a different class of problem.
- Formatting, lint, and type checks: catch code quality issues early
- Unit tests: validate individual functions and components
- Data and schema contracts: validate that data conforms to the expected schema before training
- Pipeline component tests: test each KFP component in isolation with sample inputs
- Model serialization and load test: verify the model artifact can be loaded by the serving runtime
- Deterministic smoke training: run a tiny training job (1 epoch, small batch) to verify the pipeline end-to-end
- Evaluation thresholds: compare model metrics against a baseline or minimum bar
- Slice checks: evaluate performance on important subgroups, not just aggregates
- Security and dependency checks: scan for vulnerabilities in dependencies and secrets in code
Continuous delivery promotion gates
CD gates run as the candidate moves through environments. Each environment has its own gates.
- Signed or traceable artifact: verify the container image digest and model version match the CI output
- Environment promotion: deploy to the next environment (staging, then canary, then production)
- Infrastructure and config validation: verify Kubernetes manifests, resource requests, and secrets
- Smoke and integration tests: verify the model loads and serves in the target environment
- Canary or shadow observation: route a percentage of traffic and compare metrics against baseline
- Approval and rollback: a human or policy approves promotion; rollback is always available
Continuous training triggers and safeguards
CT triggers create retraining candidates. Each trigger should be approved, logged, and gated — CT is not an automatic path to production.
Approved CT triggers: performance degradation confirmed by real labels (not just drift), scheduled refresh, new labeled data batch, data-quality incident requiring retraining on corrected data.
Safeguards: every CT candidate goes through the same CI and CD gates as a code-driven change. No CT candidate skips evaluation, slice checks, or canary. If the CT candidate fails any gate, it is rejected — not promoted by default.
Do not allow drift alone to trigger automatic promotion. Drift is an investigation signal. Retrain only when investigation confirms the drift impacts model performance, or when a scheduled refresh policy explicitly permits it.
Secrets, workload identity and auditability
Secrets (database credentials, cloud keys, API tokens) must never be hard-coded in pipeline code or container images. Use environment variables injected by the CI/CD system, or a secret store (Kubernetes Secrets, AWS Secrets Manager, HashiCorp Vault).
Workload identity (IAM roles for service accounts on Kubernetes, GitHub Actions OIDC) is safer than long-lived access keys. Use short-lived credentials scoped to the minimum permissions needed for each step.
Audit logs record who triggered a run, what gates passed or failed, who approved promotion, and when rollback occurred. These are required for compliance and for post-incident review. Store them in an append-only system.
Environment separation means staging and production have different credentials, different namespaces, and different gate requirements. A staging deployment should never have production credentials.
Promotion state machine and pipeline pattern
Every model version moves through a defined state machine. Each transition is gated and logged.
- candidate: a new model version exists in the registry, not yet evaluated
- validated: CI gates passed (tests, evaluation thresholds, slice checks)
- staged: deployed to staging environment, smoke tests passed
- canary: receiving a percentage of production traffic, metrics within thresholds
- production: @champion alias assigned, receiving full traffic
- rolled back: @champion alias reassigned to previous version, candidate archived
- archived: no longer active, retained for lineage and audit
Manual, approval-assisted, and automated promotion
Manual promotion
- Choose when
- Your model is high-risk, low-frequency, or you lack confidence in automated gates.
- Avoid when
- You retrain frequently (daily or hourly) and manual approval creates a bottleneck.
- Operational tradeoff
- Maximum control and human judgment, but slow and does not scale to frequent retraining.
Approval-assisted promotion
- Choose when
- You want automation for routine steps but human approval for the production transition.
- Avoid when
- Your retraining frequency is so high that human approval is always the bottleneck.
- Operational tradeoff
- Automates CI and staging, requires human sign-off for canary and production. Balances speed and safety for most teams.
Automated promotion (with gates)
- Choose when
- You have well-tested gates, reliable monitoring, and a rollback path you have practiced. The model is low-risk or you retrain very frequently.
- Avoid when
- Your gates are not comprehensive, your monitoring is incomplete, or the model is high-risk.
- Operational tradeoff
- Fastest path to production, but relies entirely on gate quality. A missing gate becomes a production incident. Always include automatic rollback thresholds.
CI/CD/CT failures and recovery
| Failure | Observable signal | Likely cause | First diagnostic | Containment | Durable fix | Evidence |
|---|---|---|---|---|---|---|
| Flaky test blocks promotion | CI fails intermittently on the same code | Test depends on timing, external service, or non-deterministic state | Check test logs for non-deterministic patterns; re-run to confirm flakiness | Mark test as flaky and quarantine; re-run CI | Fix the test to be deterministic; remove external dependencies from unit tests | Engineering inference from CI best practices |
| Leaked secret in CI logs | Secret visible in CI output or logs | Secret printed in error message or debug output | Check CI log output for the secret; rotate it immediately | Rotate the secret; redact logs; revoke any tokens derived from it | Use secret masking in CI; never print secrets in error messages; scan for secrets in CI | Engineering inference from security best practices |
| Mutable tag causes non-reproducible deploy | Same deployment tag produces different behavior | Container image tag overwritten or re-pushed with different content | Compare image digest (not tag) between CI output and deployed image | Re-deploy using the correct image digest | Use immutable image digests, not mutable tags; enforce digest-pinning in deployment manifests | Engineering inference from container best practices |
| Training-serving skew | Model performs well in evaluation but degrades in production | Preprocessing in training differs from preprocessing in serving | Compare feature distributions between training and serving; check preprocessing code paths | Roll back to previous @champion version | Share preprocessing code between training and serving; add a skew detection test to CI | Engineering inference from MLOps best practices |
| Pipeline drift (pipeline version mismatch) | Production pipeline behaves differently from the tested version | Pipeline IR YAML updated but recurring run not updated to new version | Check recurring run configuration and pipeline version | Update recurring run to the correct pipeline version | Version recurring runs explicitly; alert on version mismatch | Community issue #13933 (awareness only) |
| Failed canary | Canary metrics regress compared to baseline | New model performs worse on real traffic than in evaluation | Compare canary vs baseline metrics in Grafana | Roll back canary to 0% traffic automatically | Set automatic rollback thresholds; require canary observation period before full promotion | Documented from KServe canary rollout documentation |
| Registry and deployment mismatch | Production serves a different model version than @champion | Serving runtime cached old model or deployment not triggered after alias change | Check serving runtime model version against @champion alias target | Trigger model reload or redeploy | Add a post-promotion verification step that checks the deployed model version against @champion | Engineering inference from serving and registry semantics |
| Rollback failure | Rollback command does not restore previous version | Previous model artifact deleted, serving runtime cannot reload, or alias reassignment failed | Check alias target, artifact store, and serving runtime logs | Manually redeploy the previous container image if alias rollback fails | Test rollback in staging regularly; retain previous N model artifacts; never delete the @champion target | Engineering inference from rollback best practices |
GitHub Actions pipeline pattern
CI job: lint, test, and evaluate
Run on every pull request. Gates must pass before merge. This is an architecture pattern, not copy-paste configuration.
Illustrative — not copy-paste production configuration
Illustrative GitHub Actions CI pattern
name: ci on: [pull_request] jobs: lint-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 - run: pip install -r requirements.txt - run: ruff check . - run: mypy . - run: pytest tests/ -v - run: python scripts/run_smoke_training.py - run: python scripts/evaluate_model.py --threshold 0.85CD job: build, deploy to staging, canary
Run on merge to main. Builds the candidate, deploys to staging, then canary with observation.
Illustrative — not copy-paste production configuration
Illustrative GitHub Actions CD pattern
name: cd on: push: branches: [main] jobs: build-and-deploy: needs: ci steps: - run: docker build -t registry/model:${{ github.sha }} . - run: docker push registry/model:${{ github.sha }} - run: kubectl apply -f deploy/staging.yaml - run: python scripts/smoke_test.py --env staging - run: kubectl set image deploy/model-serving model=registry/model:${{ github.sha }} - run: python scripts/canary_observe.py --duration 30mCT trigger: monitoring-driven retraining
Triggered by a monitoring alert or schedule. Creates a retraining candidate that enters the same CI/CD pipeline.
Illustrative — not copy-paste production configuration
Illustrative CT trigger pattern
name: ct-retrain on: schedule: - cron: '0 2 * * 0' # weekly workflow_dispatch: # manual or monitoring-triggered jobs: retrain: steps: - run: python scripts/submit_pipeline.py --trigger ct --reason scheduled # The pipeline run creates a candidate. # The candidate enters CI/CD like any code change. # No shortcut to production.
Tested environment and technical sources
Tool versions
- GitHub Actions: documented (workflow patterns)
- Jenkins: documented (alternative CI controller)
- MLflow: 3.7.0+ (registry and aliases)
- Kubernetes: 1.28+ (deployment and canary)
Known limitations
- GitHub Actions and Jenkins examples are architecture patterns, not copy-paste production configuration. Adapt to your repository's tools, secrets management, and environment conventions.
- CI/CD/CT gate thresholds (evaluation bars, canary durations, slice requirements) must be calibrated for your model and business context. No generic threshold is correct for all models.
- Security configurations (workload identity, OIDC, secret stores) should be verified against your cloud provider's current documentation.
Related lifecycle pages
- MLflow ProductionDesign MLflow as a durable tracking and registry subsystem with promotion gates and rollback.
- End-to-End PipelineOrchestrate reproducible pipelines where Kubeflow, Ray, and MLflow own distinct responsibilities.
- Model ServingChoose and operate a serving runtime based on latency, throughput, and deployment requirements.
- Monitoring & RetrainingConnect infrastructure, data quality, drift, and retraining decisions into a controlled loop.
Sources
The SourceLedger makes technical claims auditable and gives search and retrieval systems explicit source context. It does not guarantee citation, ranking or inclusion.
- https://mlflow.org/docs/latest/ml/model-registry/01Tier 1MLflow
MLflow Model Registry
Version: MLflow 3.x
Aliases are mutable named references to model versions, useful for deployment promotion. OSS registry provides UI + API; Databricks extends with Unity Catalog.
Supports claims:
- model registration and versioning
- model aliases (e.g. @champion)
- model lifecycle: staging, production
- tags for governance
- lineage to MLflow runs
- Databricks Unity Catalog integration for governance
Last verified:
- https://www.kubeflow.org/docs/components/pipelines/concepts/pipeline/02Tier 1Kubeflow
Kubeflow Pipelines — Pipeline Concept
Version: KFP v2
Paraphrased. KFP backend converts pipeline into Kubernetes Pod instructions.
Supports claims:
- pipeline as directed graph of components
- components run in containers on Kubernetes Pods
- control flow: sequential, parallel, conditional, exit handling
- runtime logic: caching, retries, resource requests, node selectors
- IR YAML compilation
Last verified:
- https://github.com/kubeflow/pipelines/issues/1393303Tier 1Kubeflow / GitHub
Kubeflow Pipelines recurring-run version issue #13933
Issue tracker — used for failure-mode awareness.
Supports claims:
- recurring run version mismatch issues reported by community
Last verified:
- https://kserve.github.io/website/04Tier 1KServe
KServe Documentation
Version: KServe v0.20
Paraphrased. Canary rollout, scale-to-zero, and KPA autoscaling are deployment-mode dependent — see kserve-canary, kserve-kpa-autoscaler, and kserve-admin-guide sources. Do not present these as universal KServe behavior.
Supports claims:
- KServe as Kubernetes CRD for serving ML models (InferenceService)
- multi-framework support (TensorFlow, PyTorch, scikit-learn, XGBoost, ONNX)
- control plane: model revision tracking
- data plane: standardized inference protocol
- KServe joined CNCF as incubating project (November 2025)
Last verified:
- https://docs.ray.io/en/latest/serve/production-guide/index.html05Tier 1Ray
Ray Serve — Production Guide
Version: Ray 2.43+
RayService custom resource automatically handles production requirements.
Supports claims:
- production deployment via KubeRay RayService CR on Kubernetes
- serve build / serve deploy / serve status workflow
- config file as single source of truth for deployment
- health checking, status reporting, failure recovery, upgrades handled by RayService
- deploy on VMs as alternative to Kubernetes
Last verified:
- https://nextjs.org/docs/app/getting-started/metadata-and-og-images06Tier 1Next.js
Next.js App Router — Metadata and OG Images
Paraphrased. Repository uses Next.js App Router.
Supports claims:
- Next.js App Router metadata API
- OG image generation
Last verified:
Turn validation rules into an operable release workflow
Implement the pipeline, inspect failed gates, promote a candidate safely and verify that the previous release can be restored.
- Build code, data and model gates.
- Implement controlled promotion.
- Test failure recovery and rollback.