From cefa75545a7bccd0fc143b660c3a62ca0ba284a1 Mon Sep 17 00:00:00 2001 From: Byeonghoon Yoo Date: Tue, 7 Apr 2026 16:14:09 +0900 Subject: [PATCH] feat(helm): add persistent volume for local model cache (#861) * feat(helm): add persistent volume for local model cache When using local reranker (e.g., BAAI/bge-reranker-v2-m3) or local embedding models, the models are downloaded to /home/hindsight/.cache on every pod restart, causing slow startup and unnecessary bandwidth. Add optional persistent volume support: - api: PVC mounted at /home/hindsight/.cache - worker: volumeClaimTemplate (StatefulSet) at same path Disabled by default. Enable via: api.persistence.modelCache.enabled: true worker.persistence.modelCache.enabled: true Closes #860 Co-Authored-By: Claude Opus 4.6 (1M context) * feat(helm): add extraVolumes and extraVolumeMounts for api and worker Allow users to mount arbitrary volumes (configMaps, secrets, emptyDir, etc.) into api and worker pods via values, following common helm chart library conventions. Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- helm/hindsight/templates/api-deployment.yaml | 21 ++++++++ .../templates/api-model-cache-pvc.yaml | 21 ++++++++ .../templates/worker-statefulset.yaml | 32 +++++++++++ helm/hindsight/values.yaml | 53 +++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 helm/hindsight/templates/api-model-cache-pvc.yaml diff --git a/helm/hindsight/templates/api-deployment.yaml b/helm/hindsight/templates/api-deployment.yaml index 1255f6cb..36b37f35 100644 --- a/helm/hindsight/templates/api-deployment.yaml +++ b/helm/hindsight/templates/api-deployment.yaml @@ -95,6 +95,27 @@ spec: {{- toYaml .Values.api.readinessProbe | nindent 10 }} resources: {{- toYaml .Values.api.resources | nindent 10 }} + {{- if or .Values.api.persistence.modelCache.enabled .Values.api.extraVolumeMounts }} + volumeMounts: + {{- if .Values.api.persistence.modelCache.enabled }} + - name: model-cache + mountPath: /home/hindsight/.cache + {{- end }} + {{- with .Values.api.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if or .Values.api.persistence.modelCache.enabled .Values.api.extraVolumes }} + volumes: + {{- if .Values.api.persistence.modelCache.enabled }} + - name: model-cache + persistentVolumeClaim: + claimName: {{ include "hindsight.fullname" . }}-api-model-cache + {{- end }} + {{- with .Values.api.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} + {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/helm/hindsight/templates/api-model-cache-pvc.yaml b/helm/hindsight/templates/api-model-cache-pvc.yaml new file mode 100644 index 00000000..4e83e397 --- /dev/null +++ b/helm/hindsight/templates/api-model-cache-pvc.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.api.enabled .Values.api.persistence.modelCache.enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "hindsight.fullname" . }}-api-model-cache + labels: + {{- include "hindsight.api.labels" . | nindent 4 }} + {{- with .Values.api.persistence.modelCache.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + accessModes: + {{- toYaml .Values.api.persistence.modelCache.accessModes | nindent 4 }} + {{- if .Values.api.persistence.modelCache.storageClass }} + storageClassName: {{ .Values.api.persistence.modelCache.storageClass }} + {{- end }} + resources: + requests: + storage: {{ .Values.api.persistence.modelCache.size }} +{{- end }} diff --git a/helm/hindsight/templates/worker-statefulset.yaml b/helm/hindsight/templates/worker-statefulset.yaml index 85cff9f6..d0c1d211 100644 --- a/helm/hindsight/templates/worker-statefulset.yaml +++ b/helm/hindsight/templates/worker-statefulset.yaml @@ -95,6 +95,16 @@ spec: {{- toYaml .Values.worker.readinessProbe | nindent 10 }} resources: {{- toYaml .Values.worker.resources | nindent 10 }} + {{- if or .Values.worker.persistence.modelCache.enabled .Values.worker.extraVolumeMounts }} + volumeMounts: + {{- if .Values.worker.persistence.modelCache.enabled }} + - name: model-cache + mountPath: /home/hindsight/.cache + {{- end }} + {{- with .Values.worker.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} @@ -107,4 +117,26 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} + {{- with .Values.worker.extraVolumes }} + volumes: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- if .Values.worker.persistence.modelCache.enabled }} + volumeClaimTemplates: + - metadata: + name: model-cache + {{- with .Values.worker.persistence.modelCache.annotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + accessModes: + {{- toYaml .Values.worker.persistence.modelCache.accessModes | nindent 8 }} + {{- if .Values.worker.persistence.modelCache.storageClass }} + storageClassName: {{ .Values.worker.persistence.modelCache.storageClass }} + {{- end }} + resources: + requests: + storage: {{ .Values.worker.persistence.modelCache.size }} + {{- end }} {{- end }} diff --git a/helm/hindsight/values.yaml b/helm/hindsight/values.yaml index 8dc6eb70..29c1ff99 100644 --- a/helm/hindsight/values.yaml +++ b/helm/hindsight/values.yaml @@ -67,6 +67,33 @@ api: # Pod affinity/anti-affinity (overrides global affinity for this component) # affinity: {} + # Persistent volume for local model cache (reranker, embeddings) + # Models are downloaded to /home/hindsight/.cache on first use. + # Without persistence, models are re-downloaded on every pod restart. + persistence: + modelCache: + enabled: false + size: 5Gi + storageClass: "" + accessModes: + - ReadWriteOnce + annotations: {} + + # Extra volume mounts for the api container + # e.g. + # extraVolumeMounts: + # - name: my-volume + # mountPath: /mnt/my-volume + extraVolumeMounts: [] + + # Extra volumes for the api pod + # e.g. + # extraVolumes: + # - name: my-volume + # configMap: + # name: my-configmap + extraVolumes: [] + # Environment variables env: #HINDSIGHT_API_LLM_PROVIDER: "groq" @@ -140,6 +167,32 @@ worker: # Pod affinity/anti-affinity (overrides global affinity for this component) # affinity: {} + # Persistent volume for local model cache (reranker, embeddings) + # Uses volumeClaimTemplates since worker is a StatefulSet. + persistence: + modelCache: + enabled: false + size: 5Gi + storageClass: "" + accessModes: + - ReadWriteOnce + annotations: {} + + # Extra volume mounts for the worker container + # e.g. + # extraVolumeMounts: + # - name: my-volume + # mountPath: /mnt/my-volume + extraVolumeMounts: [] + + # Extra volumes for the worker pod + # e.g. + # extraVolumes: + # - name: my-volume + # configMap: + # name: my-configmap + extraVolumes: [] + # Secret environment variables (inherited from api.secrets if not specified) secrets: {}