mirror of
https://github.com/block/buzz.git
synced 2026-10-27 04:30:52 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user