feat(chart): add relay pod extension points (#3322)

## Why
Allow operators to install wrapper binaries and override the relay
entrypoint without maintaining a duplicated Deployment outside the OSS
chart. `extraManifests` can create independent resources but cannot
extend the chart-managed relay Pod.

## What
- Add opt-in init-container, volume, volume-mount, command, and args
extension points
- Preserve image defaults when extensions are empty and compose generic
init containers with the MinIO readiness gate
- Document the distinction from `extraManifests`, add schema coverage,
and release chart 0.1.7

## Risk Assessment
Low — all new values are opt-in, and default rendered manifests are
unchanged apart from version-derived metadata. Merge publishes a new
chart version without modifying existing installations.

## References
- [OpenTelemetry Collector Pod
extensions](https://github.com/open-telemetry/opentelemetry-helm-charts/blob/main/charts/opentelemetry-collector/templates/_pod.tpl)
alongside
[extraManifests](https://github.com/open-telemetry/opentelemetry-helm-charts/blob/main/charts/opentelemetry-collector/templates/extraManifests.yaml)
- [Argo CD
extraObjects](https://github.com/argoproj/argo-helm/blob/main/charts/argo-cd/templates/extra-manifests.yaml)
alongside component-scoped Pod extension hooks
- `helm unittest` 0.8.2: 43/43 tests passed
- Helm lint, schema validation, fixture renders, and chart packaging
passed
- Oracle review found no functional issues; its literal no-`tpl`
regression test recommendation is included

Generated with Amp

---------

Signed-off-by: David Grochowski <dgrochowski@squareup.com>
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Dave Grochowski
2026-07-28 13:07:04 -04:00
committed by GitHub
parent a3b097745a
commit af4d861516
6 changed files with 229 additions and 4 deletions

View File

@@ -7,7 +7,7 @@ description: |
PostgreSQL and Redis. Configurable for single-node evaluation
(subcharts on) and HA production (external services, existingSecret).
type: application
version: 0.1.6
version: 0.1.7
appVersion: "0.1.0"
home: https://github.com/block/buzz
sources:
@@ -24,7 +24,7 @@ maintainers:
annotations:
artifacthub.io/changes: |
- kind: added
description: Optional READ_DATABASE_URL env (secretKeyRef) enabling relay read-replica routing; absent key preserves prior behavior.
description: Generic init-container, volume, volume-mount, command, and args extension points for the relay Pod.
artifacthub.io/license: Apache-2.0
# Optional eval-only subcharts. Production deploys disable both and point

View File

@@ -52,6 +52,57 @@ See:
The chart fails at `helm install` / `helm template` time with a clear message if any of these are missing or malformed (see `templates/_validate.tpl`).
## Relay Pod extensions
The chart exposes narrow extension points for init containers, volumes, relay
volume mounts, and image command/argument overrides. `extraManifests` creates
independent Kubernetes resources but cannot modify the chart-managed relay
Deployment. These extension values insert fields into that Deployment, avoiding
duplication of its environment, probes, security context, secrets, and
chart-owned volumes.
For example, an init container can copy a wrapper binary into a shared volume
and make that wrapper the relay entrypoint:
```yaml
extraInitContainers:
- name: install-wrapper
image: example.com/wrapper-init:v1
args: [/opt/wrapper/wrapper]
securityContext:
runAsNonRoot: true
runAsUser: 65532
runAsGroup: 65532
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
resources:
requests:
cpu: 10m
memory: 16Mi
volumeMounts:
- name: wrapper
mountPath: /opt/wrapper
extraVolumes:
- name: wrapper
emptyDir: {}
relay:
command: [/opt/wrapper/wrapper]
args: [/usr/local/bin/buzz-relay]
extraVolumeMounts:
- name: wrapper
mountPath: /opt/wrapper
```
These values are raw Kubernetes fragments rendered with `toYaml`, not `tpl`.
The chart does not validate cross-field relationships: extension names must not
collide with chart-owned containers or volumes, mounts must reference existing
volumes, and each init container must define an appropriate security context
and resources. Empty `relay.command` and `relay.args` arrays preserve the image
defaults; non-empty values override its entrypoint and arguments respectively.
## Device pairing relay
The chart can run Buzz's stateless pairing WebSocket relay as an independent

View File

@@ -55,13 +55,14 @@ spec:
topologySpreadConstraints:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if or .Values.minio.enabled .Values.extraInitContainers }}
initContainers:
{{- if .Values.minio.enabled }}
# Quickstart only: the bundled MinIO bucket is created by a concurrent
# init Job (templates/quickstart-minio-init.yaml). The relay's A3 S3
# conformance probe is startup-fatal, so without this gate the relay Pods
# CrashLoopBackOff (with growing backoff) until the bucket appears. Block
# relay start until the bucket exists — deterministic, no crash-loops.
initContainers:
- name: wait-for-bucket
image: {{ .Values.minio.mcImage | quote }}
securityContext:
@@ -90,12 +91,24 @@ spec:
done
echo "bucket {{ .Values.s3.bucket }} present"
{{- end }}
{{- with .Values.extraInitContainers }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
containers:
- name: relay
image: {{ include "buzz.image" . }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
securityContext:
{{- toYaml .Values.relay.containerSecurityContext | nindent 12 }}
{{- with .Values.relay.command }}
command:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.relay.args }}
args:
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- { name: app, containerPort: 3000, protocol: TCP }
- { name: health, containerPort: {{ .Values.service.healthPort }}, protocol: TCP }
@@ -225,6 +238,9 @@ spec:
volumeMounts:
- { name: git-repos, mountPath: {{ .Values.persistence.git.mountPath | quote }} }
- { name: git-pack-cache, mountPath: {{ .Values.git.packCachePath | quote }} }
{{- with .Values.relay.extraVolumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
volumes:
- name: git-repos
@@ -238,3 +254,6 @@ spec:
- name: git-pack-cache
emptyDir:
sizeLimit: {{ .Values.git.packCacheVolumeSize | quote }}
{{- with .Values.extraVolumes }}
{{- toYaml . | nindent 8 }}
{{- end }}

View File

@@ -165,3 +165,118 @@ tests:
- hasDocuments:
count: 0
template: templates/pvc-git.yaml
- it: preserves image defaults when Pod extensions are empty
set:
relayUrl: wss://buzz.example.com
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
externalPostgresql.url: postgres://u:p@h:5432/d
externalRedis.url: redis://h:6379
s3.endpoint: http://minio:9000
s3.accessKey: a
s3.secretKey: s
asserts:
- notExists:
path: spec.template.spec.initContainers
template: templates/deployment.yaml
- notExists:
path: spec.template.spec.containers[0].command
template: templates/deployment.yaml
- notExists:
path: spec.template.spec.containers[0].args
template: templates/deployment.yaml
- it: appends generic Pod extensions and overrides the relay command
set:
relayUrl: wss://buzz.example.com
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
externalPostgresql.url: postgres://u:p@h:5432/d
externalRedis.url: redis://h:6379
s3.endpoint: http://minio:9000
s3.accessKey: a
s3.secretKey: s
relay.command:
- /opt/wrapper/wrapper
relay.args:
- /usr/local/bin/buzz-relay
relay.extraVolumeMounts:
- name: wrapper
mountPath: /opt/wrapper
extraInitContainers:
- name: install-wrapper
image: example.com/wrapper-init:v1
args:
- /opt/wrapper/wrapper
env:
- name: LITERAL_TEMPLATE
value: '{{ .Release.Name }}'
securityContext:
runAsNonRoot: true
resources:
requests:
cpu: 10m
memory: 16Mi
volumeMounts:
- name: wrapper
mountPath: /opt/wrapper
extraVolumes:
- name: wrapper
emptyDir: {}
asserts:
- equal:
path: spec.template.spec.initContainers[0].name
value: install-wrapper
template: templates/deployment.yaml
- equal:
path: spec.template.spec.initContainers[0].securityContext.runAsNonRoot
value: true
template: templates/deployment.yaml
# Extension fragments are deliberately rendered with toYaml, not tpl.
- equal:
path: spec.template.spec.initContainers[0].env[0].value
value: '{{ .Release.Name }}'
template: templates/deployment.yaml
- equal:
path: spec.template.spec.containers[0].command
value:
- /opt/wrapper/wrapper
template: templates/deployment.yaml
- equal:
path: spec.template.spec.containers[0].args
value:
- /usr/local/bin/buzz-relay
template: templates/deployment.yaml
- contains:
path: spec.template.spec.containers[0].volumeMounts
content:
name: wrapper
mountPath: /opt/wrapper
template: templates/deployment.yaml
- contains:
path: spec.template.spec.volumes
content:
name: wrapper
emptyDir: {}
template: templates/deployment.yaml
- it: appends generic init containers after the bundled MinIO readiness gate
release:
name: rel
set:
relayUrl: wss://buzz.example.com
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
postgresql.enabled: true
redis.enabled: true
minio.enabled: true
extraInitContainers:
- name: install-wrapper
image: example.com/wrapper-init:v1
asserts:
- equal:
path: spec.template.spec.initContainers[0].name
value: wait-for-bucket
template: templates/deployment.yaml
- equal:
path: spec.template.spec.initContainers[1].name
value: install-wrapper
template: templates/deployment.yaml

View File

@@ -72,9 +72,34 @@
"type": "array",
"items": { "type": "string" }
},
"ephemeralTtlOverride": { "type": "integer", "minimum": 0 }
"ephemeralTtlOverride": { "type": "integer", "minimum": 0 },
"command": {
"type": "array",
"items": { "type": "string" },
"description": "Optional relay container entrypoint override. Empty preserves the image default."
},
"args": {
"type": "array",
"items": { "type": "string" },
"description": "Optional relay container arguments override. Empty preserves the image default."
},
"extraVolumeMounts": {
"type": "array",
"items": { "type": "object" },
"description": "Raw Kubernetes volumeMount fragments appended to the relay container."
}
}
},
"extraInitContainers": {
"type": "array",
"items": { "type": "object" },
"description": "Raw Kubernetes init-container fragments appended to the relay Pod."
},
"extraVolumes": {
"type": "array",
"items": { "type": "object" },
"description": "Raw Kubernetes volume fragments appended to the relay Pod."
},
"service": {
"type": "object",
"additionalProperties": true,

View File

@@ -185,9 +185,24 @@ relay:
readOnlyRootFilesystem: false # git writes need a writable repo path
terminationGracePeriodSeconds: 60
# Optional image entrypoint/arguments overrides. Empty arrays preserve the
# relay image's defaults. Consumers own compatibility with the selected image.
command: []
args: []
# Appended to the chart-owned relay mounts. Names must match extraVolumes (or
# another volume supplied by the platform) and must not collide with built-ins.
extraVolumeMounts: []
extraEnv: []
extraEnvFrom: []
# ── Pod extensions ──────────────────────────────────────────────────────────
# Raw Kubernetes fragments appended to the relay Pod. They are rendered with
# toYaml, not tpl. Init containers must define their own securityContext and
# resources; names must not collide with chart-owned containers or volumes.
extraInitContainers: []
extraVolumes: []
# ── Device pairing relay ─────────────────────────────────────────────────────
# Optional, stateless NIP-AB relay. When enabled, the main relay advertises
# pairingRelay.url in NIP-11 and Buzz clients use it instead of the legacy