Praesto is a lightweight, cloud-native Kubernetes operator that prepares, caches, and mounts AI model artifacts into workloads using reusable ModelCache resources, ReadWriteMany PVCs, downloader Jobs, and admission webhooks for automatic model injection.
Praesto
Kubernetes-native model cache operator, node-agent, and CSI driver for mounting AI model artifacts into workloads.
What is Praesto?
Praesto helps Kubernetes workloads use AI and LLM model artifacts without downloading the same files again and again.
You declare which model you need with a ModelCache. Praesto prepares that cache on the selected Kubernetes nodes, then workloads receive the model as a normal mounted folder. Application containers do not need custom download logic.
The main mode is local CSI mode: a Praesto node-agent downloads public Hugging Face model artifacts into node-local storage, marks the cache as complete, and the CSI driver mounts it into Pods as a read-only volume. From the application point of view, the model is simply available at a path like /models or /model.
Local caches can also be evicted per node after a configured unused TTL. If a new Pod later lands on a node where its cache was evicted, the node-agent rehydrates it on demand and the CSI mount succeeds after the cache is ready again.
Praesto also supports a shared PVC mode. In that mode, Praesto uses a PVC + downloader Job flow for clusters that prefer RWX storage.
Installation
Install Praesto first, then create ModelCache resources and annotated workloads.
Prerequisites
You need:
- a Kubernetes cluster
kubectlhelm- cert-manager installed in the cluster when
webhooks.certManager.enabled=true(default) - for local CSI mode, node-local storage prepared as described below
- for shared PVC mode, a StorageClass that supports
ReadWriteMany
Prepare node local cache storage
For local CSI mode, prepare the cache base path on every node where Praesto may cache models. This is typically a fast local SSD mount:
/var/praesto
Example on each cache-capable node:
sudo mkdir -p /var/praesto
sudo chmod 0775 /var/praesto
If you use a different path, set it in Helm:
localCache:
basePath: /mnt/fast-ssd/praesto
Praesto expects the base path to already exist. The praesto-node-agent DaemonSet creates and owns per-cache directories below it:
<basePath>/<namespace>/<modelcache>
For example:
/var/praesto/praesto-ovms/ovms-distilbert-squad
The namespace directory may remain after cleanup, but Praesto removes the per-model subdirectory when the corresponding ModelCacheNode is deleted.
Deleting a local-mode ModelCache deletes its ModelCacheNode resources. The node-agent finalizer then removes the node-local model directory before the ModelCacheNode disappears.
To run the node-agent only on selected nodes, label those nodes and configure nodeAgent.nodeSelector:
kubectl label node <node-name> praesto.io/cache-node=true
nodeAgent:
nodeSelector:
praesto.io/cache-node: "true"
Make sure the node-agent runs on every node that a local-mode ModelCache.spec.nodeSelector may select.
Install with Helm
Install Praesto with the local chart:
helm install praesto ./charts/praesto \
--namespace praesto-system \
--create-namespace
Pin release images explicitly:
helm install praesto ./charts/praesto \
--namespace praesto-system \
--create-namespace \
--set image.tag=0.6.2 \
--set downloader.image.tag=0.6.2 \
--set csi.image.tag=0.6.2 \
--set nodeAgent.image.tag=0.6.2
The chart can also be published and installed as an OCI Helm package from GHCR:
helm install praesto oci://ghcr.io/federicolepera/praesto/charts/praesto \
--version 0.6.2 \
--namespace praesto-system \
--create-namespace
Wait for Praesto components:
kubectl get pods -n praesto-system
With local CSI mode enabled, you should see the controller manager, CSI node DaemonSet, and node-agent DaemonSet running in praesto-system.
For chart options, see the commented Helm values example and the Chart documentation.
Storage modes
Praesto supports two storage modes. The mode is selected by spec.storage.storageClassName:
- Local CSI mode: the primary mode. Leave
storageClassNameempty. Praesto creates oneModelCacheNodeper selected node; the node-agent downloads the model into node-local storage; the CSI driver mounts the completed cache into Pods. No PV, PVC, or downloader Job is created for this mode. - Shared PVC mode: set
storageClassName. Praesto creates a shared RWX PVC and a downloader Job, then mounts that PVC into Pods. This mode does not useModelCacheNode.
kubectl get modelcache shows the same high-level status for both modes:
NAMESPACE NAME PHASE MODE READY TOTAL PVC DOWNLOAD JOB
default tinyllama-test Downloading PVC 0 1 praesto-tinyllama-test praesto-download-tinyllama-test
praesto-ovms ovms-distilbert-squad Ready Node 1 1
praesto-ovms ovms-vit-food101 Ready Node 1 1
MODE identifies the backend used by the cache. READY and TOTAL summarize cache readiness across the logical cache units: 1/1 for shared PVC mode and one unit per selected node for local CSI mode. PVC and DOWNLOAD JOB are populated only for shared PVC mode.
Minimal local CSI ModelCache:
apiVersion: praesto.praesto.io/v1alpha1
kind: ModelCache
metadata:
name: tinyllama
namespace: default
spec:
source:
huggingface:
repo: TinyLlama/TinyLlama-1.1B-Chat-v1.0
storage:
size: 5Gi
nodeSelector:
praesto.io/cache-node: "true"
Minimal shared PVC ModelCache:
apiVersion: praesto.praesto.io/v1alpha1
kind: ModelCache
metadata:
name: tinyllama-rwx
namespace: default
spec:
source:
huggingface:
repo: TinyLlama/TinyLlama-1.1B-Chat-v1.0
storage:
size: 5Gi
storageClassName: rwx-storage-class
Local CSI mode currently supports public Hugging Face downloads from the node-agent. Hugging Face token/private model support remains available in the PVC downloader Job flow and will be added to local mode later.
For local CSI mode, the node-agent writes cache markers into each model directory:
.praesto-owner
.praesto-manifest.json
.praesto-complete
The CSI driver mounts a cache only after .praesto-complete exists, so workloads do not see partially downloaded models.
See the storage modes documentation for examples and details.
Demo
Praesto includes an OpenVINO Model Server demo: it downloads two OpenVINO-ready models, mounts both into one Pod through the CSI driver, and serves them from a single model server.
See the demo documentation.
Quickstart
For a short end-to-end walkthrough, see the quickstart guide.
Admission Webhooks
Praesto uses admission webhooks for model validation and Pod volume injection.
Mutating Pod webhook
The mutating webhook injects a ready model cache into annotated Pods.
Before creating annotated Pods, enable injection in the workload namespace:
kubectl label namespace <namespace> praesto.io/model-cache-injection=enabled
Namespaces without this label are ignored by the mutating webhook. This keeps unrelated workloads from depending on Praesto webhook availability.
Recommended annotation:
praesto.io/model-mounts: |
[
{"modelCache":"ovms-distilbert-squad","mountPath":"/models/distilbert/1"},
{"modelCache":"ovms-vit-food101","mountPath":"/models/vit/1"}
]
Optional annotations:
praesto.io/target-container: ovms
If the target container is omitted, Praesto mounts the cache into the first container in the Pod spec.
The older single-model annotations are still supported for compatibility, but praesto.io/model-mounts is the preferred form:
praesto.io/model-mounts: |
[
{"modelCache":"tinyllama-test","mountPath":"/models"}
]
The webhook:
- reads the requested
ModelCachefrom the Pod namespace - requires the
ModelCacheto beReady - injects a read-only CSI volume for local CSI mode (
storageClassNameempty) - injects a read-only PVC volume for shared PVC mode (
storageClassNameset)
failurePolicy: Fail inside opt-in namespaces. If Praesto is unavailable, annotated Pods in enabled namespaces are rejected instead of running without their model cache.
Validating ModelCache webhook
The validating webhook checks common ModelCache input errors:
spec.storage.sizeis required and must be greater than zerospec.source.huggingface.repois required- HuggingFace token
secretRef.nameandsecretRef.keymust be configured together specis immutable after creation- in shared PVC mode,
spec.storage.storageClassNamemust reference an existing StorageClass
License
Apache License 2.0. See LICENSE for details.