feat: customization - #160
Conversation
…ners, topology spread and extraObjects across the chart
| keytool -storepasswd -keystore "${CACERTS_TMP}" -storepass changeit -new "${TRUSTSTORE_PASS}" || { echo "Error: failed to set the truststore password."; exit 1; } | ||
| fi | ||
| {{- if and .Values.graylog.config.tls.enabled .Values.graylog.config.tls.updateKeyStore }} | ||
| keytool -importcert -noprompt -alias byoc -file "/mnt/tls/tls.crt" -keystore "${CACERTS_TMP}" -storepass "${TRUSTSTORE_PASS}" |
There was a problem hiding this comment.
May be worth adding a || { echo "Error: failed to import the custom cert CA."; exit 1; } guard here. If invalid, this keystore might cause a broken truststore
There was a problem hiding this comment.
That's a great idea, that should be caught early! I'll implement that in this PR if possible.
There was a problem hiding this comment.
Done in 2539414. Both the byoc and byoc-ca imports now fail the init container, matching the OpenSearch CA import that already had a guard.
| DISABLED 2026-07-30 -- the settings are inert: the forwarder listener is | ||
| configured as attributes on a Graylog input of type "Forwarder", not through | ||
| server.conf, and unrecognised GRAYLOG_* env vars are silently dropped. | ||
| graylog.config.forwarder was removed from values.yaml, so this helper reads a | ||
| path that no longer exists -- re-add those values before restoring it. | ||
|
|
||
| Whether the Graylog server should listen for forwarder connections. | ||
| Defaults to ingress.forwarder.enabled so that exposing the ingest endpoint also | ||
| binds the ports behind it; set graylog.config.forwarder.enabled explicitly to | ||
| override (e.g. to bind the ports without creating an Ingress). | ||
|
|
||
| {{- define "graylog.forwarder.enabled" -}} | ||
| {{- $configured := .Values.graylog.config.forwarder.enabled -}} | ||
| {{- if kindIs "bool" $configured -}} | ||
| {{- $configured -}} | ||
| {{- else -}} | ||
| {{- .Values.ingress.forwarder.enabled | ternary true false -}} | ||
| {{- end -}} | ||
| {{- end }} | ||
| */}} |
There was a problem hiding this comment.
May be worth removing if deprecated.
There was a problem hiding this comment.
Agreed, not entirely sure what the api sunset strategy should be yet, but taking this into consideration!
There was a problem hiding this comment.
Leaving this one for now. It's a commented-out block, so there's no render impact either way, and the note above it is the part that has value. The deprecation warning in the templates will help for the next api breaking change release of the chart.
| Sourced from graylog.inputs, so it must stay in sync with that entry's name. | ||
| */}} | ||
| {{- define "graylog.service.port.forwarder.message" -}} | ||
| {{- print "input-forwarder" }} |
There was a problem hiding this comment.
Not positive this is an issue but there may be a potential gap if someone renames the forwarder. Apologies if just missing context!
Eg.
graylog:
inputs:
- name: my-forwarder # renamed from "input-forwarder"
port: 13301
targetPort: 13301
protocol: TCP
Service might be named my-forwarder but ingress would still look for input-forwarder
potential fix:
{{/*
Graylog service port name for the forwarder message channel (default 13301).
Sourced from graylog.inputs, so it must stay in sync with that entry's name.
*/}}
{{- define "graylog.service.port.forwarder.message" -}}
{{- $entry := "" -}}
{{- range .Values.graylog.inputs -}}
{{- if eq (int .port) 13301 -}}{{- $entry = .name -}}{{- end -}}
{{- end -}}
{{- if not $entry -}}
{{- fail "No entry in graylog.inputs with port 13301 — the forwarder message channel Ingress has nothing to bind to. Add an input with port: 13301 or disable ingress.forwarder.messageChannel." -}}
{{- end -}}
{{- $entry -}}
{{- end }}
There was a problem hiding this comment.
Thanks for that catch! These issues, while real are not related to this effort. But I'm working on resolution to this in a different branch.
No commit in the 1.0.0 to 2.0.0 window carried a breaking-change footer, so release-please had no breaking-changes section to generate. This adds the 16 found by rendering the chart at both versions and diffing resource names, StatefulSet immutable fields, security contexts and values keys. Also adds the mongodb entry from #176, which the parser dropped, corrects "starup" to "startup" in the #169 entry, and gives #160 a description of what it actually does. The publish job generates artifacthub.io/changes from this file, so these notes reach Artifact Hub as written.
* chore(main): release graylog 2.0.0 * chore(main): write the 2.0.0 breaking changes into the changelog No commit in the 1.0.0 to 2.0.0 window carried a breaking-change footer, so release-please had no breaking-changes section to generate. This adds the 16 found by rendering the chart at both versions and diffing resource names, StatefulSet immutable fields, security contexts and values keys. Also adds the mongodb entry from #176, which the parser dropped, corrects "starup" to "startup" in the #169 entry, and gives #160 a description of what it actually does. The publish job generates artifacthub.io/changes from this file, so these notes reach Artifact Hub as written. --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: alix-graylog <alix.fullerton@graylog.com>
Summary
Lets users adopt the chart into an existing ecosystem without forking it. Every rendered object accepts custom labels and annotations, both workloads accept arbitrary volumes and containers, pods can be spread across failure domains, and anything the chart does not model can be deployed alongside it via
extraObjects.Details
Labels and annotations on every object
Three helpers in
_helpers.tpl—graylog.metadata.labels,graylog.metadata.annotationsandgraylog.pod.labels— render the metadata block for every object. Each merges, lowest to highest precedence:global.commonLabels/global.commonAnnotations, the object's ownlabels/annotations, then the chart-owned identity labels and Helm hook/resource-policy annotations, which always win.All 33 rendered objects are covered, including the
MongoDBCommunityCR, the external-OpenSearch Secret, the Helm test Pods and the waiting-room objects.Extra volumes, mounts and containers
extraVolumes,extraVolumeMounts,extraInitContainersandextraContainerson both workloads, plusextraInitVolumeMountsfor the chart'scopy-datainit container. The Datanode'svolumes:block was previously omitted entirely when both persistent volumes were enabled, so it was restructured to always render when extra volumes are present.Pod scheduling and runtime
topologySpreadConstraints,priorityClassName,schedulerName,runtimeClassName,dnsPolicy,dnsConfigandhostAliaseson both workloads.topologySpreadConstraintsis the substantive one. The chart's existing anti-affinity is a soft hostname preference — it does not guarantee a spread across zones, so a single-zone failure could take every Data Node replica with it. There was previously no way to express a real multi-AZ layout.extraObjects
A top-level list rendered through
tpl, so entries can reference the release context. Mapping and string forms both work — the string form is what you need when the manifest itself contains Helm syntax.global.commonLabels/commonAnnotationsare merged in; anything set on the object wins. An entry that renders without akindfails the render with an actionable message rather than emitting an invalid manifest.Lifecycle hooks
graylog.lifecycle.postStart/preStopfor user-supplied hooks, alongside the chart-managedpreStopDrainfrom #147. SettingpreStoptogether withpreStopDrain.enabledfails the render, because a container can only have one preStop hook and silently dropping either would be worse.Truststore handling in the init container
The BYO Graylog certificate and the BYO OpenSearch CA each built the Java truststore their own way, and the two paths disagreed about where the JDK bundle lives — the OpenSearch path read
${JAVA_HOME}while the Graylog path derived it by runningjava. They are now one build, gated by agraylog.truststore.enabledhelper, always seeded from the JDK bundle in the image so the default CAs survive and our certificates are only ever added on top.Two defects fell out of that:
javain the Graylog image carries a file capability (cap_net_bind_service=ep), and the init container runsallowPrivilegeEscalation: false, which setsno_new_privs. The kernel refuses toexecvea file with capabilities under that flag, so the JVM died withOperation not permitted(exit 126) and the derived path came back empty. Onmainthat path is unchecked (init-graylog.yaml:78):cp "${JAVA_HOME_LOCAL}/lib/security/cacerts"degrades tocp /lib/security/cacerts, fails silently, andkeytoolthen creates a fresh keystore holding only the BYO certificate. Since the chart passes-Djavax.net.ssl.trustStore=/usr/share/graylog/data/cacerts/graylog.jksto the JVM, that becomes Graylog's entire trust anchor set — every outbound TLS connection to anything not signed by that one certificate would fail. The lookup now reads${JAVA_HOME}with a fallback across known JDK paths and never starts a JVM;keytoolhas no file capability and is unaffected.keyStorePasscould never be applied. The JDK bundle ships aschangeit, so importing with a different-storepassfailed outright. The seeded copy is now re-keyed first.The store is also only moved into place when its content actually changed, and
keyStorePassis single-quoted so a password with shell metacharacters is safe.Incidental fixes
values.schema.jsonstill described the pre-feat: Safe Graylog Journal Draining #147 flatingress.forwarder.*shape. Rewritten to the two-channel form with a shared$defs/forwarderChannel.labelsadded to the forwarder Ingresses (they already hadannotations).datanode.persistence.dataaccepted noannotations/labels, even though the template already read them and its siblingnativeLibsclaim exposed them. Gap closed, so all four claim templates behave the same way.mongodb.userswas still declared invalues.schema.jsonafter the value itself was dropped. Removed.@,/,:or?no longer splits it at the wrong place.annotations:andinitContainers:keys are no longer emitted as bare nulls.Breaking changes
Verified there are no breaking changes to immutable objects.
PR Checklist
Testing Checklist
Static Validation
helm lint ./charts/grayloghelm template graylog ./charts/graylog --validateInstallation
helm install graylog ./charts/graylogkubectl rollout status statefulset/grayloghelm test graylogFunctional (if applicable)
Upgrade (if applicable)
Specific to this PR
helm unittest ./charts/graylog— 330 tests across 28 suitesorigin/mainand this branch with identical values and diffed the output object-by-object; every difference is accounted for aboveexistingSecretName,nativeLibs.enabledgraylog-helm-1onglc-central-devwith BYO OpenSearch; Graylog pods reached Running through the rebuilt init containermain(render-diff clean; the live upgrade that was run started from a polluted baseline, see above)extraObjectsapplied against a live cluster with a real CRD (e.g. a ServiceMonitor) — only render-tested so farNotes for reviewers
Two conflict resolutions during the rebase onto #147 are worth a look, since both were judgement calls rather than mechanical merges:
templates/service/ingress/graylog-forwarder.yaml— feat: Safe Graylog Journal Draining #147 rewrote this into one Ingress per gRPC channel. The metadata helpers were moved to per-channel and alabelskey added to each channel, rather than keeping a flatingress.forwarder.labels.templates/workload/statefulsets/graylog.yaml— kept akindIs "invalid"guard forterminationGracePeriodSecondsin preference towith, sincewithskips a legitimate value of0.Known issue, pre-existing, not addressed here
A numeric MaxMind account ID (
--set graylog.config.geolocation.maxmindGeoIp.accountId=1, unquoted) fails withb64enc: wrong type for value; expected string; got int64. Reproduced onorigin/main, so it is not a regression from this PR. Workaround is--set-string. Tracked separately.