Skip to content

[FEATURE] Prefetch a Model to cache without an InferenceService (eager/standalone download) #904

Description

@Defilan

Feature Description

Allow a Model to be prefetched (downloaded into a cache) on declaration, independent of any InferenceService. Today a Model with a remote source (https://…, hf://…) is only a declaration: nothing is fetched until an InferenceService serving it spins up a model-downloader init container. A Model with no serving workload sits Ready having downloaded nothing.

Problem Statement

As an operator, I want to declare a Model and have its artifact pulled to the node cache ahead of time, so that the first InferenceService serves immediately and I can stage/validate large GGUFs without standing up a serving pod.

Two concrete pain points:

  • Surprise: kubectl apply a Model with a HuggingFace URL, see it go Ready, assume it's cached — but it isn't. The download only happens lazily at first serve.
  • No first-class staging: prefetching a 20–30 GB GGUF today requires hand-rolling a download Job + PVC and switching the source to pvc://… (this is how every Strix/AMD model is staged). That's exactly the manual loader-Job dance the operator could own.

Proposed Solution

A prefetch/refresh switch on Model that makes the operator run a download Job (the same init-container logic, hoisted to a standalone Job) into the model cache when the Model is created/updated, and reflect progress in status.

Example YAML:

apiVersion: inference.llmkube.dev/v1alpha1
kind: Model
metadata:
  name: qwopus36-mtp-q6k
spec:
  format: gguf
  source: https://huggingface.co/.../Qwopus3.6-35B-A3B-Coder-MTP-Q6_K.gguf
  quantization: Q6_K
  prefetch: true            # operator pulls to cache now, no InferenceService required
  hardware:
    gpu: { enabled: true, vendor: amd, runtime: vulkan }
status:
  phase: Downloading        # -> Cached
  cache: { pvc: qwopus36-mtp-q6k-model-cache, progressBytes: 18253611008, totalBytes: 31300000000 }

Then status.phase: Cached is a real readiness signal, and an InferenceService referencing it serves with a cache hit.

Alternatives Considered

  • Status quo (manual loader Job + pvc://): works but is undocumented tribal knowledge and easy to get wrong (PVC sizing, file layout, node placement, taint tolerations).
  • Eager-by-default: make every remote Model prefetch automatically. Simpler API but pulls artifacts you may never serve; an opt-in prefetch field is safer.

Additional Context

  • Download logic today lives in the InferenceService init container (internal/controller/model_storage.go, model-downloader), keyed off the serving pod — there is no Model-level download path.
  • Related issues: [BUG] hostpath PVC provisioning blocked on tainted GPU nodes (breaks AMD/Vulkan model staging) #850 — on AMD/Vulkan nodes the serve-time download is broken anyway (the cache PVC can't provision on the devic.es/dri-render-tainted node), so prefetch + a properly-tolerated download Job would also be the natural place to fix AMD staging.
  • Workaround in use: a standalone curlimages/curl Job (with the GPU-taint toleration) downloading into a pre-bound PVC, then a pvc:// source.

Priority

  • Medium - Nice to have

Willingness to Contribute

  • Yes, I can submit a PR
  • Yes, I can help test

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions