This repository hosts a public Helm chart for deploying the WEKA App Store Operator and its web UI onto a Kubernetes cluster.
The WEKA App Store is designed to help user to install WEKA designed blueprints for machine learning use cases.
AI blueprints are installed by the operator as Custom Resources (CRs). Multiple Blueprints can be installed into their own namespaces as long as there is enough resources in the Kubernetes Cluster.
Helm repo URL: https://weka.github.io/wekaappstore
Chart name: weka-app-store-operator-chart
- A Kubernetes cluster (v1.24+ recommended)
- A Kubernetes cluster with NVIDIA GPU support
- kubectl configured to point at the target cluster
- Helm v3.10+ installed
- Cluster admin privileges (the chart installs RBAC resources and a CRD by default)
- Add the repo and update your local cache
- helm repo add wekaappstore https://weka.github.io/wekaappstore
- helm repo update
- Inspect available versions (optional)
- helm search repo wekaappstore/weka-app-store-operator-chart --versions
- Install into a dedicated namespace (recommended)
- kubectl create namespace weka-app-store
- helm install weka-app-store wekaappstore/weka-app-store-operator-chart -n weka-app-store
- Verify the deployment
- kubectl get pods -n weka-app-store
- A single pod called weka-app-store-operator should be running
- To check the CRD is installed type kubectl get crd wekaappstores.warp.io
You can override values via --set or a custom values.yaml. The chart exposes these notable options (see weka-app-store-operator-chart/values.yaml for the full list):
- image.repository: Container image repo
- Default: wekachrisjen/weka-app-store-multi-arch
- image.tag: Container image tag
- Default: "v0.2"
- image.pullPolicy: Image pull policy
- Default: IfNotPresent
- service.type: Kubernetes Service type
- Default: ClusterIP (use LoadBalancer or NodePort for external access)
- service.port: Service port
- Default: 80
- serviceAccount.create: Whether to create a ServiceAccount
- Default: true
- serviceAccount.name: Custom SA name (empty lets Helm generate one)
- Default: ""
- serviceAccount.automount: Automount SA token
- Default: true
- rbac.create: Create RBAC resources
- Default: true
- rbac.clusterWide: Grant cluster-wide permissions (ClusterRole/ClusterRoleBinding)
- Default: true
- rbac.clusterRoleName: Custom ClusterRole name
- Default: "" (auto-derived)
- rbac.clusterRole.rules: Base RBAC rules for the operator
- You can add rbac.clusterRole.extraRules to extend without replacing defaults
- customResourceDefinition.create: Create the operator CRD
- Default: true
- autoscaling.enabled: Enable HPA (templates expect values if enabled)
- Default: false
Example: expose the service externally and change the image tag
- helm upgrade --install weka-app-store wekaappstore/weka-app-store-operator-chart
-n weka-app-store
--set service.type=LoadBalancer
--set image.tag=v0.3
Alternatively, create a custom values.yaml and pass -f values.yaml.
The operator performs single-pass ${VAR} substitution over kubernetesManifest: strings and valuesFiles: content (loaded from ConfigMaps and Secrets) before they are applied or merged into Helm values. This makes a single AppStack CR portable across namespaces and environments — the same blueprint deploys into staging, aidp-prod, or aidp-test by changing metadata.namespace and the spec.appStack.variables map, without forking the YAML.
| Syntax | Behavior |
|---|---|
${VAR} |
Substituted with the value of VAR from spec.appStack.variables. Strict — undefined references fail loudly. |
$$ |
Literal dollar sign. Use this when a manifest needs a real $ (for example a database password starting with $). |
${namespace} |
Auto-defaults to the CR's metadata.namespace. You can override by listing namespace: explicitly under spec.appStack.variables. |
undefined ${VAR} |
Raises kopf.PermanentError naming the variable, the component, and the manifest/valuesFiles location. The CR must be fixed and re-applied. |
invalid key (e.g., my-host) |
Rejected at admission by the CRD schema, and again at the operator. Variable names must match the Python identifier pattern [_a-zA-Z][_a-zA-Z0-9]*. |
The example below mirrors the AIDP migration pattern: two components, ${namespace} auto-defaulting, an explicit ${milvusHost} consumed both inside a kubernetesManifest and inside a ConfigMap-loaded valuesFiles reference.
apiVersion: warp.io/v1alpha1
kind: WekaAppStore
metadata:
name: ai-research
namespace: aidp-prod
spec:
appStack:
variables:
milvusHost: milvus.aidp-prod.svc.cluster.local
components:
- name: vector-db
helmChart:
repository: oci://registry.example.com/charts
name: milvus
version: 4.2.1
valuesFiles:
- kind: ConfigMap
name: milvus-values
key: values.yaml
# The ConfigMap above contains:
# externalAccess:
# enabled: true
# host: ${milvusHost}
# which the operator renders to milvus.aidp-prod.svc.cluster.local
# before merging into Helm values.
- name: ingress
kubernetesManifest: |
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ai-research-ingress
namespace: ${namespace}
spec:
rules:
- host: ai-research.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ai-research
port:
number: 80Apply the same blueprint to a different namespace by changing metadata.namespace (and the milvusHost value to match):
metadata:
name: ai-research
namespace: aidp-test
spec:
appStack:
variables:
milvusHost: milvus.aidp-test.svc.cluster.local
components:
# ... unchanged ...Note: Variable values are taken literally — no recursive resolution. The operator runs a single substitution pass;
${...}tokens that appear inside variable VALUES are NOT expanded.
# WRONG (this does NOT work):
spec:
appStack:
variables:
milvusHost: milvus.${namespace}.svc.cluster.local # nested ${} is NOT expanded# CORRECT (use fully-resolved values):
spec:
appStack:
variables:
milvusHost: milvus.aidp-prod.svc.cluster.localIf you have many environments, generate the fully-resolved CR per environment from your own templating tool (Helm chart wrapper, kustomize, sed, etc.) — the operator deliberately stops at single-pass substitution to keep failure modes predictable.
The fields below are operator-control fields and are NOT subject to ${VAR} substitution. Putting ${...} in any of them is a no-op that will silently fail to resolve at deploy time:
helmChart.repository,helmChart.name,helmChart.versionreleaseNametargetNamespacereadinessCheck.*(type,name,namespace,timeout)
Recommendation: Omit targetNamespace and let the operator default to metadata.namespace. Templating is not supported on this field; setting it pins the component to a specific namespace and defeats the portability the variables block provides.
- Undefined variable (e.g.,
${unset}appears in a manifest with no matching key inspec.appStack.variables):kopf.PermanentErroris raised. The error message names the variable, the component, and the source location. The reconcile does NOT retry — the CR must be edited and re-applied. - Missing referenced ConfigMap or Secret (e.g.,
valuesFiles[].namedoes not exist in the cluster yet):kopf.TemporaryError(delay=30)is raised. The operator retries every 30 seconds — useful when the ConfigMap is created after the CR. - Malformed
${...}(e.g.,${},${123}, bare$at end of line):kopf.PermanentErroris raised. The error message names the malformed placeholder. - Invalid variable key (e.g.,
my-hostwith a hyphen):kopf.PermanentErroris raised at the start of reconcile, before any deployment work. Variable names must match[_a-zA-Z][_a-zA-Z0-9]*.
Fetch the latest chart index and upgrade the release:
- helm repo update
- helm upgrade weka-app-store wekaappstore/weka-app-store-operator-chart -n weka-app-store
To upgrade with custom values:
- helm upgrade weka-app-store wekaappstore/weka-app-store-operator-chart -n weka-app-store -f my-values.yaml
Remove all release-managed resources:
- helm uninstall weka-app-store -n weka-app-store
Notes:
- If you installed the CRD via the chart, Helm will remove it with the release when managed through templates. If the CRD remains due to finalizers or external references, you may need to remove finalizers or delete the CRD manually:
- kubectl delete crd wekaappstores.warp.io
- You can also delete the namespace if it was dedicated to this chart:
- kubectl delete namespace weka-app-store
- Check pod events and logs:
- kubectl describe pods -n weka-app-store
- kubectl logs -n weka-app-store deploy/weka-app-store-operator-chart
- Validate RBAC permissions if the operator reports access issues.
- Ensure the CRD exists if the operator manages custom resources:
- kubectl get crd wekaappstores.warp.io
When using AppStack components, you can control how the operator waits for a component to become ready after installation. The operator supports waiting on either pods (default) or deployments using kubectl wait under the hood.
Examples:
-
Wait for a specific deployment by name (recommended when you know the resource name):
appStack: components: - name: envoy-gateway enabled: true helmChart: repository: oci://example.registry/charts name: envoy-gateway version: 1.2.3 readinessCheck: type: deployment name: envoy-gateway namespace: envoy-gateway-system timeout: 300
-
Wait for pods by label selector (default behavior if name is not provided):
appStack: components: - name: my-component enabled: true helmChart: repository: https://example.com/helm name: my-chart version: 0.1.0 readinessCheck: type: pod matchLabels: app.kubernetes.io/instance: my-component app.kubernetes.io/name: my-chart timeout: 300
Notes:
- If
readinessCheck.nameis set, the operator waits fortype/namein the specified namespace (or the component targetNamespace if omitted). - If
nameis not set, the operator uses the selector (or matchLabels) to wait for the corresponding resource(s). For many Helm charts the operator auto-derives a good default selector when none is supplied. - Supported types:
pod,deployment,statefulset,job.
For maintainers who need to publish a new chart version to GitHub Pages under docs/:
- Bump version in weka-app-store-operator-chart/Chart.yaml
- Package the chart:
- helm package weka-app-store-operator-chart -d docs/
- Rebuild the repo index (update the URL to your GitHub Pages path if it changes):
- helm repo index docs --url https://weka.github.io/wekaappstore
- Commit and push docs/ (including the new .tgz and updated index.yaml) to the default branch
- Consumers can then helm repo update and install the new version