Merge pull request #83 from jk-cluster/feat/checksum-config-template-chart
template-chart: checksum/config-Annotation + verbindliche Style-Guideline (#82)
This commit is contained in:
5 files changed
+36
-4
No files matched your search
@@ -61,6 +61,7 @@ The binding style guide for all current and future charts lives in **README.md (
|
||||
- Main image tag from `{{ .Chart.AppVersion }}`; auxiliary/sidecar/init images pinned via values and reviewed on app-update rounds.
|
||||
- Ingress: `ingress.domain` and `ingress.clusterIssuer` `required` **without defaults**; `ingress.className` defaults to `nginx`; optional `ingress.annotations` merged with the cert-manager annotation; TLS secret `tls-<release>-<chart>-ingress`. Documented exception: homeassistant keeps its flexible upstream ingress style (className default `nginx`).
|
||||
- Secrets are 1Password `OnePasswordItem` CRs: values expose `secrets.<name>SecretRef` holding an `op://` item path; the operator materializes the Kubernetes Secret.
|
||||
- Config changes must restart the workload (#82): every pod template consuming a ConfigMap carries `checksum/config: {{ include (print $.Template.BasePath "/<chart>.configmap.yaml") . | sha256sum }}` (one line per ConfigMap). Without it a changed ConfigMap restarts nothing — `subPath` mounts are never refreshed and apps read config only at start. Adding it to an existing chart is a **major** bump. Secrets from `OnePasswordItem` cannot be hashed (Helm never sees their content); charts mounting them document the limitation in `values.yaml`.
|
||||
- Every container offers an additive `env` block rendered through `tpl` with `value`, `secretKeyRef`, and `configMapKeyRef` forms.
|
||||
- Hardening: `automountServiceAccountToken: false`, non-root, `readOnlyRootFilesystem: true`, caps dropped, `allowPrivilegeEscalation: false`; contexts values-configurable (`securityContext.pod` / `securityContext.container`); writable paths as emptyDirs; image-forced deviations MUST be documented with a comment in the chart's `values.yaml`.
|
||||
- Probes: liveness/readiness/startup on every workload (exception: paperless consume CronJob), values-configurable with calibrated defaults.
|
||||
|
||||
@@ -125,18 +125,35 @@ These guidelines are **binding for every current and future chart** in this repo
|
||||
|
||||
- Secrets are **1Password `OnePasswordItem` CRs**: values expose `secrets.<name>SecretRef` holding an `op://` item path; the 1Password operator materializes the Kubernetes Secret in-cluster.
|
||||
|
||||
### 9. Environment variables
|
||||
### 9. Config changes must restart the workload (#82)
|
||||
|
||||
- **Every workload that consumes a ConfigMap carries a `checksum/config` annotation on its pod template** — one line per ConfigMap it consumes:
|
||||
|
||||
```yaml
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/config: {{ include (print $.Template.BasePath "/<chart>.configmap.yaml") . | sha256sum }}
|
||||
```
|
||||
|
||||
Reference implementation: `template-chart/templates/xxx.deployment.yaml` and `xxx.sfs.yaml`. Where a workload consumes several ConfigMaps, use one annotation per file with a distinguishing suffix (`checksum/config-<name>`).
|
||||
- **Why it is mandatory, not optional**: without it a changed ConfigMap does not change the pod template, so nothing restarts and the running container keeps the old config — silently. `subPath` mounts (the usual form here) are never refreshed by the kubelet at all, and most apps read their config only at start. In #82 this produced a real outage: the router kept routing to Services that no longer existed while every bundle was green and the pod was Ready.
|
||||
- **The annotation is content-based, not time-based**: the hash is taken over the rendered ConfigMap, so an unchanged config renders an identical hash and `helm upgrade` is a no-op. It never degenerates into a restart-on-every-upgrade.
|
||||
- Adding the annotation to an existing chart is a **major** bump (§2): runtime behavior changes — a config change now costs a restart. Name that cost in the PR (some workloads take minutes to come back).
|
||||
- **Secrets from `OnePasswordItem` cannot use this mechanism.** Helm never sees their content — the 1Password operator fills the Secret in-cluster after rendering, so there is nothing to hash. A chart that mounts such a Secret as a file documents the limitation in its `values.yaml` where it cannot close the gap.
|
||||
|
||||
### 10. Environment variables
|
||||
|
||||
- Every workload container offers an additive `env` value block, appended to the env entries the chart always sets.
|
||||
- Entries are rendered through `tpl` (so values may contain Helm templating) and support the `value`, `secretKeyRef` and `configMapKeyRef` forms (pattern: `template-chart/templates/xxx.deployment.yaml`).
|
||||
|
||||
### 10. Scaling
|
||||
### 11. Scaling
|
||||
|
||||
- Every Deployment/StatefulSet has a `replicas` value (default `1`, the values path per workload matches its section) that also accepts an explicit `0` for per-workload fine control.
|
||||
- Every chart has a global `scaleDown` flag (default `false`): `scaleDown: true` takes precedence over all `replicas` values, renders every Deployment/StatefulSet with `replicas: 0` and suspends CronJobs. It **stops** the app but does not uninstall it — PVCs, Secrets, Services and Ingress stay in place; setting it back to `false` brings the workloads back up.
|
||||
- Implemented via a per-chart `<chart>.replicas` helper in `_helpers.tpl` (reference in `template-chart`); the helper uses an explicit nil check (`kindIs "invalid"`) because Helm's `default` would swallow an explicit `0`.
|
||||
|
||||
### 11. Everything else
|
||||
### 12. Everything else
|
||||
|
||||
- `icon:` is mandatory in every `Chart.yaml`.
|
||||
- `helm lint --strict` must pass without findings.
|
||||
|
||||
@@ -5,7 +5,7 @@ icon: https://helm.sh/img/helm.svg
|
||||
|
||||
type: application
|
||||
|
||||
version: 1.0.0+upxxx
|
||||
version: 2.0.0+upxxx
|
||||
appVersion: "xxx"
|
||||
|
||||
maintainers:
|
||||
|
||||
@@ -14,6 +14,13 @@ spec:
|
||||
name: {{ .Release.Name }}-{{ .Chart.Name }}-deployment
|
||||
labels:
|
||||
app: {{ .Release.Name }}-{{ .Chart.Name }}-deployment
|
||||
annotations:
|
||||
# Hash of the rendered ConfigMap: a changed ConfigMap changes the pod
|
||||
# template and thus rolls the pods. Without it a config change stays
|
||||
# invisible to the running container - subPath mounts are never
|
||||
# updated by the kubelet, and most apps read their config only at
|
||||
# start. Add one line per ConfigMap the workload consumes.
|
||||
checksum/config: {{ include (print $.Template.BasePath "/xxx.configmap.yaml") . | sha256sum }}
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
securityContext:
|
||||
|
||||
@@ -15,6 +15,13 @@ spec:
|
||||
name: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
||||
labels:
|
||||
app: {{ .Release.Name }}-{{ .Chart.Name }}-sfs
|
||||
annotations:
|
||||
# Hash of the rendered ConfigMap: a changed ConfigMap changes the pod
|
||||
# template and thus restarts the pods. Without it a config change stays
|
||||
# invisible to the running container - subPath mounts are never
|
||||
# updated by the kubelet, and most apps read their config only at
|
||||
# start. Add one line per ConfigMap the workload consumes.
|
||||
checksum/config: {{ include (print $.Template.BasePath "/xxx.configmap.yaml") . | sha256sum }}
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
securityContext:
|
||||
|
||||
Reference in new issue
Block a user