From 43f9a8bec2b7a3f39b6701c01b7db50baa05fd5f Mon Sep 17 00:00:00 2001 From: Anton Evseev <78427278+slayoffer@users.noreply.github.com> Date: Wed, 11 Feb 2026 19:39:41 +1000 Subject: [PATCH] feat(helm): TEI reranker and embedding as separate Deployments (#333) Refactor TEI from sidecar (PR #333) to standalone Deployment+Service pairs for independent scaling. Adds embedding support alongside reranker. - New tei-reranker-deployment.yaml and tei-reranker-service.yaml - New tei-embedding-deployment.yaml and tei-embedding-service.yaml - Auto-inject RERANKER/EMBEDDINGS provider and URL env vars on API pod - Config restructured under tei.reranker.* and tei.embedding.* in values - Both disabled by default, opt-in via tei.reranker.enabled / tei.embedding.enabled Co-authored-by: Claude Opus 4.6 --- helm/hindsight/templates/_helpers.tpl | 32 ++++++++ helm/hindsight/templates/api-deployment.yaml | 12 +++ .../templates/tei-embedding-deployment.yaml | 76 ++++++++++++++++++ .../templates/tei-embedding-service.yaml | 17 ++++ .../templates/tei-reranker-deployment.yaml | 76 ++++++++++++++++++ .../templates/tei-reranker-service.yaml | 17 ++++ helm/hindsight/values.yaml | 78 +++++++++++++++++++ 7 files changed, 308 insertions(+) create mode 100644 helm/hindsight/templates/tei-embedding-deployment.yaml create mode 100644 helm/hindsight/templates/tei-embedding-service.yaml create mode 100644 helm/hindsight/templates/tei-reranker-deployment.yaml create mode 100644 helm/hindsight/templates/tei-reranker-service.yaml diff --git a/helm/hindsight/templates/_helpers.tpl b/helm/hindsight/templates/_helpers.tpl index 70d8a421..2abc9081 100644 --- a/helm/hindsight/templates/_helpers.tpl +++ b/helm/hindsight/templates/_helpers.tpl @@ -127,6 +127,38 @@ API URL for control plane {{- printf "http://%s-api:%d" (include "hindsight.fullname" .) (.Values.api.service.port | int) }} {{- end }} +{{/* +TEI reranker labels +*/}} +{{- define "hindsight.tei.reranker.labels" -}} +{{ include "hindsight.labels" . }} +app.kubernetes.io/component: tei-reranker +{{- end }} + +{{/* +TEI reranker selector labels +*/}} +{{- define "hindsight.tei.reranker.selectorLabels" -}} +{{ include "hindsight.selectorLabels" . }} +app.kubernetes.io/component: tei-reranker +{{- end }} + +{{/* +TEI embedding labels +*/}} +{{- define "hindsight.tei.embedding.labels" -}} +{{ include "hindsight.labels" . }} +app.kubernetes.io/component: tei-embedding +{{- end }} + +{{/* +TEI embedding selector labels +*/}} +{{- define "hindsight.tei.embedding.selectorLabels" -}} +{{ include "hindsight.selectorLabels" . }} +app.kubernetes.io/component: tei-embedding +{{- end }} + {{/* Get the name of the secret to use */}} diff --git a/helm/hindsight/templates/api-deployment.yaml b/helm/hindsight/templates/api-deployment.yaml index eefc3945..1255f6cb 100644 --- a/helm/hindsight/templates/api-deployment.yaml +++ b/helm/hindsight/templates/api-deployment.yaml @@ -67,6 +67,18 @@ spec: - name: {{ $key }} value: {{ $value | quote }} {{- end }} + {{- if .Values.tei.reranker.enabled }} + - name: HINDSIGHT_API_RERANKER_PROVIDER + value: "tei" + - name: HINDSIGHT_API_RERANKER_TEI_URL + value: "http://{{ include "hindsight.fullname" . }}-tei-reranker:{{ .Values.tei.reranker.port }}" + {{- end }} + {{- if .Values.tei.embedding.enabled }} + - name: HINDSIGHT_API_EMBEDDINGS_PROVIDER + value: "tei" + - name: HINDSIGHT_API_EMBEDDINGS_TEI_URL + value: "http://{{ include "hindsight.fullname" . }}-tei-embedding:{{ .Values.tei.embedding.port }}" + {{- end }} {{- /* Only use api.secrets when not using existingSecret (for chart-managed secrets) */}} {{- if not .Values.existingSecret }} {{- range $key, $value := .Values.api.secrets }} diff --git a/helm/hindsight/templates/tei-embedding-deployment.yaml b/helm/hindsight/templates/tei-embedding-deployment.yaml new file mode 100644 index 00000000..10690312 --- /dev/null +++ b/helm/hindsight/templates/tei-embedding-deployment.yaml @@ -0,0 +1,76 @@ +{{- if .Values.tei.embedding.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "hindsight.fullname" . }}-tei-embedding + labels: + {{- include "hindsight.tei.embedding.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.tei.embedding.replicaCount }} + selector: + matchLabels: + {{- include "hindsight.tei.embedding.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "hindsight.tei.embedding.selectorLabels" . | nindent 8 }} + spec: + {{- if .Values.serviceAccount.create }} + serviceAccountName: {{ include "hindsight.serviceAccountName" . }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: tei-embedding + securityContext: + {{- toYaml .Values.securityContext | nindent 10 }} + image: "{{ .Values.tei.embedding.image.repository }}:{{ .Values.tei.embedding.image.tag }}" + imagePullPolicy: {{ .Values.tei.embedding.image.pullPolicy }} + args: + - "--model-id" + - {{ .Values.tei.embedding.model | quote }} + - "--hostname" + - "0.0.0.0" + {{- range .Values.tei.embedding.args }} + - {{ . | quote }} + {{- end }} + ports: + - name: http + containerPort: {{ .Values.tei.embedding.port }} + protocol: TCP + env: + - name: PORT + value: {{ .Values.tei.embedding.port | quote }} + {{- range $key, $value := .Values.tei.embedding.env }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + livenessProbe: + {{- toYaml .Values.tei.embedding.livenessProbe | nindent 10 }} + readinessProbe: + {{- toYaml .Values.tei.embedding.readinessProbe | nindent 10 }} + resources: + {{- toYaml .Values.tei.embedding.resources | nindent 10 }} + volumeMounts: + - name: model-cache + mountPath: /data + volumes: + - name: model-cache + emptyDir: {} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/helm/hindsight/templates/tei-embedding-service.yaml b/helm/hindsight/templates/tei-embedding-service.yaml new file mode 100644 index 00000000..dabe88e0 --- /dev/null +++ b/helm/hindsight/templates/tei-embedding-service.yaml @@ -0,0 +1,17 @@ +{{- if .Values.tei.embedding.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "hindsight.fullname" . }}-tei-embedding + labels: + {{- include "hindsight.tei.embedding.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - port: {{ .Values.tei.embedding.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "hindsight.tei.embedding.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/helm/hindsight/templates/tei-reranker-deployment.yaml b/helm/hindsight/templates/tei-reranker-deployment.yaml new file mode 100644 index 00000000..1e8eb77b --- /dev/null +++ b/helm/hindsight/templates/tei-reranker-deployment.yaml @@ -0,0 +1,76 @@ +{{- if .Values.tei.reranker.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "hindsight.fullname" . }}-tei-reranker + labels: + {{- include "hindsight.tei.reranker.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.tei.reranker.replicaCount }} + selector: + matchLabels: + {{- include "hindsight.tei.reranker.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "hindsight.tei.reranker.selectorLabels" . | nindent 8 }} + spec: + {{- if .Values.serviceAccount.create }} + serviceAccountName: {{ include "hindsight.serviceAccountName" . }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: tei-reranker + securityContext: + {{- toYaml .Values.securityContext | nindent 10 }} + image: "{{ .Values.tei.reranker.image.repository }}:{{ .Values.tei.reranker.image.tag }}" + imagePullPolicy: {{ .Values.tei.reranker.image.pullPolicy }} + args: + - "--model-id" + - {{ .Values.tei.reranker.model | quote }} + - "--hostname" + - "0.0.0.0" + {{- range .Values.tei.reranker.args }} + - {{ . | quote }} + {{- end }} + ports: + - name: http + containerPort: {{ .Values.tei.reranker.port }} + protocol: TCP + env: + - name: PORT + value: {{ .Values.tei.reranker.port | quote }} + {{- range $key, $value := .Values.tei.reranker.env }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + livenessProbe: + {{- toYaml .Values.tei.reranker.livenessProbe | nindent 10 }} + readinessProbe: + {{- toYaml .Values.tei.reranker.readinessProbe | nindent 10 }} + resources: + {{- toYaml .Values.tei.reranker.resources | nindent 10 }} + volumeMounts: + - name: model-cache + mountPath: /data + volumes: + - name: model-cache + emptyDir: {} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/helm/hindsight/templates/tei-reranker-service.yaml b/helm/hindsight/templates/tei-reranker-service.yaml new file mode 100644 index 00000000..0f67207e --- /dev/null +++ b/helm/hindsight/templates/tei-reranker-service.yaml @@ -0,0 +1,17 @@ +{{- if .Values.tei.reranker.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "hindsight.fullname" . }}-tei-reranker + labels: + {{- include "hindsight.tei.reranker.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - port: {{ .Values.tei.reranker.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "hindsight.tei.reranker.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/helm/hindsight/values.yaml b/helm/hindsight/values.yaml index cb1ba93f..8dc6eb70 100644 --- a/helm/hindsight/values.yaml +++ b/helm/hindsight/values.yaml @@ -293,6 +293,84 @@ tolerations: [] # Affinity (applied to all components unless overridden per-component) affinity: {} +# TEI (Text Embeddings Inference) - optional standalone deployments +# for reranking and/or embedding models +tei: + reranker: + enabled: false + replicaCount: 1 + image: + repository: ghcr.io/huggingface/text-embeddings-inference + tag: cpu-1.8.3 + pullPolicy: IfNotPresent + model: "cross-encoder/ms-marco-MiniLM-L-6-v2" + port: 8090 + args: + - "--auto-truncate" + env: + PAYLOAD_LIMIT: "10000000" + MAX_CLIENT_BATCH_SIZE: "256" + resources: + limits: + cpu: 2000m + memory: 2Gi + requests: + cpu: 500m + memory: 1Gi + livenessProbe: + httpGet: + path: /health + port: 8090 + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + readinessProbe: + httpGet: + path: /health + port: 8090 + initialDelaySeconds: 15 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 3 + + embedding: + enabled: false + replicaCount: 1 + image: + repository: ghcr.io/huggingface/text-embeddings-inference + tag: cpu-1.8.3 + pullPolicy: IfNotPresent + model: "sentence-transformers/all-MiniLM-L6-v2" + port: 8091 + args: [] + env: + PAYLOAD_LIMIT: "10000000" + MAX_CLIENT_BATCH_SIZE: "256" + resources: + limits: + cpu: 2000m + memory: 2Gi + requests: + cpu: 500m + memory: 1Gi + livenessProbe: + httpGet: + path: /health + port: 8091 + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + readinessProbe: + httpGet: + path: /health + port: 8091 + initialDelaySeconds: 15 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 3 + # Autoscaling autoscaling: enabled: false