feat(helm): expose priorityClassName and topologySpreadConstraints

The gateway pod template exposes nodeSelector, affinity and tolerations but
not priorityClassName or topologySpreadConstraints. Operators who need
either have to fork the chart or mutate the rendered output out-of-band.

Add two optional passthroughs:

- priorityClassName: the gateway is a control-plane component. When it shares
  nodes with the workloads it serves, the default priority gives it no
  advantage under node pressure, so a local capacity crunch can evict it and
  widen into a fleet-wide outage.
- topologySpreadConstraints: spread replicas across zones or nodes. Only
  affinity was available, which is a blunter tool for even spreading.

Both go in the shared gatewayPodTemplate, so they apply identically to the
statefulset and deployment workload shapes. Both render only when set; a
default render is byte-identical to before this change.

The data volume size/StorageClass passthroughs from the original revision are
dropped: upstream now provides them as server.dataStorageSize and
server.dataStorageClass.

Signed-off-by: Bryce Wilkinson <22760097+bjw123@users.noreply.github.com>
This commit is contained in:
Bryce Wilkinson
2026-10-22 14:16:41 +03:00
parent 39d95b42cb
commit 69ec36a68f
4 changed files with 99 additions and 0 deletions
+2
View File
@@ -461,6 +461,7 @@ discovery endpoint or its TLS CA.
| podLabels | object | `{}` | Extra labels to add to the gateway pod. |
| podLifecycle.terminationGracePeriodSeconds | int | `30` | Maximum time, in seconds, Kubernetes waits for the gateway to exit before killing it. The gateway exits as soon as shutdown completes; the limit covers supervisor session cleanup and draining queued OCSF records. |
| podSecurityContext.fsGroup | int | `1000` | fsGroup assigned to the gateway pod. |
| priorityClassName | string | `""` | PriorityClass for the gateway pod. The gateway is a control-plane component; when it shares nodes with the workloads it serves, the default priority gives it no advantage under node pressure. Empty = omit the field. |
| probes.liveness.failureThreshold | int | `3` | Liveness probe failure threshold before the container is restarted. |
| probes.liveness.initialDelaySeconds | int | `2` | Liveness probe initial delay, in seconds. |
| probes.liveness.periodSeconds | int | `5` | Liveness probe period, in seconds. |
@@ -592,6 +593,7 @@ discovery endpoint or its TLS CA.
| supervisor.podSecurityContext.seccompProfile.type | string | `"RuntimeDefault"` | Seccomp profile applied to the shared supervisor pod. |
| supervisor.sandboxRuntime.boundaryPort | int | `5500` | Workload boundary TLS listener port. |
| tolerations | list | `[]` | Tolerations for the gateway pod. |
| topologySpreadConstraints | list | `[]` | Topology spread constraints for the gateway pod, used to spread replicas across zones or nodes. Empty = omit the field. |
| upstreamProxy | object | `{"authAllowInsecure":false,"authSecret":{"key":"","name":""},"caBundle":{"configMapName":"","key":"ca.crt"},"connectByHostname":false,"noProxy":"","url":""}` | Operator-owned corporate forward proxy for policy-approved TLS egress from Kubernetes sandboxes. The workload cannot select or override it. |
| upstreamProxy.authAllowInsecure | bool | `false` | Required when authSecret is configured because Basic auth to an HTTP proxy is cleartext. |
| upstreamProxy.authSecret.key | string | `""` | Secret key containing the proxy credential. |
@@ -307,6 +307,9 @@ spec:
{{- with .Values.server.extraVolumes }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.priorityClassName }}
priorityClassName: {{ . }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 4 }}
@@ -319,4 +322,8 @@ spec:
tolerations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
@@ -0,0 +1,81 @@
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
suite: gateway scheduling fields
templates:
- templates/gateway-config.yaml
- templates/statefulset.yaml
- templates/deployment.yaml
release:
name: openshell
namespace: my-namespace
tests:
# priorityClassName — shared pod template, so both workload shapes
- it: omits priorityClassName by default on the StatefulSet
template: templates/statefulset.yaml
asserts:
- notExists:
path: spec.template.spec.priorityClassName
- it: sets priorityClassName on the StatefulSet when configured
template: templates/statefulset.yaml
set:
priorityClassName: system-cluster-critical
asserts:
- equal:
path: spec.template.spec.priorityClassName
value: system-cluster-critical
- it: sets priorityClassName on the Deployment when configured
template: templates/deployment.yaml
set:
workload.kind: deployment
server.externalDbSecret: openshell-db
priorityClassName: system-cluster-critical
asserts:
- equal:
path: spec.template.spec.priorityClassName
value: system-cluster-critical
# topologySpreadConstraints — shared pod template, so both workload shapes
- it: omits topologySpreadConstraints by default on the StatefulSet
template: templates/statefulset.yaml
asserts:
- notExists:
path: spec.template.spec.topologySpreadConstraints
- it: sets topologySpreadConstraints on the StatefulSet when configured
template: templates/statefulset.yaml
set:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/name: openshell
asserts:
- equal:
path: spec.template.spec.topologySpreadConstraints[0].maxSkew
value: 1
- equal:
path: spec.template.spec.topologySpreadConstraints[0].topologyKey
value: topology.kubernetes.io/zone
- equal:
path: spec.template.spec.topologySpreadConstraints[0].whenUnsatisfiable
value: DoNotSchedule
- it: sets topologySpreadConstraints on the Deployment when configured
template: templates/deployment.yaml
set:
workload.kind: deployment
server.externalDbSecret: openshell-db
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
asserts:
- equal:
path: spec.template.spec.topologySpreadConstraints[0].topologyKey
value: kubernetes.io/hostname
+9
View File
@@ -322,6 +322,15 @@ tolerations: []
# -- Affinity rules for the gateway pod.
affinity: {}
# -- PriorityClass for the gateway pod. The gateway is a control-plane
# component; when it shares nodes with the workloads it serves, the default
# priority gives it no advantage under node pressure. Empty = omit the field.
priorityClassName: ""
# -- Topology spread constraints for the gateway pod, used to spread replicas
# across zones or nodes. Empty = omit the field.
topologySpreadConstraints: []
# -- Non-secret gateway application configuration. Top-level keys name TOML
# tables and are rendered into the mounted gateway.toml file. Kubernetes
# resource inputs remain outside this map; template expressions derive the