Skip to content

Guides

Complete, annotated examples of workload template plugins. Each example shows all plugin-author annotations in context with inline comments explaining the purpose of each.


Example 1: Basic Web Application

A standard web application workload. Demonstrates actions, connection details, and ingress endpoint control.

scripts/chart/templates/workstation.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ .Values.name }}
  annotations:
    # Declare the workload category for Hubble — shown on the running workload in the Hubble UI.
    # This value can be any string. It must match the value in templates/metadata.yaml:
    #   - metadata.yaml copy → read by Genesis to categorize the template in the catalog
    #   - workstation.yaml copy → read by Hubble to label the active running workload
    juno-innovations.com/workload: "Application"
    # Whitelist which actions users can trigger on this StatefulSet via the Kuiper API.
    kuiper.juno-innovations.com/actions: "restart"
    # Expose static connection details in the Hubble UI alongside this workload's endpoints.
    kuiper.juno-innovations.com/connection: "username={{ .Values.user }},port=8080"
spec:
  selector:
    matchLabels:
      app: {{ .Values.name }}
  template:
    metadata:
      labels:
        app: {{ .Values.name }}
    spec:
      containers:
        - name: app
          image: "{{ .Values.registry }}/{{ .Values.repo }}:{{ .Values.tag }}"
          ports:
            - containerPort: 8080
scripts/chart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ .Values.name }}
spec:
  selector:
    app: {{ .Values.name }}
  ports:
    - port: 8080
      targetPort: 8080
scripts/chart/templates/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ .Values.name }}
  annotations:
    kubernetes.io/ingress.class: nginx
    # Required: authenticate requests through Hubble before allowing access.
    nginx.ingress.kubernetes.io/auth-url: "http://hubble.{{ .Release.Namespace }}.svc.cluster.local:3000/api/auth-workstation/{{ .Values.name }}/"
    nginx.ingress.kubernetes.io/use-regex: "true"
    # Hide internal paths from the Hubble endpoint list.
    kuiper.juno-innovations.com/ingress-hide: "/socket.io"
    # Surface additional deep-link paths as clickable endpoints in Hubble.
    kuiper.juno-innovations.com/ingress-extras: "/app/index.html"
spec:
  rules:
    - host: {{ .Values.host }}
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: {{ .Values.name }}
                port:
                  number: 8080
          - path: /socket.io
            pathType: Prefix
            backend:
              service:
                name: {{ .Values.name }}
                port:
                  number: 8088

Example 2: EC2-backed Remote Desktop

A workload backed by a Crossplane-managed EC2 instance. Demonstrates EC2-specific annotations and the adopt pattern for resources Kuiper creates after launch.

scripts/chart/templates/ec2-instance.yaml
apiVersion: ec2.aws.crossplane.io/v1alpha1
kind: Instance
metadata:
  name: {{ .Values.name }}-ec2
  annotations:
    # Tell Kuiper to auto-create an ExternalName Service exposing these ports
    # once EC2 DNS is available. The service name will be deterministic:
    # {{ .Values.name }}-ec2-svc
    kuiper.juno-innovations.com/expose: "22,3389"

    # Once EC2 DNS is ready, instruct Kuiper to compute and write the
    # connection annotation on this object so Hubble can display it.
    kuiper.juno-innovations.com/aws-remote-connection: "true"

    # Use the private DNS name instead of the public one.
    # Remove this line if the instance should be reached via public DNS.
    kuiper.juno-innovations.com/use-private-dns: "true"

    # Adopt the ExternalName Service that Kuiper will create post-launch.
    # This makes it an owned resource of the workload so it is cleaned up
    # on shutdown. The service name is deterministic — Kuiper names it
    # {{ .Values.name }}-ec2-svc when it processes the expose annotation.
    kuiper.juno-innovations.com/adopt-{{ .Values.name }}-ec2-svc: "Service"
spec:
  forProvider:
    region: {{ .Values.region }}
    instanceType: {{ .Values.instance_type }}
    ami: {{ .Values.ami }}