Releases: aehrc/ontoserver-deploy
Release list
ontoserver: v0.5.2
ontoserver: v0.5.1
ontoserver: v0.5.0
0.5.0 (2026-08-13)
Added
- ontoserver: expose OTel metrics and logs exporters (46a37e2)
- ontoserver: expose StatefulSet podManagementPolicy (f960874)
Fixed
- ontoserver: expose podManagementPolicy and OTel exporters, restore empty serverPort default (7cdff43)
- ontoserver: restore empty serverPort default (d76637a)
Documentation
ontoserver: v0.4.1
ontoserver-indexer: v0.2.1
ontoserver-extras: v0.1.2
ontoserver-indexer-0.2.0
Note: checked against the
ontoserver-indexer-0.1.0tag by diffing the values keys, not assembled from commit
messages, so nothing user-facing since that release is missing.
Added
resources.heapGb— sets the JVM-Xmxindependently of the container memory limit. The
default ismemoryGb - 2, leaving 2 GiB for non-heap JVM memory (metaspace, code cache,
thread stacks, GC structures, direct buffers). Previously-Xmxwas set equal to the memory
limit, which guarantees an eventual OOMKill.- Validation rejecting a heap that meets or exceeds
resources.memoryGb, so the misconfiguration
fails at install time rather than as an OOMKill mid-index. - Opt-in security context:
job.podSecurityContext,job.containerSecurityContextand
job.automountServiceAccountToken, all unset by default so existing users see no change. The
README documents a hardened configuration; note a non-root Job needs anfsGroupthat can
write the output PVC. job.extraVolumesandjob.extraVolumeMounts— arbitrary volumes and mounts for the indexer
container, rendered verbatim and appended after the chart's ownoutput-volume/input-volume
entries so those win a name collision. Both default to empty, so nothing changes for existing
users. This makesreadOnlyRootFilesystem: truereachable: the indexer runs the same Spring Boot
image as the server and needs a writable/tmp, which the chart previously could not supply.
Fixed
- Registry credentials containing a
"or\no longer corrupt the image pull secret. The
.dockerconfigjsonwas built by interpolating the username and password into a JSON string
literal withprintf, so either character produced invalid JSON — which the kubelet reports
only as an opaqueImagePullBackOff. It is now built withdictandtoJson.
Changed
- The default Job name is now
<release name>-<release revision>rather than the release name,
so an upgrade creates a new Job instead of failing on the immutable pod template of the
existing one.
ontoserver-extras-0.1.1
Note: checked against the
ontoserver-extras-0.1.0tag by diffing the values keys, not assembled from commit
messages, so nothing user-facing since that release is missing.
Added
-
Chart description corrected — it still advertised a PV template, which now lives in the
ontoserverchart. -
collector.podSecurityContextandcollector.containerSecurityContext. The collector pod is
built by the OpenTelemetry Operator from theOpenTelemetryCollectorCR, so these render as CR
fields rather than pod-spec fields:spec.podSecurityContextandspec.securityContext— the
latter being the container context despite the name. Both verified against thev1beta1CRD
shipped with operator 0.156.0.spec.containerSecurityContext, the plausible spelling, is not a
field on the CRD. How that fails depends on the client, and both were tested against a live
operator:kubectl applyrejects it with a strict decoding error, while Helm succeeds and the
API server prunes the field — the release reportsdeployedand the collector runs with no
container security context at all. The Helm path is the one that matters here and it is silent, so
a test asserts the chart never emits that spelling.
Validated on a cluster: the Operator (0.131.0) applies both contexts verbatim to the collector
pod it builds, and the collector starts and runs underreadOnlyRootFilesystemwith all
capabilities dropped. -
Readiness and liveness probes on the
varnishcontainer (varnish.probes.*, on by default).
Only the metrics exporter sidecar had one before, so the Service began routing to a pod whose
varnishdwas not yet accepting connections and every rolling update dropped requests.Both are
tcpSocketon the http port rather thanhttpGet. An HTTP probe would be proxied to
Ontoserver: backend traffic on every period, and — worse — the cache marked unready whenever the
backend was down, turning a backend outage into a cache outage and defeating the point of
varnish.graceSeconds. The liveness probe is deliberately more tolerant than the readiness probe
because a restart discards the whole cache.Note this is the one change here that is not pod-spec-neutral: the first upgrade rolls the
Varnish Deployment once and the cache starts cold. Setvarnish.probes.enabled: falseto keep
the previous behaviour. -
collector.batch.sendBatchSizeandcollector.batch.timeout, previously hardcoded. -
Opt-in security context:
varnish.podSecurityContext,varnish.containerSecurityContextand
varnish.automountServiceAccountToken. All default to unset, so upgrading an existing release
leaves the pod spec byte-identical and does not discard a warm cache. The container-level value
applies to every container in the pod — varnish, the metrics exporter and both trace sidecars —
because they share a process namespace and are not independently isolatable.
Fixed
-
Traces now actually ship. The batch processor was configured with
timeout: 0s, which does not
mean "flush immediately" — it disables the flush timer, so spans were held until
send_batch_size(1000) accumulated. A terminology server is usually quiet, so the practical
effect was that tracing appeared configured and nothing arrived. Now defaults to5s, and a zero
value is rejected at render time in any unit. -
The
filter/health_checksprocessor now runs witherror_mode: ignore. Its default,
propagate, fails the entire batch when one condition errors, so a single span missing
http.urlwould discard every span batched with it. The threecache_lookupconditions were
also missing the nil guard the surrounding conditions already had — and a condition that errors
is one that never matches, so the spans it should have filtered were being exported. -
Varnish now restarts when its VCL changes.
varnishdparses/etc/varnish/default.vclonce
at startup and never re-reads the mounted ConfigMap, so ahelm upgradethat changed only a
cache setting updated the ConfigMap, left the pod template untouched, and Varnish went on
serving the previous VCL indefinitely. The Deployment pod template now carries a
checksum/configannotation over the rendered VCL. Note this means upgrading to this version
restarts Varnish once, discarding the warm cache.
Changed
- The VCL body moved from
varnish-configmap.yamlinto a named template
(ontoserver-extras.varnish.vcl) so the Deployment can hash exactly the VCL text. The
rendered ConfigMap content is unchanged. The hash is deliberately independent of the chart
version, so future releases do not restart Varnish without a VCL change. - Chart icon URL now points at the
masterbranch rather than the non-existentmain.
ontoserver-0.4.0
Removed
-
BREAKING: the bundled
nginx-ingresssubchart. The chart no longer installs an ingress
controller. It was pinned at2.1.0and nobody was updating it, which makes a vendored
network-facing controller a liability rather than a convenience.Migration. Install a controller yourself and point the chart at its IngressClass:
helm repo add nginx-stable https://helm.nginx.com/stable helm install nginx-ingress nginx-stable/nginx-ingress \ --namespace nginx-ingress --create-namespace \ --set controller.ingressClass.name=ontoserver-nginx
ontoserver: ingress: enabled: true className: ontoserver-nginx # must match the controller's IngressClass # delete the whole nginx-ingress: block
The chart fails to render if a
nginx-ingress:block is still present — including
enabled: false. That is deliberate: nothing at the top level ofvalues.schema.jsonsets
additionalProperties: false, so the key would otherwise be accepted silently andhelm upgrade
would quietly stop deploying the controller, taking the service offline with no error anywhere.
The presence of the key, not its value, is the signal that a values file has not been migrated.Consequences worth knowing: the chart now has no dependencies at all, so
Chart.lockand the
vendoredcharts/directory are gone andhelm dependency buildis a no-op.
Note: verified against the
ontoserver-v0.3.0tag rather than assembled from commit messages —
18 commits touch this chart since that release, and the values-key diff was used to confirm
nothing user-facing is missing. Changes predating 0.3.0 are covered by the sections below.
Added
-
ontoserver.gateway.allowPlaintextandontoserver.gateway.listenerPortPlain. A plaintext HTTP
listener now has to be requested explicitly: it is off by default so a public Gateway cannot be
left unencrypted by accident. Enable it for local development, or when TLS terminates upstream. -
ontoserver.gateway.closureRequestTimeout(default300s). The$closureHTTPRoute carried no
timeoutsblock at all, so the chart's longest-running operation inherited whatever the Gateway
implementation defaults to. Falls back torequestTimeoutwhen empty. -
ontoserver.metrics.serviceMonitor.labels,.interval,.scrapeTimeoutand
.namespaceSelector. Most Prometheus installations set a non-emptyserviceMonitorSelector, and
a ServiceMonitor carrying no matching label is silently never discovered — nothing errors, the
metrics just never appear. -
Validation of the release-name length, with the limits checked against a live API server. The
binding constraint is Service names (DNS labels, capped at 63), which caps the release name at
33 — Helm's own cap of 53 is not low enough. Without this an over-long name yields a
partially installed release: everything applies except one Service. -
ontoserver.deployment.allowScaledReadWrite— opt in to the unsupported scaled read-write
topology. Scaled deployments must otherwise be read-only: each replica keeps its own Lucene
index on its own PVC, so content written through the round-robin Service is indexed only on
the replica that served the write, and$expand/$validate-codethen fail on the others. -
ontoserver.deployment.podDisruptionBudget.maxUnavailableand.unhealthyPodEvictionPolicy
as real values rather than commented-out suggestions. -
Opt-in security context:
ontoserver.deployment.podSecurityContext,
.containerSecurityContext,.db.containerSecurityContextand.automountServiceAccountToken.
The chart previously set no security context anywhere, so pods ran as root. All four default to
unset, so upgrading an existing release renders a byte-identical pod spec and rolls no pods —
hardening has to be requested. The Postgres sidecar has its own value because it cannot share
the Ontoserver container's: the postgres entrypoint requires uid 999.A verified hardened configuration is documented in the README, along with the two
combinations that cannot be made to work non-root (the Postgres sidecar and Ontoserver's own
HTTPS mode). Those constraints were established by running the shipped images under each
setting, not inferred — each failure is a crash at startup. -
ontoserver.deployment.extraVolumesand.extraVolumeMounts— arbitrary volumes and mounts for
the Ontoserver container, rendered verbatim and appended after the chart's own entries so
chart-managed names always win a collision. Both default to empty, so an existing release
renders a byte-identical pod spec.This makes
readOnlyRootFilesystem: truereachable, which it previously was not: the server
needs a writable/tmpand the chart had no way to supply one. Validated on a cluster (AKS,
external PostgreSQL, Gatekeeper auditing): Ready in ~50s with 0 restarts, root filesystem
genuinely read-only, FHIR served, bothhelm testsuites passing, and zero violations of
readOnlyRootFilesystem,allowedUsersGroupsornoPrivilegeEscalationfor the namespace./tmpturned out to be
load-bearing rather than just a log destination — a running server writesspring.log,
hsperfdata, Tomcat's work directories anddownlaod-*scratch files there. The hardened
README recipe now includes both, asserted together by a test so it cannot ship half-applied. -
Schema validation and test coverage for
ontoserver.existingSecretConfig, a 0.3.0 feature that
shipped with neither. The value was accepted before (the schema has noadditionalProperties
restriction at that level) so this is validation and documentation rather than a functional fix:
a non-string is now rejected with a message naming the key.
Fixed
-
Documented a silent
$closurerouting failure on Traefik. Traefik matchesPathPrefixagainst
the percent-encoded path, so a client sending/fhir/%24closuremisses the dedicated pod-0 route
and is load-balanced across all pods, corrupting the stateful closure table. NGINX decodes before
matching and is unaffected. Both were tested; AWS ALB and Azure AGIC remain unverified and the
README says so. -
Removed the unreachable
existingVolumebranch from the StatefulSet'svolumeClaimTemplates.
validate-values.yamlrejectspersistence.files.existingVolumefor a StatefulSet outright, so
the branch could never render — and the spec it would have produced (volumeNamewith no
accessModesorresources) was not a valid PVC. Renders are byte-identical across all eight
test fixtures. -
Renamed
poddistributionbudget.yamltopoddisruptionbudget.yaml(the resource is a
PodDisruptionBudget). Template filenames are not part of the API, so this changes nothing at
install time. -
A
Deploymentwith persistence on aReadWriteOncevolume now rendersstrategy.type: Recreate
instead of the requestedRollingUpdate.RollingUpdatecannot work there: it starts the
replacement pod before removing the old one, and a RWO disk attaches to one node at a time, so a
replacement scheduled elsewhere waits indefinitely onMulti-Attach errorwhile the old pod is
never torn down. Reproduced on a live cluster; it also blocks PVC expansion until the volume
detaches. Scoped toReadWriteOnce/ReadWriteOncePod, soReadWriteManyusers keep
zero-downtime rolling upgrades, and the sidecar'sdbfilesaccess mode is only consulted when
the sidecar is enabled.Upgrading an existing release: Kubernetes defaults
spec.strategy.rollingUpdateand refuses
to hold it alongsidetype: Recreate.helm upgradeand client-sidekubectl applyhandle the
removal; server-side apply fails withspec.strategy.rollingUpdate: Forbidden. Each row of
that was verified on a cluster, and the README gives the one-line patch that clears it. -
ontoserver.secretConfigno longer fails to render on a non-string value.b64encrejects
anything but a string, so a numeric port or a boolean flag aborted the whole release with
wrong type for value; expected string; got int64— and the error named only<b64enc>, not the
key at fault. Values are now coerced withtoString, matching the siblingontoserver.config,
which has always accepted them via| quote. Note that Helm parses YAML numbers as float64, so
quote any value whose exact form matters; that is true of both keys and is not new. -
envoygateway.envoyProxy.pdbMinAvailable: 0and.replicas: 0are no longer silently coerced to
1 and 2. Both were rendered with| default, and 0 is falsy in Go templates, so the Envoy fleet
could not be scaled to 0 and its PodDisruptionBudget could not be set to permit full eviction.
Same class of bug as the PodDisruptionBudget fix above.minAvailablenow also routes through the
shared IntOrString helper for consistency, though the quoting is not load-bearing in this field. -
podDisruptionBudget.minAvailable/.maxUnavailablenow accept percentages. The previous guard
comparedintagainst 1, andint "25%"is 0, so every percentage — including the25%form
the values file suggested — was rejected. Percentages are emitted quoted and counts unquoted,
as the KubernetesIntOrStringtype requires. Setting both, setting neither,maxUnavailable: 0,
and aminAvailableat or above the replica count are now all rejected with an actionable
message instead of silently producing an unevictable workload. -
Configuration changes now roll the pods.
checksum/secret-configand
checksum/external-secretannotations were added to the pod template, because Ontoserver
resolves its configuration as environment variables at container start, so ahelm upgrade
that changed only a Secret left the running pods on the old value indefinitely. See
"Configuration changes and pod restarts" in the README for what is and is not covered. -
The `-ontoserver-db...
ontoserver-0.3.0
Added
existingSecretConfig— reference a pre-existing Kubernetes Secret by name; its keys are injected as environment variables viaenvFrom, enabling GitOps workflows (e.g. ArgoCD) where secrets are managed outside the chart.- Chart-native External Secrets support for registry credentials via
ontoserver.externalSecret.imagePullSecret. - Automatic wiring of the generated external pull secret into workload
imagePullSecretsfor bothDeploymentandStatefulSetmodes. - Optional
secretStoreRefoverrides for the image pull secret, allowing registry credentials to come from a different secret store than other external secrets. - Unit test coverage for external pull secret rendering, workload wiring, and validation behaviour.
Changed
- Replaced the manual ExternalSecret-based quay.io pull-secret example with the chart-managed
externalSecret.imagePullSecretworkflow in the chart documentation.
Fixed
- Added render-time validation to require both
imagePullSecret.data.username.keyandimagePullSecret.data.password.keyto be set together. - Added render-time validation to block the unsupported combination of
certmanager.enabled=truewith ALB ingress.