Overview¶
Workload templates are the most complex plugin type. This page covers the complete system — what they are, how the data flows from plugin through the platform to a running workload, and how to author them correctly.
What Is a Workload Template?¶
A workload template is a plugin that defines a reusable workload schema for the Juno platform.
- At install time: Terra installs it as an ArgoCD Application into the
argocdnamespace. No running workload is created. What gets created is a pair of ConfigMaps. - At launch time: A user opens Genesis, picks a workload type, fills in parameters, and submits. Kuiper reads the stored schema, renders the embedded Helm chart with the user's values, and applies the resulting manifests to the cluster.
The key insight: the plugin ships a Helm chart inside a ConfigMap. Genesis reads the schema from it. Kuiper renders it on demand.
Full Data Flow¶
flowchart TD
subgraph AUTHOR["Plugin Author"]
A["plugins/my-template/scripts/chart/"]
B["plugins/my-template/templates/metadata.yaml"]
end
subgraph PACKAGE["Packaging — make package"]
C["tar -czf scripts.tar scripts/\nbase64 encode"]
D["templates/packaged-scripts.yaml\n(generated — do not edit)"]
end
subgraph INSTALL["Install Time — Terra + ArgoCD"]
E["<release>-terra-metadata ConfigMap\n(fields:, description:, kuiper label)"]
F["<release>-scripts-configmap ConfigMap\n(packaged_scripts.base64)"]
end
subgraph CATALOG["Catalog — Genesis"]
G["Lists ConfigMaps with\nkuiper.juno-innovations.com/chart label"]
H["Reads fields: → workload creation UI\nReads packaged_scripts.base64 → stores chart"]
end
subgraph LAUNCH["Launch Time — Kuiper"]
I["User submits workload form in Genesis"]
J["b64decode → tar extract → scripts/chart/"]
K["helm template scripts/chart/ -f user-values.yaml"]
L["kubectl apply rendered manifests"]
end
A --> C
B --> INSTALL
C --> D
D --> F
B --> E
E --> G
F --> G
G --> H
H --> I
I --> J
J --> K
K --> L
Directory Structure¶
scripts/
├── entrypoint.sh # Required for packaging; not executed at launch
└── chart/
├── Chart.yaml
├── values.yaml # All field names from metadata.yaml must exist here
└── templates/
├── workstation.yaml # Primary workload resource (StatefulSet by convention; Crossplane plugins use xr.yaml)
├── service.yaml # ClusterIP Service
└── ingress.yaml # nginx Ingress with Hubble auth
templates/metadata.yaml¶
This ConfigMap does two jobs:
1. Discovery the kuiper.juno-innovations.com/chart label tells Genesis to include this plugin
in the workload catalog.
2. Schema the data.fields: block defines what the user sees in the Genesis workload creation form.
Every field becomes a Helm value passed to scripts/chart/ by Kuiper.
juno-innovations.com/workload Annotation Values¶
The values in the table below are the conventional categories used in the Juno platform, but this
annotation accepts any string. The value in metadata.yaml is read by Genesis to categorize the
template in the workload catalog. The matching value in scripts/chart/templates/ is read by Hubble
to label the active running workload.
| Value | Conventional use |
|---|---|
Application |
General GUI applications |
Terminal |
Shell / terminal workloads |
Workspace |
Full desktop or IDE environments |
Server |
Headless server workloads |
Virtual Machine |
KubeVirt VM workloads |
These are examples — not an exhaustive list. Custom values are valid.
Set this annotation in two places
The juno-innovations.com/workload annotation must appear in both:
templates/metadata.yaml— Genesis uses it to categorize the template in the catalogscripts/chart/templates/workstation.yamlon the StatefulSet — Hubble uses it to display the running workload type
scripts/chart/values.yaml¶
Every field name: in metadata.yaml must exist as a key in scripts/chart/values.yaml.
Kuiper passes user-provided values to Helm as --set key=value. If a key is missing from values.yaml,
Helm rendering fails silently at workload launch time.
Kuiper-Injected Standard Values Reference¶
| Key | Description |
|---|---|
name |
Unique name for this workload instance |
user |
Username of the Juno user who launched the workload |
group |
Primary group of that user |
cpu / memory |
Resource requests from the Genesis launch form |
cpuLimit / memoryLimit |
Resource limits; null means no limit applied |
idx |
Instance index for multi-instance workloads |
guid / puid |
Group ID / user ID of the launching user |
host |
Hostname assigned to this workload at launch time — the same hostname registered with Hubble. Use this to construct the ingress host: rule and to pass the base URL into the container (e.g. via the PREFIX env var) |
session |
Unique session token for this workload instance |
pullSecret |
Image pull secret name if configured in the cluster |
volumeMounts / volumes |
PVC mounts requested at launch time |
env |
User-defined environment variables from the Genesis launch form |
selector |
Label selector injected by Kuiper for resource ownership tracking |
plugins |
Helios plugin script mounts |
_kuiper |
Deprecated. Internal Kuiper metadata — do not read or modify. May be removed in a future platform version. |
Ingress must not use the root path
Juno platform services are served from / on the cluster ingress. A workload template must
not configure its ingress at the root path — doing so will clash with platform services and
break routing for the entire cluster.
Your workload must support a URL prefix (e.g. /{{ .Values.name }}/) or another sub-path
routing strategy. The PREFIX environment variable is the conventional way to pass the base
path into the container — set it from {{ .Values.host }} or your chosen sub-path in
workstation.yaml.
scripts/chart/templates/workstation.yaml¶
This StatefulSet is what Kuiper deploys when a user launches a workload. Key conventions:
- Node affinity — must target nodes with
juno-innovations.com/workstation: "true" - Toleration — must tolerate the
juno-innovations.com/workstation: NoScheduletaint - Annotations —
juno-innovations.com/workloadmust matchmetadata.yaml - Plugin mounts — range over
.Values.pluginsto mount Helios plugin scripts - Standard env vars —
JUNO_WORKSTATION,JUNO_PROJECT,USER,HOME,PREFIX
See plugins/helios/scripts/chart/templates/workstation.yaml for the full reference implementation.
Packaging¶
The entire scripts/ directory (including scripts/chart/) must be packaged into a ConfigMap before
deploying. This is done by:
What it does:
Always repackage after any scripts/ change
templates/packaged-scripts.yaml is a generated file. Editing scripts/ without repackaging
means the old version deploys. ArgoCD gives no error. This is the most common source of bugs.
The 1MiB Limit¶
Kubernetes enforces a 1MiB limit on ConfigMap data. The base64-encoded tarball must fit within this.
make package calls make check-size automatically:
- > 900KB — warning printed
- > 1MiB — error, build blocked
If approaching the limit:
- Remove unnecessary assets from
scripts/assets/ - Remove unused templates from
scripts/chart/templates/ - Avoid adding binaries or large static files to
scripts/
Development Workflow¶
For active workload template development, use watch mode to auto-repackage on every save:
This requires inotifywait (available in the devbox shell).
Creating a Workload Template¶
make new-plugin→ select type3(workload) → select workload category- Edit
terra.yaml— setname,description,category,icon - Edit
templates/metadata.yaml: - Set
description: - Define
fields:schema with all user-facing parameters - Verify
juno-innovations.com/workloadannotation matches intended category - Edit
scripts/chart/values.yaml— add every field frommetadata.yamlas a key - Edit
scripts/chart/templates/workstation.yaml: - Set correct image reference using
{{ .Values.registry }}/{{ .Values.repo }}:{{ .Values.tag }} - Set correct
containerPortand probe ports - Set
juno-innovations.com/workloadannotation to matchmetadata.yaml - Edit
scripts/chart/templates/service.yaml— set correctport/targetPort make package <plugin-name>make check-size <plugin-name>— confirm under 1MiBmake verify— confirm nothing is stalemake test <plugin-name>ormake test-plugin <plugin-name>- Commit
scripts/,templates/metadata.yaml, AND the generatedtemplates/packaged-scripts*.yaml
Common Mistakes¶
| Mistake | Symptom | Fix |
|---|---|---|
fields: name ≠ values.yaml key |
Workload fails at launch; no visible error | Align names exactly |
Forgot make package |
Old workload behavior after deploy | make package <plugin> |
Missing kuiper.juno.../chart label |
Plugin absent from Genesis catalog | Add label to metadata.yaml |
Missing juno-innovations.com/workload annotation |
Not categorized in Hubble | Add to both metadata.yaml and workstation.yaml |
packaged-scripts.yaml hand-edited |
Overwritten on next make package |
Edit scripts/ instead |
Large assets in scripts/ |
Exceeds 1MiB ConfigMap limit | Use make check-size, trim assets |
Next Steps¶
- Configuration Reference — field types, Kuiper annotations, ingress authentication
- Guides — full annotated examples: simple web app, EC2-backed workstation