Skip to content

feat(common): PDB, topology spread, pod-spec options, probe scheme, PVC mount, monitor endpoint fields (2.5.0) - #6

Merged
kharkevich merged 6 commits into
mainfrom
feat/common-floe-gaps
Oct 6, 2026
Merged

kharkevich merged 6 commits into
mainfrom
feat/common-floe-gaps

Conversation

@kharkevich

@kharkevich kharkevich commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Summary

Adds what the floe chart (kharkevich-engineering-lab/floe, deploy/helm/floe) needs so it can stay a thin chart of one-line common.* calls, instead of re-implementing pieces locally. Bumps common to 2.5.0. Every new key is off unless set: an existing chart renders byte-for-byte the same.

Gap in 2.4.0 (evidence) Added in 2.5.0
No PodDisruptionBudget template (no PodDisruptionBudget anywhere in templates/) common.pdb (pdb.enabled, maxUnavailable / minAvailable, unhealthyPodEvictionPolicy), selector = common.labels.selector
_deployment.yaml pod spec has no topologySpreadConstraints; values can't express the selector because it depends on the fullname topologySpread.topologyKeys → one constraint per key, labelSelector from common.labels.selector, matchLabelKeys: [pod-template-hash] (same style as antiAffinityLabels)
Pod spec: no terminationGracePeriodSeconds, nodeSelector, priorityClassName, enableServiceLinks, automountServiceAccountToken; pod metadata only gets the checksum/prometheus annotations and the standard labels terminationGracePeriodSeconds, nodeSelector, priorityClassName, enableServiceLinks, automountServiceAccountToken (both only when the key is set), podLabels, podAnnotations
_healthcheck.yaml: httpGet has no scheme, so an app terminating TLS itself can't be probed; _container.yaml picks tcp/http for all three probes at once (healthCheck.kind) healthCheck.scheme / <probe>.scheme; <probe>.kind overrides healthCheck.kind per probe (floe in ACME mode: tcp liveness/startup while it waits for a certificate, HTTPS readiness on /readyz)
common.persistentvolumeclaim creates a claim but nothing mounts it; common.volume.pvc is only usable from a template at a fixed indent, values can't name the claim (it's the fullname) persistence.mountPath (+ persistence.volumeName, default data) adds the volume and the volumeMount
The ConfigMap is named common.fullname, so a values-only volumes entry can't mount it as a file; configmap.enabled only controls envFrom configmap.mountPath (+ configmap.volumeName, default config) adds the configMap volume and a read-only mount
Monitors: the endpoint has only interval/port/path; an override can't add a field to it (the merge replaces the whole endpoints list); no way to add the release label a Prometheus selects by monitoring.endpoint (merged into the endpoint: scheme, tlsConfig, authorization, …) and monitoring.labels on ServiceMonitor, PodMonitor and VMServiceScrape

Also a fix: common.service in the override form ((list . "app.service")) printed {} when service.enabled: false (an invalid manifest helm lint --strict rejects); it now renders nothing, like the single-context form.

The README now documents the templates and the new keys.

Compatibility

  • charts/github-app-jwt2token-controller and charts/application-ingress, pointed at a local file:// copy of common 2.4.0 and then 2.5.0: helm template output is identical (diff empty).
  • A scratch chart calling every common.* template with two values files using only 2.4.0 keys (one minimal, one setting nearly every key: tcp probes, NodePort, HPA, PVC, ingress, HTTPRoute, monitors, secrets, initContainers, …): identical output on 2.4.0 and 2.5.0.
  • With the new keys set, the rendered manifests pass kubeconform -strict -kubernetes-version 1.33.0 (plus the datree CRD schemas for the monitors and HTTPRoute).

Not addressed here (noted for later)

  • Several Deployments from one chart (floe's role split: a maintain instance next to the serving fleet). Every template reads .Values of the one context, so this needs a design (an instances map, or a documented context-per-instance pattern); the floe chart documents installing itself twice instead.
  • Small existing quirks left alone so this stays non-breaking: probe/strategy values use default, so 0 means "use the default" (initialDelaySeconds: 0 becomes 180/40); resources.limits.cpu is always rendered (defaults to 1000m); the ServiceMonitor's targetPort is quoted, so a numeric port becomes a port name (use a port name); gateway.enabled defaults to true when the key is absent; common.volume.pvc only renders correctly at one indent.

Merging this lets the release workflow publish common 2.5.0 to oci://ghcr.io/technicaldomain/helm, which the floe chart PR waits for.

🤖 Generated with Claude Code

kharkevich and others added 6 commits October 6, 2026 14:38
… the deployment

New, off unless set: podLabels, podAnnotations, automountServiceAccountToken, enableServiceLinks, terminationGracePeriodSeconds, priorityClassName, nodeSelector, topologySpread.topologyKeys (constraints selecting the release's pods, like antiAffinityLabels), and persistence.mountPath, which adds the claim as a volume (persistence.volumeName, default data).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
healthCheck.scheme (and <probe>.scheme) sets the httpGet scheme, so an app that serves TLS itself can be probed; <probe>.kind overrides healthCheck.kind per probe (e.g. tcp liveness and startup with an http readiness). The persistence mount from the previous commit lands in volumeMounts. Unset keys render exactly as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
common.pdb (pdb.enabled, maxUnavailable or minAvailable, unhealthyPodEvictionPolicy) selects the deployment's pods. monitoring.labels adds labels to the ServiceMonitor/PodMonitor/VMServiceScrape and monitoring.endpoint merges extra fields (scheme, tlsConfig, authorization, ...) into the scrape endpoint, for metrics behind auth or TLS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ntPath

The ConfigMap is named after the release (common.fullname), so a values-only volumes entry cannot reference it. configmap.mountPath (+ configmap.volumeName, default config) adds the configMap volume and a read-only mount. Combine with configmap.enabled: false to keep it out of envFrom (a config file, not env vars).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
common.service called as (list . "app.service") with service.enabled: false merged an empty override into an empty template and printed "{}", a manifest without a kind or name that helm lint --strict rejects. The single-context form already rendered nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kharkevich
kharkevich merged commit 3a432a2 into main Oct 6, 2026
3 checks passed
@kharkevich
kharkevich deleted the feat/common-floe-gaps branch October 6, 2026 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant