Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions deploy/helm/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
16 changes: 16 additions & 0 deletions deploy/helm/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: v2
name: evidently-ui
description: A Helm chart for Evidently AI's UI
type: application
version: 0.1.0
appVersion: "0.7.20"
keywords:
- evidently
- mlops
- monitoring
- data-quality
- data-drift
home: https://evidentlyai.com
sources:
- https://github.com/evidentlyai/evidently
maintainers: []
39 changes: 39 additions & 0 deletions deploy/helm/templates/NOTES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Evidently UI has been deployed.

{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
URL: http{{ if $.Values.ingress.tls }}s{{ end }}://{{ .host }}
{{- end }}
{{- else if and .Values.httpRoute.enabled .Values.httpRoute.parentRefs }}
{{- if .Values.httpRoute.hostnames }}
URL: https://{{ index .Values.httpRoute.hostnames 0 }}
{{- else }}
URL: set via your Gateway / virtual host
{{- end }}
{{- else }}
kubectl port-forward svc/{{ include "evidently-ui.fullname" . }} 8000:{{ .Values.service.port }}
Then open http://localhost:8000
{{- end }}

{{- if .Values.s3.enabled }}

S3 workspace: s3://{{ .Values.s3.bucketName }}/{{ .Values.s3.path }}
Endpoint: {{ .Values.s3.endpointUrl }}

To use S3 you must provide credentials in one of these ways:
1. Install with inline creds:
helm upgrade --install evidently-ui . --set s3.accessKey="YOUR_ACCESS_KEY" --set s3.secretKey="YOUR_SECRET_KEY"
2. Use an existing Secret (e.g. from Vault or external-secrets): set in values
s3.existingSecret:
name: "your-s3-secret"
accessKeyKey: "access-key" # optional, default: access-key
secretKeyKey: "secret-key" # optional, default: secret-key
3. Create a secret, then install with existingSecret:
kubectl create secret generic evidently-ui-s3 --from-literal=access-key=... --from-literal=secret-key=...
helm upgrade --install evidently-ui . --set s3.existingSecret.name=evidently-ui-s3

Without valid S3 credentials the UI pod will fail to start.
{{- else }}

Workspace: local path /app/workspace (ensure persistence is enabled or use a volume).
{{- end }}
80 changes: 80 additions & 0 deletions deploy/helm/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "evidently-ui.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "evidently-ui.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "evidently-ui.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "evidently-ui.labels" -}}
helm.sh/chart: {{ include "evidently-ui.chart" . }}
{{ include "evidently-ui.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "evidently-ui.selectorLabels" -}}
app.kubernetes.io/name: {{ include "evidently-ui.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "evidently-ui.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "evidently-ui.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

{{/*
Workspace path: s3, simplecache::s3, or local
*/}}
{{- define "evidently-ui.workspacePath" -}}
{{- if .Values.s3.enabled -}}
{{- if (index (.Values.s3.cache | default dict) "enabled") }}simplecache::{{ end }}s3://{{ .Values.s3.bucketName }}/{{ .Values.s3.path }}
{{- else -}}
/app/workspace
{{- end -}}
{{- end }}

{{/*
Whether S3 cache is enabled
*/}}
{{- define "evidently-ui.s3CacheEnabled" -}}
{{- (index (.Values.s3.cache | default dict) "enabled") -}}
{{- end }}
230 changes: 230 additions & 0 deletions deploy/helm/templates/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "evidently-ui.fullname" . }}
labels:
{{- include "evidently-ui.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.autoscaling.enabled | ternary .Values.autoscaling.minReplicas .Values.replicaCount }}
selector:
matchLabels:
{{- include "evidently-ui.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "evidently-ui.selectorLabels" . | nindent 8 }}
{{- if .Values.podAnnotations }}
annotations:
{{- toYaml .Values.podAnnotations | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "evidently-ui.serviceAccountName" . }}
{{- if .Values.podSecurityContext }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
{{- end }}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.s3.enabled }}
initContainers:
- name: create-s3-workspace
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
command: ["python3", "-c"]
args:
- |
import sys
import traceback
path = '{{ include "evidently-ui.workspacePath" . }}'
print(f'Creating workspace at {path}...', flush=True)
try:
from evidently.ui.workspace import Workspace
ws = Workspace.create(path)
print(f'Workspace ready: {path} ({len(ws.list_projects())} projects)', flush=True)
except Exception as e:
print(f'ERROR: {e}', file=sys.stderr, flush=True)
traceback.print_exc(file=sys.stderr)
sys.exit(1)
env:
- name: FSSPEC_S3_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.s3.existingSecret.name | default (printf "%s-s3" (include "evidently-ui.fullname" .)) }}
key: {{ .Values.s3.existingSecret.accessKeyKey | default "access-key" }}
- name: FSSPEC_S3_SECRET
valueFrom:
secretKeyRef:
name: {{ .Values.s3.existingSecret.name | default (printf "%s-s3" (include "evidently-ui.fullname" .)) }}
key: {{ .Values.s3.existingSecret.secretKeyKey | default "secret-key" }}
- name: FSSPEC_S3_ENDPOINT_URL
value: {{ .Values.s3.endpointUrl | quote }}
{{- if .Values.s3.region }}
- name: AWS_DEFAULT_REGION
value: {{ .Values.s3.region | quote }}
{{- end }}
{{- if .Values.s3.addressingStyle }}
- name: AWS_S3_ADDRESSING_STYLE
value: {{ .Values.s3.addressingStyle | quote }}
{{- end }}
{{- if .Values.evidentlyDebug }}
- name: EVIDENTLY_DEBUG
value: "1"
{{- end }}
- name: HOME
value: "/tmp"
- name: XDG_CONFIG_HOME
value: "/tmp"
{{- if (index (.Values.s3.cache | default dict) "enabled") }}
- name: FSSPEC_simplecache_cache_storage
value: {{ (.Values.s3.cache | default dict).storagePath | default "/app/s3-cache" | quote }}
{{- end }}
{{- if .Values.initContainersResources }}
resources:
{{- toYaml .Values.initContainersResources | nindent 10 }}
{{- end }}
{{- if (index (.Values.s3.cache | default dict) "enabled") }}
volumeMounts:
- name: s3-cache
mountPath: {{ (.Values.s3.cache | default dict).storagePath | default "/app/s3-cache" }}
{{- end }}
{{- end }}
containers:
- name: evidently-ui
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
command: ["evidently"]
args:
- "ui"
- "--workspace"
- {{ include "evidently-ui.workspacePath" . | quote }}
- "--port"
- "8000"
- "--host"
- "0.0.0.0"
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
env:
{{- if .Values.s3.enabled }}
- name: FSSPEC_S3_KEY
valueFrom:
secretKeyRef:
name: {{ .Values.s3.existingSecret.name | default (printf "%s-s3" (include "evidently-ui.fullname" .)) }}
key: {{ .Values.s3.existingSecret.accessKeyKey | default "access-key" }}
- name: FSSPEC_S3_SECRET
valueFrom:
secretKeyRef:
name: {{ .Values.s3.existingSecret.name | default (printf "%s-s3" (include "evidently-ui.fullname" .)) }}
key: {{ .Values.s3.existingSecret.secretKeyKey | default "secret-key" }}
- name: FSSPEC_S3_ENDPOINT_URL
value: {{ .Values.s3.endpointUrl | quote }}
{{- if .Values.s3.region }}
- name: AWS_DEFAULT_REGION
value: {{ .Values.s3.region | quote }}
{{- end }}
{{- if .Values.s3.addressingStyle }}
- name: AWS_S3_ADDRESSING_STYLE
value: {{ .Values.s3.addressingStyle | quote }}
{{- end }}
- name: EVIDENTLY_WORKSPACE
value: {{ include "evidently-ui.workspacePath" . | quote }}
{{- if .Values.evidentlyDebug }}
- name: EVIDENTLY_DEBUG
value: "1"
{{- end }}
- name: HOME
value: "/tmp"
- name: XDG_CONFIG_HOME
value: "/tmp"
{{- if (index (.Values.s3.cache | default dict) "enabled") }}
- name: FSSPEC_simplecache_cache_storage
value: {{ (.Values.s3.cache | default dict).storagePath | default "/app/s3-cache" | quote }}
{{- end }}
{{- end }}
{{- with .Values.envVars }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.startupProbe }}
startupProbe:
httpGet:
path: {{ .Values.startupProbe.httpGet.path }}
port: {{ .Values.startupProbe.httpGet.port }}
{{- if .Values.startupProbe.initialDelaySeconds }}
initialDelaySeconds: {{ .Values.startupProbe.initialDelaySeconds }}
{{- end }}
{{- if .Values.startupProbe.periodSeconds }}
periodSeconds: {{ .Values.startupProbe.periodSeconds }}
{{- end }}
{{- if .Values.startupProbe.timeoutSeconds }}
timeoutSeconds: {{ .Values.startupProbe.timeoutSeconds }}
{{- end }}
{{- if .Values.startupProbe.failureThreshold }}
failureThreshold: {{ .Values.startupProbe.failureThreshold }}
{{- end }}
{{- end }}
{{- if .Values.livenessProbe }}
livenessProbe:
httpGet:
path: {{ .Values.livenessProbe.httpGet.path }}
port: {{ .Values.livenessProbe.httpGet.port }}
{{- if .Values.livenessProbe.initialDelaySeconds }}
initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }}
{{- end }}
{{- if .Values.livenessProbe.periodSeconds }}
periodSeconds: {{ .Values.livenessProbe.periodSeconds }}
{{- end }}
{{- if .Values.livenessProbe.timeoutSeconds }}
timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }}
{{- end }}
{{- if .Values.livenessProbe.failureThreshold }}
failureThreshold: {{ .Values.livenessProbe.failureThreshold }}
{{- end }}
{{- end }}
{{- if .Values.readinessProbe }}
readinessProbe:
httpGet:
path: {{ .Values.readinessProbe.httpGet.path }}
port: {{ .Values.readinessProbe.httpGet.port }}
{{- if .Values.readinessProbe.initialDelaySeconds }}
initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }}
{{- end }}
{{- if .Values.readinessProbe.periodSeconds }}
periodSeconds: {{ .Values.readinessProbe.periodSeconds }}
{{- end }}
{{- if .Values.readinessProbe.timeoutSeconds }}
timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }}
{{- end }}
{{- if .Values.readinessProbe.failureThreshold }}
failureThreshold: {{ .Values.readinessProbe.failureThreshold }}
{{- end }}
{{- end }}
{{- if .Values.resources }}
resources:
{{- toYaml .Values.resources | nindent 10 }}
{{- end }}
{{- if or (and .Values.persistence.enabled (not .Values.s3.enabled)) (index (.Values.s3.cache | default dict) "enabled") }}
volumeMounts:
{{- if and .Values.persistence.enabled (not .Values.s3.enabled) }}
- name: workspace-storage
mountPath: {{ .Values.persistence.mountPath }}
{{- end }}
{{- if (index (.Values.s3.cache | default dict) "enabled") }}
- name: s3-cache
mountPath: {{ (.Values.s3.cache | default dict).storagePath | default "/app/s3-cache" }}
{{- end }}
{{- end }}
{{- if or (and .Values.persistence.enabled (not .Values.s3.enabled)) (index (.Values.s3.cache | default dict) "enabled") }}
volumes:
{{- if and .Values.persistence.enabled (not .Values.s3.enabled) }}
- name: workspace-storage
persistentVolumeClaim:
claimName: {{ .Values.persistence.existingClaim | default (include "evidently-ui.fullname" .) }}
{{- end }}
{{- if (index (.Values.s3.cache | default dict) "enabled") }}
- name: s3-cache
emptyDir: {}
{{- end }}
{{- end }}
Loading