infra/feast-operator/docs/mlflow-integration.md
When both the Feast operator and MLflow operator are enabled (Managed) on RHOAI/ODH, the Feast operator automatically detects the cluster MLflow instance and enables MLflow experiment tracking for every FeatureStore deployment. This provides:
feast apply and feast materializeThe operator lists all MLflow CRs (mlflow.opendatahub.io/v1) in the cluster and uses the first one with an Available=True or Ready=True condition. The RHOAI MLflow CRD enforces a singleton named mlflow, but the operator uses list-based discovery for forward-compatibility.
If the MLflow CR does not report conditions (older operator versions), auto-discovery will not activate. In that case, set trackingUri explicitly.
No spec.mlflow needed. The operator auto-enables when an Available MLflow CR is detected:
apiVersion: feast.dev/v1
kind: FeatureStore
metadata:
name: my-store
spec:
feastProject: my_project
services:
onlineStore: {}
registry: {}
ui: {}
# mlflow is auto-enabled — no config required
Override defaults or enable additional features:
apiVersion: feast.dev/v1
kind: FeatureStore
metadata:
name: my-store
spec:
feastProject: my_project
services:
onlineStore: {}
registry: {}
ui: {}
mlflow:
enabled: true
trackingUri: "https://custom-mlflow.example.com:8443"
uiUrl: "https://dashboard.example.com/mlflow"
trackingAuth: "kubernetes-namespaced"
autoLog: true
autoLogEntityDf: true
entityDfMaxRows: 50000
logOperations: true
opsExperimentSuffix: "-feast-ops"
Disable MLflow even when the MLflow operator is present:
spec:
mlflow:
enabled: false
| Field | Type | Default | Description |
|---|---|---|---|
enabled | bool | auto-detected | Master switch for MLflow integration |
trackingUri | string | auto-discovered | MLflow tracking server URI (in-cluster, from status.address.url) |
uiUrl | string | auto-discovered | Browser-reachable MLflow URL for Feast UI lineage hyperlinks (from status.url) |
trackingAuth | *string | "kubernetes-namespaced" | Auth method for Feast pods calling MLflow (see Authentication) |
autoLog | *bool | true | Auto-log feature metadata on every retrieval |
autoLogEntityDf | *bool | false | Save entity DataFrame as artifact |
entityDfMaxRows | *int32 | 100000 | Skip artifact for large DataFrames |
logOperations | *bool | false | Log feast apply / materialize to ops experiment |
opsExperimentSuffix | *string | "-feast-ops" | Ops experiment name suffix |
extraConfig | map[string]string | — | Additional YAML fields (coerced to native types) |
The operator injects MLFLOW_TRACKING_AUTH into all Feast pod containers. This env var is consumed by the MLflow Python client's auth plugin system to attach credentials to HTTP requests made to the tracking server.
trackingAuth value | Behavior |
|---|---|
"kubernetes-namespaced" (default) | Reads the pod's SA token and namespace from /var/run/secrets/kubernetes.io/serviceaccount/, sends Authorization: Bearer <token> and X-MLFLOW-WORKSPACE: <namespace> headers. Multi-tenant isolation on RHOAI. |
"kubernetes" | Same as above but without the workspace header. Single-tenant setups. |
"basic" | HTTP Basic auth using MLFLOW_TRACKING_USERNAME / MLFLOW_TRACKING_PASSWORD env vars. |
"bearer" | Static bearer token from MLFLOW_TRACKING_TOKEN env var. |
"" (empty string) | No auth header. For local dev or unprotected MLflow instances. |
No Kubernetes RoleBinding is required for MLflow tracking API access. The MLflow server validates the SA token directly via TokenReview and applies its own access policies.
Lineage appears in the Feast UI (not the RHOAI Dashboard):
oc get route -l app.kubernetes.io/name=<featurestore-name>The RHOAI Dashboard provides navigation to both the Feast UI and the MLflow application tile.
For workbench notebooks to use store.mlflow:
opendatahub.io/mlflow-instance annotation (enables MLflow SDK env injection by the MLflow operator).Then in the notebook:
from feast import FeatureStore
store = FeatureStore(...) # from mounted client config
with store.mlflow.start_run(run_name="training"):
df = store.get_historical_features(...).to_df()
model = train(df)
store.mlflow.log_model(model, "model")
trackingUri in FeatureStore CRstatus.address.url (first Available/Ready CR)MLFLOW_TRACKING_URI environment variable (on workbench pods, injected by MLflow operator)./mlruns)uiUrl in FeatureStore CRMLFLOW_UI_URL environment variablestatus.url (external gateway route)trackingUri (works for local dev where tracking URI is browser-reachable)Available=True or Ready=True condition: discovery returns empty; mlflow stays off./api/mlflow-* returns empty responses; lineage panels are hidden.