Chart values¶
Generated from charts/spawnery/values.schema.json -- the schema Helm validates every install and --set against -- with defaults read from charts/spawnery/values.yaml, the chart's own shipped copy.
Helm validates values.yaml and every --set against this before rendering. It exists because without it a wrong value was rejected by the operator's flag parser instead: the container exited at startup with invalid value "30" for flag -startup-deadline, which reaches a cluster as CrashLoopBackOff and names neither the value nor the key. What is validated here is what has actually gone wrong, plus types; the pass-through values (resources, nodeSelector, tolerations, affinity, additionalLabels) are deliberately left open, because a schema that is wrong about them fails an install that would have worked.
Required at the top level: image, operator.
A blank Description is not a gap: the schema describes only what needs it, and leaves a key bare when its name and type already say what it is.
| Key | Type | Default | Description |
|---|---|---|---|
image | object | {repository: ghcr.io/spawnery/spawnery-operator, tag: 0.34.0, digest: '', pullPolicy: IfNotPresent} | One of tag or digest has to name something. With both empty the templates render an image reference ending in a colon, and helm's own error is a YAML parse failure pointing at deployment.yaml rather than at the value that is missing. |
image.repository | string (length >= 1) | ghcr.io/spawnery/spawnery-operator | |
image.tag | string | 0.34.0 | |
image.digest | string (pattern ^$|^[a-z0-9]+:[a-f0-9]{32,}$) | | Empty, or an algorithm-prefixed digest. A bare hex string is the shape somebody reaches for first and it is not what a container reference takes. The value checked in at any tag describes the release before it and structurally cannot describe its own: hack/publish.sh takes it from skopeo copy --digestfile, which exists only once the tag is published, so the commit writing it back is necessarily behind the tag it names. Measured on the RKE2 rollout, where a HelmRelease installing the chart at v0.1.0 ran the tag rather than a digest. A deployment that wants an immutable reference pins it where the deployment is described, not here. |
image.pullPolicy | string (one of: Always, IfNotPresent, Never) | IfNotPresent | |
resources | object | {requests: {cpu: 100m, memory: 128Mi}, limits: {memory: 256Mi}} | |
nodeSelector | object | {} | |
tolerations | array | [] | |
affinity | object | {} | |
networkPolicy | object | {enabled: true} | |
networkPolicy.enabled | boolean | true | |
metrics | object | {serviceMonitor: {enabled: false, additionalLabels: {}, interval: 30s}, prometheusRule: {enabled: false, additionalLabels: {}, caExpiryWarningDays: 90}, dashboard: {enabled: false, labels: {grafana_dashboard: '1'}, annotations: {}}} | |
metrics.serviceMonitor | object | {enabled: false, additionalLabels: {}, interval: 30s} | |
metrics.serviceMonitor.enabled | boolean | false | |
metrics.serviceMonitor.additionalLabels | object | {} | |
metrics.serviceMonitor.interval | string (pattern ^[0-9]+(ms|s|m|h|d|w|y)$) | 30s | A Prometheus duration, which is not a Go one: no fractions and no compound units. |
metrics.dashboard | object | {enabled: false, labels: {grafana_dashboard: '1'}, annotations: {}} | |
metrics.dashboard.enabled | boolean | false | |
metrics.dashboard.labels | map[string]string | {grafana_dashboard: '1'} | |
metrics.dashboard.annotations | map[string]string | {} | |
metrics.prometheusRule | object | {enabled: false, additionalLabels: {}, caExpiryWarningDays: 90} | |
metrics.prometheusRule.enabled | boolean | false | |
metrics.prometheusRule.additionalLabels | object | {} | |
metrics.prometheusRule.caExpiryWarningDays | integer (>= 1) | 90 | |
operator | object | {startupDeadline: 5m, leaderElect: true, allowPluginVolumes: false, allowFileVolumes: false, allowMountVolumes: false, aotCache: false} | |
operator.startupDeadline | string (pattern ^([0-9]+(\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$) | 5m | A Go duration, so it carries a unit: 5m, 20s, 1h30m. A bare number is accepted by YAML and refused by the flag parser at container start, which is the failure this whole file exists for. |
operator.leaderElect | boolean | true | A bool, not a YAML string. yes is a string here, and the flag parser refuses it at container start. |
operator.allowPluginVolumes | boolean | false | A bool, for the reason leaderElect is one. Lets a group name a spec.extraPlugins claim, and only that -- a claim-backed spec.mounts entry has its own switch, allowMountVolumes, since 0.2.x (docs/guides/plugins-from-a-volume.md). Not a security control -- a PersistentVolumeClaim is in the same trust domain as the group naming it. |
operator.allowFileVolumes | boolean | false | A bool, for the reason leaderElect is one. Lets a group name a spec.extraFiles claim whose tree is copied into every server's working directory on start (docs/guides/mounts-and-files.md). Not a security control -- a PersistentVolumeClaim is in the same trust domain as the group naming it. |
operator.allowMountVolumes | boolean | false | A bool, for the reason leaderElect is one. Lets a group's spec.mounts name a PersistentVolumeClaim rather than a ConfigMap or a Secret (docs/guides/mounts-and-files.md). Until 0.2.x this was governed by allowPluginVolumes. Not a security control -- a PersistentVolumeClaim is in the same trust domain as the group naming it. |
operator.aotCache | boolean | false | A bool, for the reason leaderElect is one. Mounts the startup cache published with spawnery's own Purpur images (0.23.0 and later) into their servers as an image volume. Needs Kubernetes with the ImageVolume feature; on a cluster without it every server pod is refused. |
worldSync | object | {enabled: false, namespace: '', image: {repository: ghcr.io/spawnery/spawnery-worldsync, tag: '', digest: ''}, registrarImage: 'registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.18.0', objectStore: {endpoint: '', region: '', bucket: '', prefix: '', credentialsSecret: ''}, hostPath: /var/lib/spawnery/worldsync, snapshotInterval: 5m, nodeSelector: {}, tolerations: [{operator: Exists}], priorityClassName: system-node-critical, resources: {requests: {cpu: 50m, memory: 64Mi}, limits: {memory: 512Mi}}} | Worlds of groups with spec.storage.backend ObjectStore: a CSI driver, a node agent DaemonSet and the operator's --world-sync flags. Enabling it without the endpoint, region, bucket and credentialsSecret fails the render. |
worldSync.enabled | boolean | false | |
worldSync.namespace | string | | Where the node agent DaemonSet runs. It needs privileged pods, so it cannot share a namespace held to the restricted Pod Security level. The chart does not create it. Empty means the release namespace. |
worldSync.image | object | {repository: ghcr.io/spawnery/spawnery-worldsync, tag: '', digest: ''} | |
worldSync.image.repository | string (length >= 1) | ghcr.io/spawnery/spawnery-worldsync | |
worldSync.image.tag | string | | Empty means the chart's appVersion. |
worldSync.image.digest | string (pattern ^$|^[a-z0-9]+:[a-f0-9]{32,}$) | | |
worldSync.registrarImage | string (length >= 1) | registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.18.0 | The csi-node-driver-registrar sidecar that registers the driver with the kubelet. |
worldSync.objectStore | object | {endpoint: '', region: '', bucket: '', prefix: '', credentialsSecret: ''} | |
worldSync.objectStore.endpoint | string | | |
worldSync.objectStore.region | string | | |
worldSync.objectStore.bucket | string | | |
worldSync.objectStore.prefix | string | | A prefix inside the bucket; empty for none. |
worldSync.objectStore.credentialsSecret | string | | A Secret with AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, in both the release namespace (for deletions) and worldSync.namespace. |
worldSync.hostPath | string (length >= 1) | /var/lib/spawnery/worldsync | The node directory for worlds and their snapshots. |
worldSync.snapshotInterval | string (pattern ^([0-9]+(\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$) | 5m | A Go duration, so it carries a unit: 5m, 90s. How often a running member asks for a snapshot: the most play a node loss costs. |
worldSync.nodeSelector | object | {} | |
worldSync.tolerations | array | [{operator: Exists}] | Every taint by default: a game pod scheduled onto a tainted node needs the driver there, or its world volume never mounts. |
worldSync.priorityClassName | string | system-node-critical | Keeps the node agent from being evicted ahead of the game pods whose worlds it holds. Empty means none. |
worldSync.resources | object | {requests: {cpu: 50m, memory: 64Mi}, limits: {memory: 512Mi}} | |
networkNamespaces | array | [] | Namespaces holding a Network, and the forwarding secret in each. Renders a Role and RoleBinding per entry, narrowed with resourceNames to exactly those secrets. Empty means none are rendered and config/rbac/forwarding-secret-reader.yaml is applied by hand instead. |
networkNamespaces[].namespace | string (length >= 1) | The namespace that holds the Network. | |
networkNamespaces[].secrets | array of string (at least 1 item(s)) | The Secret names each Network in that namespace points its forwardingSecretRef at. Required and non-empty: an entry with none would render a Role granting get on every Secret in the namespace, which is what naming them exists to avoid. |