RayService running our own Ray, image and CUDA
userspace. Batch runs as ephemeral RayJobs in the same namespace.
This page is the list of what has to be true of your cluster first. The
qualification suite checks every item on it and
gives you the report before anything is installed.
Cluster
- KubeRay already installed, either cluster-wide or watching the namespace you grant. Mixpeek does not install it and does not need to own it. This is the one cluster-scoped prerequisite, and Security and RBAC covers why and for how long.
- KubeRay 1.1 or newer. Hard requirement. Below it
submissionMode: HTTPModedoes not exist and batch cannot be submitted at all. - Kubernetes 1.33 or newer is optional. From 1.33 Ray’s autoscaler can use
in-place vertical scaling (
pods/resize), which the kit’s autoscaler Role grants. On older clusters that rule is inert and Ray replaces pods to resize them. - One namespace, and the two Roles from Security and RBAC.
- A
ResourceQuotayou are comfortable with. One ships with the kit. Change the numbers; Mixpeek reads it and sizes batches to fit.
Compute
Node capacity the namespace can schedule onto, with the taints and labels we should target. Tell us the labels and we render them into the deployment rather than assuming yours look like ours. GPU nodes at a known NVIDIA driver baseline for inference and extraction. The suite reports GPU nodes it can see and whether an untolerating pod can actually reach them, which is a different question from whether the nodes exist.The floor, before a single document
The install brings up thirteen Ray Serve applications and holds them warm. Their replica minimums multiply out to 10.1 CPU sitting idle, and 31.9 CPU if every one of them scales to its ceiling under load. That is the engine alone. It does not count the API, Celery, Redis, or the MongoDB you bring. None of the thirteen requests a GPU. The extractors that use one take it through the batch path, not through a warm Serve replica, so a cluster with no GPU nodes brings the whole plane up healthy and then fails at extraction time rather than at install time. Bring the GPU nodes; the qualification suite will tell you whether an untolerating pod can reach them.That 10.1 CPU has to fit on one worker
Read the number above as a per-node requirement, not a cluster total. Serve runs its HTTP proxy on the head only, and the head is started withnum-cpus: 0
because it holds the cluster’s metadata rather than running work. Every one of
the thirteen applications asks for CPU, so none of them can land there. They all
go to a worker.
Four workers of 3 CPU each add up to 12 and schedule nothing, because no single
worker can hold the set. Size the worker group so that one replica has at least
11 CPU and 28 GiB available to Ray, and let autoscaling add replicas above
that for batch work.
Ray takes its logical CPU count from the container’s limit, so requests and
limits both have to reach that number. Requests above limits is refused by the
Kubernetes API server outright, and the pod never appears at all: the RayCluster
still reports RayClusterProvisioned: True, because that condition counts the
pods that exist. Look at the ReplicaFailure condition when a worker is missing.
The applications also ask for a custom Ray resource named serve_node, which the
chart declares on both node groups through rayStartParams. If you replace the
cluster config with your own, carry that declaration across. Without it every
application stays unschedulable, the RayService sits in Initializing with an
empty SERVICE STATUS, and nothing reports an error.
Disk, which is larger than the registry suggests
Two images land on every node that runs Mixpeek: the engine image and the platform image that carries the API, Celery and MVS. A registry size is compressed. What a node needs is the unpacked size, and on our own fixture the platform image measured 4.96 GB in the registry and 14.2 GB on disk, a factor of 2.85. The engine image is larger still, around 15.4 GB unpacked. Pulling the platform image took 130 seconds on a well-connected VM. Size nodes for roughly 60 GB of image storage before their own workload, and expect the first pull on a cold node to take minutes rather than seconds.Egress on first start
An install with no route to the public internet does not come up, and the way it fails is easy to misread as slowness. Three of the thirteen Serve applications fetch their model weights fromhuggingface.co the first time each replica loads: the reranker (2.2 GB), the
SigLIP image encoder (779 MB), and the MiniLM sentence encoder (88 MB). A fourth,
the CLAP audio encoder, fetches a checkpoint from the same host the first time it
sees audio. Two other models, ArcFace and the multilingual E5 encoder, are baked
into the image and need nothing.
So you have two options, and we would rather you pick one deliberately:
- Allow egress to
huggingface.cofrom the Mixpeek namespace, at least on first start. Once a replica has loaded, it does not fetch again. - Ask us for a pre-baked image. The engine image already bakes two of the six model sets by exactly this mechanism, so baking the rest is additive. The four together measure 4.9 GB, which is what it would add to the image.
google__gemini_embedding_2
embeds through Google’s Generative Language and Vertex endpoints, and
universal__api, which backs POST /v1/inference, dispatches to OpenAI, Google
and Anthropic by model name. Neither is on the path for the extractors and
retrievers a standard install uses, so leaving them unreachable does not affect
indexing or search. universal__api also accepts a self-hosted
OpenAI-compatible endpoint, which keeps POST /v1/inference working with no
outbound traffic. Bring the requirement to your deployment conversation if your
environment forbids reaching a hosted model provider.
Storage
Two different things, and it is worth separating them because they fail differently. Object storage is where your index lives. MVS keeps durable state in S3 or GCS, not on a disk. Losing a pod does not lose the index; it loses at most the un-replayed write-ahead window, which MVS keeps in a localemptyDir sized per
shard. That is a deliberate design: the vector store is object-storage-native, and
it is why a node drain is a recovery rather than a restore.
A CSI storage class is still required, for the stateful services beside it.
Redis runs as a StatefulSet with volumeClaimTemplates and needs a real
PersistentVolume. A cluster that cannot provision one cannot run the plane, even
though MVS itself would not have noticed.
- A CSI storage class that provisions persistent volumes surviving pod restarts and rescheduling. The suite writes a nonce from one pod, deletes it, and reads it back from a second pod on the same claim.
- Throughput and IOPS above the floor for your workload size. The suite measures sequential write and read against a stated floor and fails below it. It does not infer the floor from what it observed, because a bound derived from the measurement can never fail.
- Object storage, S3 or GCS, reachable from the namespace. This is the one MVS actually depends on, so treat it as the load-bearing requirement rather than the afterthought its position in this list once implied.
A MongoDB you provide
The chart ships Redis and does not ship MongoDB. Mixpeek stores its metadata in Mongo: objects, collections, batches, retriever definitions, and the six control-plane collections. The API reads its connection string from the Secret you supply at install. So a database has to exist and be reachable from the namespace before the first install, and it is the one prerequisite on this page that is not a property of your cluster.- A MongoDB the namespace can reach, managed or self-run, inside the cluster or outside it. We do not pin a minimum server version: our driver is pymongo 4.9, and what we run and test against is current MongoDB. If you are standing up something older, or a wire-compatible service rather than MongoDB itself, tell us which and we will qualify it rather than guess.
- A connection string in the install Secret. The API takes its whole environment from a Secret, so the URI goes there rather than into chart values.
- Sized for metadata, not for media. Documents are records and references; your video stays in object storage. This database stays small relative to the index.
Networking and identity
- Egress from the namespace to your object storage and to the Mixpeek control plane.
- In-cluster DNS and pod-to-pod routing inside the namespace. A default-deny
NetworkPolicywith no allow rule for us is the common cause of a namespace that looks healthy and cannot talk to itself, and the suite separates that from a DNS failure rather than reporting one verdict for both. - Workload identity if you want Mixpeek’s pods to reach cloud resources without static credentials. GKE Workload Identity, EKS IRSA and AKS Workload Identity are all recognised.
- Image pull access to the Mixpeek engine image, either a pull secret in the namespace or a mirror into a registry your nodes already trust.
Which of your customisations we accept
You asked whether we require customisations or direct control of theRayCluster/RayService objects. We own those objects in the granted namespace,
and this is the honest list of what your platform’s conventions can change about
them.
The mechanism is one sentence: the chart renders the
rayClusterConfig from
values, so anything expressible in a Kubernetes pod template reaches the cluster
unmodified. There is no allowlist to extend.
What turns the chart on, and the one value that must be right
values.yaml is an all-off skeleton. enabled: false for api, celery, mvs, ray, redis
and qdrant, each template gated on its own flag, so a bare helm install ./chart
renders essentially nothing. What turns components on is an install-values overlay
applied with -f. Your deployment ships with an overlay written for your
environment, so the values that govern it are the ones in that file.
Two consequences worth knowing before your first install.
A default written under a disabled component is not a default you get. A storage
class, a node selector or a resource request sitting in values.yaml beneath a
component that ships off is not what your cluster will do. Your overlay is the file
that answers “what will this actually run”, and it is the one to review.
Portability is not evenly distributed across the chart, and it is not readable from
the file names. api.yaml and the four observability templates branch on platform.
ray.yaml, mvs.yaml, celery.yaml, redis.yaml and qdrant.yaml carry no such
branch. Separately, the generator that emits the Ray cluster spec writes Google node
selectors (cloud.google.com/gke-nodepool), so on a non-GKE cluster the node placement
in that spec is rendered data we replace for you rather than a value you override.
Your Ray version is not an input
A Ray cluster runs one image and that image is ours. Your Ray, Python and CUDA versions have no bearing on whether Mixpeek works, because we run our own runtime under your scheduler rather than inside yours. That constraint applies only to the shared-cluster integration, which is scoped per cluster.What stays yours
Node pools, quotas, autoscaler policy, taints and network policy. The qualification suite tests that they stay authoritative: work that must land on your designated pool, work that must be refused for want of a toleration, and work your quota must reject.Teardown
Removing the kit’s objects removes what Mixpeek created. The suite’s--expect-clean mode runs afterwards and fails if residue remains, so the claim
gets checked.
