diff --git a/README.md b/README.md index 1e44cc4..ffd0ddd 100644 --- a/README.md +++ b/README.md @@ -76,5 +76,6 @@ For runtime verification (do the workloads actually start, do probes/security se - Secrets are **1Password `OnePasswordItem` CRs**: values expose `secrets.SecretRef` holding an `op://` item path; the 1Password operator materializes the Kubernetes Secret in-cluster. - Ingress assumes ingress-nginx (`ingressClassName: nginx`) and cert-manager: `ingress.clusterIssuer` and `ingress.domain` are required values; the TLS secret is named `tls---ingress`. - `env` entries in `values.yaml` are rendered through `tpl`, so values may contain Helm templating; `value`, `secretKeyRef` and `configMapKeyRef` forms are supported. -- Hardened defaults: `automountServiceAccountToken: false`, non-root user, `readOnlyRootFilesystem: true`, all capabilities dropped, probes and resource requests/limits always set. Pod and container contexts are configurable via `securityContext.pod` / `securityContext.container` in each chart's values; writable paths (e.g. `/tmp`, nginx cache dirs, s6-overlay's `/run`) are emptyDirs. Where an image cannot satisfy the full standard (e.g. Home Assistant must start as root for s6-overlay, paperless needs a root init container to hand over `/run`), the deviation is minimal and justified with a comment in that chart's `values.yaml`. +- Hardened defaults: `automountServiceAccountToken: false`, non-root user, `readOnlyRootFilesystem: true`, all capabilities dropped, probes and resource requests always set. Pod and container contexts are configurable via `securityContext.pod` / `securityContext.container` in each chart's values; writable paths (e.g. `/tmp`, nginx cache dirs, s6-overlay's `/run`) are emptyDirs. Where an image cannot satisfy the full standard (e.g. Home Assistant must start as root for s6-overlay, paperless needs a root init container to hand over `/run`), the deviation is minimal and justified with a comment in that chart's `values.yaml`. +- Resource requests ship as chart defaults and are user-overridable; limits are computed by a per-chart `_helpers.tpl` helper (reference implementation in `template-chart/templates/_helpers.tpl`): an explicitly set limit always wins, missing memory and ephemeral-storage limits default to `resources.limitFactor` × the request (factor default `3`), and a CPU limit is only rendered when set explicitly — otherwise CPU stays unlimited (it is compressible, throttling instead of OOM-killing). The helper is duplicated into every chart because charts have no dependencies. - Charts have no dependencies (`charts/` directories are empty). diff --git a/apache-tika/Chart.yaml b/apache-tika/Chart.yaml index 5562956..c205293 100644 --- a/apache-tika/Chart.yaml +++ b/apache-tika/Chart.yaml @@ -4,5 +4,5 @@ description: A Helm chart to deploy Apache Tika on Kubernetes type: application -version: 6.0.0+up3.2.3.0.full +version: 7.0.0+up3.2.3.0.full appVersion: "3.2.3.0-full" diff --git a/apache-tika/templates/_helpers.tpl b/apache-tika/templates/_helpers.tpl new file mode 100644 index 0000000..5bbb4ab --- /dev/null +++ b/apache-tika/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "apache-tika.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "apache-tika.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "apache-tika.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "apache-tika.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "apache-tika.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "apache-tika.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "apache-tika.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/apache-tika/templates/deployment.yaml b/apache-tika/templates/deployment.yaml index 3e4d664..bebe14e 100644 --- a/apache-tika/templates/deployment.yaml +++ b/apache-tika/templates/deployment.yaml @@ -40,14 +40,7 @@ spec: startupProbe: {{- toYaml .Values.tika.startupProbe | nindent 12 }} resources: - requests: - memory: "{{ .Values.tika.resources.requests.memory }}" - cpu: "{{ .Values.tika.resources.requests.cpu }}" - ephemeral-storage: "{{ .Values.tika.resources.requests.ephemeralStorage }}" - limits: - memory: "{{ .Values.tika.resources.limits.memory }}" - cpu: "{{ .Values.tika.resources.limits.cpu }}" - ephemeral-storage: "{{ .Values.tika.resources.limits.ephemeralStorage }}" + {{- include "apache-tika.resources" .Values.tika.resources | nindent 12 }} volumes: - name: tmp emptyDir: {} diff --git a/apache-tika/values.yaml b/apache-tika/values.yaml index f86e60f..2387666 100644 --- a/apache-tika/values.yaml +++ b/apache-tika/values.yaml @@ -37,11 +37,11 @@ tika: timeoutSeconds: 5 failureThreshold: 30 resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: cpu: 0.1 memory: 512Mi - ephemeralStorage: 10Mi - limits: - cpu: 100m - memory: 768Mi - ephemeralStorage: 100Mi \ No newline at end of file + ephemeralStorage: 10Mi \ No newline at end of file diff --git a/calibre-web-automated/Chart.yaml b/calibre-web-automated/Chart.yaml index 7d27cf4..fea1ba4 100644 --- a/calibre-web-automated/Chart.yaml +++ b/calibre-web-automated/Chart.yaml @@ -4,7 +4,7 @@ type: application name: calibre-web-automated description: A Helm chart to deploy calibere-web-automated -version: 2.0.1+upv4.0.6 +version: 3.0.0+upv4.0.6 appVersion: v4.0.6 maintainers: diff --git a/calibre-web-automated/templates/_helpers.tpl b/calibre-web-automated/templates/_helpers.tpl new file mode 100644 index 0000000..f55ea7f --- /dev/null +++ b/calibre-web-automated/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "calibre-web-automated.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "calibre-web-automated.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "calibre-web-automated.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "calibre-web-automated.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "calibre-web-automated.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "calibre-web-automated.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "calibre-web-automated.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/calibre-web-automated/templates/calibre-web-automated.sfs.yaml b/calibre-web-automated/templates/calibre-web-automated.sfs.yaml index f5d25fa..1aef689 100644 --- a/calibre-web-automated/templates/calibre-web-automated.sfs.yaml +++ b/calibre-web-automated/templates/calibre-web-automated.sfs.yaml @@ -62,14 +62,7 @@ spec: startupProbe: {{- toYaml .Values.cwa.startupProbe | nindent 12 }} resources: - requests: - memory: "{{ .Values.cwa.resources.requests.memory }}" - cpu: "{{ .Values.cwa.resources.requests.cpu }}" - ephemeral-storage: "{{ .Values.cwa.resources.requests.ephemeralStorage }}" - limits: - memory: "{{ .Values.cwa.resources.limits.memory }}" - cpu: "{{ .Values.cwa.resources.limits.cpu }}" - ephemeral-storage: "{{ .Values.cwa.resources.limits.ephemeralStorage }}" + {{- include "calibre-web-automated.resources" .Values.cwa.resources | nindent 12 }} automountServiceAccountToken: false securityContext: fsGroup: 1000 diff --git a/calibre-web-automated/values.yaml b/calibre-web-automated/values.yaml index 9b87836..91f29ca 100644 --- a/calibre-web-automated/values.yaml +++ b/calibre-web-automated/values.yaml @@ -29,14 +29,14 @@ cwa: timeoutSeconds: 5 failureThreshold: 30 resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: cpu: 0.1 memory: 512Mi ephemeralStorage: 100Mi - limits: - cpu: 1 - memory: 1024Mi - ephemeralStorage: 200Mi ingress: clusterIssuer: "letsencrypt-issuer" diff --git a/cyberchef/Chart.yaml b/cyberchef/Chart.yaml index bc4a3b7..5d28ea2 100644 --- a/cyberchef/Chart.yaml +++ b/cyberchef/Chart.yaml @@ -4,7 +4,7 @@ description: A Helm chart to deploy Cyberchef on Kubernetes type: application -version: 3.0.0+up10.22.1 +version: 4.0.0+up10.22.1 appVersion: "10.22.1" maintainers: diff --git a/cyberchef/templates/_helpers.tpl b/cyberchef/templates/_helpers.tpl new file mode 100644 index 0000000..1b9c098 --- /dev/null +++ b/cyberchef/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "cyberchef.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "cyberchef.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "cyberchef.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "cyberchef.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "cyberchef.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "cyberchef.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "cyberchef.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/cyberchef/templates/cyberchef.deployment.yaml b/cyberchef/templates/cyberchef.deployment.yaml index 34640c3..ae7a155 100644 --- a/cyberchef/templates/cyberchef.deployment.yaml +++ b/cyberchef/templates/cyberchef.deployment.yaml @@ -42,14 +42,7 @@ spec: startupProbe: {{- toYaml .Values.cyberchef.startupProbe | nindent 12 }} resources: - requests: - memory: "{{ .Values.cyberchef.resources.requests.memory }}" - cpu: "{{ .Values.cyberchef.resources.requests.cpu }}" - ephemeral-storage: "{{ .Values.cyberchef.resources.requests.ephemeralStorage }}" - limits: - memory: "{{ .Values.cyberchef.resources.limits.memory }}" - cpu: "{{ .Values.cyberchef.resources.limits.cpu }}" - ephemeral-storage: "{{ .Values.cyberchef.resources.limits.ephemeralStorage }}" + {{- include "cyberchef.resources" .Values.cyberchef.resources | nindent 12 }} volumes: - name: nginx-cache emptyDir: {} diff --git a/cyberchef/values.yaml b/cyberchef/values.yaml index 6938c52..7655255 100644 --- a/cyberchef/values.yaml +++ b/cyberchef/values.yaml @@ -41,14 +41,14 @@ cyberchef: timeoutSeconds: 5 failureThreshold: 30 resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: cpu: 0.1 memory: 512Mi ephemeralStorage: 10Mi - limits: - cpu: 1 - memory: 768Mi - ephemeralStorage: 100Mi ingress: enabled: true diff --git a/gotenberg/Chart.yaml b/gotenberg/Chart.yaml index 096ac8b..23c102c 100644 --- a/gotenberg/Chart.yaml +++ b/gotenberg/Chart.yaml @@ -4,7 +4,7 @@ description: A Helm chart to deploy Gotenberg on Kubernetes type: application -version: 3.0.0+up8.26.0 +version: 4.0.0+up8.26.0 appVersion: "8.26.0" maintainers: diff --git a/gotenberg/templates/_helpers.tpl b/gotenberg/templates/_helpers.tpl new file mode 100644 index 0000000..dc23056 --- /dev/null +++ b/gotenberg/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "gotenberg.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "gotenberg.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "gotenberg.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "gotenberg.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "gotenberg.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "gotenberg.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "gotenberg.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/gotenberg/templates/deployment.yaml b/gotenberg/templates/deployment.yaml index b048c8d..98be79f 100644 --- a/gotenberg/templates/deployment.yaml +++ b/gotenberg/templates/deployment.yaml @@ -43,14 +43,7 @@ spec: startupProbe: {{- toYaml .Values.gotenberg.startupProbe | nindent 12 }} resources: - requests: - memory: "{{ .Values.gotenberg.resources.requests.memory }}" - cpu: "{{ .Values.gotenberg.resources.requests.cpu }}" - ephemeral-storage: "{{ .Values.gotenberg.resources.requests.ephemeralStorage }}" - limits: - memory: "{{ .Values.gotenberg.resources.limits.memory }}" - cpu: "{{ .Values.gotenberg.resources.limits.cpu }}" - ephemeral-storage: "{{ .Values.gotenberg.resources.limits.ephemeralStorage }}" + {{- include "gotenberg.resources" .Values.gotenberg.resources | nindent 12 }} volumes: - name: tmp emptyDir: {} diff --git a/gotenberg/values.yaml b/gotenberg/values.yaml index ed54738..3ee8e62 100644 --- a/gotenberg/values.yaml +++ b/gotenberg/values.yaml @@ -38,11 +38,11 @@ gotenberg: timeoutSeconds: 5 failureThreshold: 30 resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: cpu: 0.1 memory: 512Mi - ephemeralStorage: 10Mi - limits: - cpu: 1 - memory: 768Mi - ephemeralStorage: 100Mi \ No newline at end of file + ephemeralStorage: 10Mi \ No newline at end of file diff --git a/homeassistant/Chart.yaml b/homeassistant/Chart.yaml index df4bc41..501cc54 100644 --- a/homeassistant/Chart.yaml +++ b/homeassistant/Chart.yaml @@ -3,7 +3,7 @@ name: homeassistant description: A Helm chart to deploy Home Assistant on Kubernetes type: application -version: 3.0.0+up2026.2.3 +version: 4.0.0+up2026.2.3 appVersion: "2026.2.3" diff --git a/homeassistant/templates/_helpers.tpl b/homeassistant/templates/_helpers.tpl new file mode 100644 index 0000000..abb8c76 --- /dev/null +++ b/homeassistant/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "homeassistant.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "homeassistant.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "homeassistant.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "homeassistant.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "homeassistant.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "homeassistant.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "homeassistant.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/homeassistant/templates/homeassistant.sfs.yaml b/homeassistant/templates/homeassistant.sfs.yaml index 3fb7481..7bd84c6 100644 --- a/homeassistant/templates/homeassistant.sfs.yaml +++ b/homeassistant/templates/homeassistant.sfs.yaml @@ -39,14 +39,7 @@ spec: startupProbe: {{- toYaml .Values.startupProbe | nindent 12 }} resources: - limits: - cpu: {{ .Values.resources.limits.cpu }} - memory: {{ .Values.resources.limits.memory }} - ephemeral-storage: {{ .Values.resources.limits.ephemeralStorage }} - requests: - cpu: {{ .Values.resources.requests.cpu }} - memory: {{ .Values.resources.requests.memory }} - ephemeral-storage: {{ .Values.resources.requests.ephemeralStorage }} + {{- include "homeassistant.resources" .Values.resources | nindent 12 }} volumeMounts: - mountPath: /config/configuration.yaml subPath: configuration.yaml diff --git a/homeassistant/values.yaml b/homeassistant/values.yaml index e3ed2d5..124c8a1 100644 --- a/homeassistant/values.yaml +++ b/homeassistant/values.yaml @@ -43,14 +43,14 @@ securityContext: - NET_RAW resources: - limits: - cpu: 1 - memory: 1Gi - ephemeralStorage: 1Gi - requests: - cpu: 0.2 - memory: 512Mi - ephemeralStorage: 128Mi + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 + requests: + cpu: 0.2 + memory: 512Mi + ephemeralStorage: 128Mi # This is to setup the liveness, readiness and startup probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ livenessProbe: diff --git a/matrix-synapse/Chart.yaml b/matrix-synapse/Chart.yaml index 1bcac09..91dbd06 100644 --- a/matrix-synapse/Chart.yaml +++ b/matrix-synapse/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: matrix-synapse description: A Helm chart to deploy a Matrix Synapse server on Kubernetes type: application -version: 3.0.0+upv1.149.1 +version: 4.0.0+upv1.149.1 appVersion: "v1.149.1" maintainers: - name: jklein \ No newline at end of file diff --git a/matrix-synapse/templates/_helpers.tpl b/matrix-synapse/templates/_helpers.tpl new file mode 100644 index 0000000..523b1bb --- /dev/null +++ b/matrix-synapse/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "matrix-synapse.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "matrix-synapse.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "matrix-synapse.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "matrix-synapse.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "matrix-synapse.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "matrix-synapse.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "matrix-synapse.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/matrix-synapse/templates/matrix-delegation-nginx.deployment.yaml b/matrix-synapse/templates/matrix-delegation-nginx.deployment.yaml index 7d90d07..527ddee 100644 --- a/matrix-synapse/templates/matrix-delegation-nginx.deployment.yaml +++ b/matrix-synapse/templates/matrix-delegation-nginx.deployment.yaml @@ -36,14 +36,7 @@ spec: - name: tmp mountPath: /tmp resources: - limits: - memory: "{{ .Values.matrix.delegation.resources.limits.memory }}" - cpu: "{{ .Values.matrix.delegation.resources.limits.cpu }}" - ephemeral-storage: "{{ .Values.matrix.delegation.resources.limits.ephemeralStorage }}" - requests: - memory: "{{ .Values.matrix.delegation.resources.requests.memory }}" - cpu: "{{ .Values.matrix.delegation.resources.requests.cpu }}" - ephemeral-storage: "{{ .Values.matrix.delegation.resources.requests.ephemeralStorage }}" + {{- include "matrix-synapse.resources" .Values.matrix.delegation.resources | nindent 12 }} readinessProbe: httpGet: path: /.well-known/matrix/server diff --git a/matrix-synapse/templates/matrix-synapse.sfs.yaml b/matrix-synapse/templates/matrix-synapse.sfs.yaml index e27ea00..7c36a24 100644 --- a/matrix-synapse/templates/matrix-synapse.sfs.yaml +++ b/matrix-synapse/templates/matrix-synapse.sfs.yaml @@ -65,14 +65,7 @@ spec: timeoutSeconds: 5 failureThreshold: 30 resources: - requests: - memory: "{{ .Values.matrix.resources.requests.memory }}" - cpu: "{{ .Values.matrix.resources.requests.cpu }}" - ephemeral-storage: "{{ .Values.matrix.resources.requests.ephemeralStorage }}" - limits: - memory: "{{ .Values.matrix.resources.limits.memory }}" - cpu: "{{ .Values.matrix.resources.limits.cpu }}" - ephemeral-storage: "{{ .Values.matrix.resources.limits.ephemeralStorage }}" + {{- include "matrix-synapse.resources" .Values.matrix.resources | nindent 12 }} volumeMounts: - name: matrix-synapse-volume mountPath: /data diff --git a/matrix-synapse/values.yaml b/matrix-synapse/values.yaml index da802f5..c3a458c 100644 --- a/matrix-synapse/values.yaml +++ b/matrix-synapse/values.yaml @@ -21,23 +21,23 @@ matrix: drop: - ALL resources: - limits: - memory: "128Mi" - cpu: "250m" - ephemeralStorage: "100Mi" + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: memory: "64Mi" cpu: "125m" ephemeralStorage: "50Mi" resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: memory: "1Gi" cpu: "1" ephemeralStorage: "1Gi" - limits: - memory: "2Gi" - cpu: "2" - ephemeralStorage: "2Gi" storage: amount: 10Gi diff --git a/outline/Chart.yaml b/outline/Chart.yaml index 9f2d692..d13c211 100644 --- a/outline/Chart.yaml +++ b/outline/Chart.yaml @@ -4,7 +4,7 @@ description: A Helm chart to deploy Outline on Kubernetes type: application -version: 2.0.0+up1.9.2 +version: 3.0.0+up1.9.2 appVersion: 1.9.2 maintainers: diff --git a/outline/templates/_helpers.tpl b/outline/templates/_helpers.tpl new file mode 100644 index 0000000..9fb1504 --- /dev/null +++ b/outline/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "outline.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "outline.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "outline.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "outline.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "outline.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "outline.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "outline.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/outline/templates/outline.sfs.yaml b/outline/templates/outline.sfs.yaml index a9896fb..3af1530 100644 --- a/outline/templates/outline.sfs.yaml +++ b/outline/templates/outline.sfs.yaml @@ -108,14 +108,7 @@ spec: timeoutSeconds: 5 failureThreshold: 30 resources: - requests: - memory: "{{ .Values.outline.resources.requests.memory }}" - cpu: "{{ .Values.outline.resources.requests.cpu }}" - ephemeral-storage: "{{ .Values.outline.resources.requests.ephemeralStorage }}" - limits: - memory: "{{ .Values.outline.resources.limits.memory }}" - cpu: "{{ .Values.outline.resources.limits.cpu }}" - ephemeral-storage: "{{ .Values.outline.resources.limits.ephemeralStorage }}" + {{- include "outline.resources" .Values.outline.resources | nindent 12 }} volumeMounts: - mountPath: "/outline-data/data" name: outline-data diff --git a/outline/values.yaml b/outline/values.yaml index 54ff5ae..cd11687 100644 --- a/outline/values.yaml +++ b/outline/values.yaml @@ -11,14 +11,14 @@ outline: size: 10Gi storageClass: null resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: cpu: 0.1 memory: 512Mi ephemeralStorage: 10Mi - limits: - cpu: 1 - memory: 768Mi - ephemeralStorage: 100Mi ingress: maxUploadFileSize: 25m diff --git a/paperless-ngx/Chart.yaml b/paperless-ngx/Chart.yaml index af2ff57..0752716 100644 --- a/paperless-ngx/Chart.yaml +++ b/paperless-ngx/Chart.yaml @@ -4,7 +4,7 @@ description: A Helm chart to deploy Paperless-NGX on Kubernetes type: application -version: 6.0.0+up2.20.13 +version: 7.0.0+up2.20.13 appVersion: 2.20.13 diff --git a/paperless-ngx/templates/_helpers.tpl b/paperless-ngx/templates/_helpers.tpl new file mode 100644 index 0000000..e79cdd3 --- /dev/null +++ b/paperless-ngx/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "paperless-ngx.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "paperless-ngx.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "paperless-ngx.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "paperless-ngx.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "paperless-ngx.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "paperless-ngx.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "paperless-ngx.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/paperless-ngx/templates/paperless-consume.cronjob.yaml b/paperless-ngx/templates/paperless-consume.cronjob.yaml index 44a0ee6..e76ee40 100644 --- a/paperless-ngx/templates/paperless-consume.cronjob.yaml +++ b/paperless-ngx/templates/paperless-consume.cronjob.yaml @@ -30,14 +30,7 @@ spec: mountPath: "/mnt/consume" readOnly: false resources: - requests: - memory: "{{ .Values.smbConnection.cron.resources.requests.memory }}" - cpu: "{{ .Values.smbConnection.cron.resources.requests.cpu }}" - ephemeral-storage: "{{ .Values.smbConnection.cron.resources.requests.ephemeralStorage }}" - limits: - memory: "{{ .Values.smbConnection.cron.resources.limits.memory }}" - cpu: "{{ .Values.smbConnection.cron.resources.limits.cpu }}" - ephemeral-storage: "{{ .Values.smbConnection.cron.resources.limits.ephemeralStorage }}" + {{- include "paperless-ngx.resources" .Values.smbConnection.cron.resources | nindent 16 }} restartPolicy: Never volumes: - name: smb-share diff --git a/paperless-ngx/templates/paperless-server.sfs.yaml b/paperless-ngx/templates/paperless-server.sfs.yaml index 6228d2c..69d1bbd 100644 --- a/paperless-ngx/templates/paperless-server.sfs.yaml +++ b/paperless-ngx/templates/paperless-server.sfs.yaml @@ -199,14 +199,7 @@ spec: - mountPath: /run name: run resources: - requests: - memory: "{{ .Values.paperless.resources.requests.memory }}" - cpu: "{{ .Values.paperless.resources.requests.cpu }}" - ephemeral-storage: "{{ .Values.paperless.resources.requests.ephemeralStorage }}" - limits: - memory: "{{ .Values.paperless.resources.limits.memory }}" - cpu: "{{ .Values.paperless.resources.limits.cpu }}" - ephemeral-storage: "{{ .Values.paperless.resources.limits.ephemeralStorage }}" + {{- include "paperless-ngx.resources" .Values.paperless.resources | nindent 12 }} readinessProbe: httpGet: path: / diff --git a/paperless-ngx/values.yaml b/paperless-ngx/values.yaml index c007219..c3db1db 100644 --- a/paperless-ngx/values.yaml +++ b/paperless-ngx/values.yaml @@ -34,14 +34,14 @@ paperless: postConsumptionScripts: [] preConsumptionScripts: [] resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: cpu: 0.2 memory: 1024Mi ephemeralStorage: 200Mi - limits: - cpu: 1 - memory: 2048Mi - ephemeralStorage: 400Mi # Paperless-ngx supports rootless operation: the pod runs as uid/gid 1000 # (the image's default paperless user), fsGroup makes the PVCs writable and # /tmp + /run are emptyDirs so the root filesystem stays read-only. @@ -86,14 +86,14 @@ smbConnection: drop: - ALL resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: cpu: 10m memory: 16Mi ephemeralStorage: 10Mi - limits: - cpu: 100m - memory: 32Mi - ephemeralStorage: 50Mi oidc: enabled: false autoLoginWithProvider: false diff --git a/patchmon/Chart.yaml b/patchmon/Chart.yaml index 1b4e2c5..f3701fc 100644 --- a/patchmon/Chart.yaml +++ b/patchmon/Chart.yaml @@ -4,7 +4,7 @@ description: A Helm chart to deploy Patchmon on Kubernetes type: application -version: 3.0.0+up1.4.2 +version: 4.0.0+up1.4.2 appVersion: "1.4.2" maintainers: diff --git a/patchmon/templates/_helpers.tpl b/patchmon/templates/_helpers.tpl new file mode 100644 index 0000000..b58049e --- /dev/null +++ b/patchmon/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "patchmon.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "patchmon.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "patchmon.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "patchmon.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "patchmon.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "patchmon.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "patchmon.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/patchmon/templates/patchmon-backend.deployment.yaml b/patchmon/templates/patchmon-backend.deployment.yaml index bd8abf6..46e7363 100644 --- a/patchmon/templates/patchmon-backend.deployment.yaml +++ b/patchmon/templates/patchmon-backend.deployment.yaml @@ -159,10 +159,8 @@ spec: periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 30 - {{- with .Values.patchmon.backend.resources }} resources: - {{ toYaml . | nindent 12 }} - {{- end }} + {{- include "patchmon.resources" .Values.patchmon.backend.resources | nindent 12 }} volumeMounts: - mountPath: /app/assets name: patchmon-volume diff --git a/patchmon/templates/patchmon-frontend.deployment.yaml b/patchmon/templates/patchmon-frontend.deployment.yaml index 4115b85..ce85354 100644 --- a/patchmon/templates/patchmon-frontend.deployment.yaml +++ b/patchmon/templates/patchmon-frontend.deployment.yaml @@ -33,10 +33,8 @@ spec: value: "{{ .Release.Name }}-{{ .Chart.Name }}-backend-service" - name: BACKEND_PORT value: "80" - {{- with .Values.patchmon.frontend.resources }} resources: - {{- toYaml . | nindent 12 }} - {{- end }} + {{- include "patchmon.resources" .Values.patchmon.frontend.resources | nindent 12 }} livenessProbe: httpGet: path: / diff --git a/patchmon/values.yaml b/patchmon/values.yaml index 03c5705..b671621 100644 --- a/patchmon/values.yaml +++ b/patchmon/values.yaml @@ -22,24 +22,24 @@ patchmon: drop: - ALL resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: cpu: 0.1 memory: 128Mi ephemeral-storage: 10Mi - limits: - cpu: 0.5 - memory: 265Mi - ephemeral-storage: 100Mi backend: resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: cpu: 0.1 memory: 512Mi ephemeral-storage: 10Mi - limits: - cpu: 1 - memory: 768Mi - ephemeral-storage: 100Mi ingress: clusterIssuer: null diff --git a/rallly/Chart.yaml b/rallly/Chart.yaml index ae56f50..611b776 100644 --- a/rallly/Chart.yaml +++ b/rallly/Chart.yaml @@ -4,7 +4,7 @@ description: A Helm chart to deploy Rallly on Kubernetes type: application -version: 2.0.0+up4.8.1 +version: 3.0.0+up4.8.1 appVersion: "4.8.1" maintainers: diff --git a/rallly/templates/_helpers.tpl b/rallly/templates/_helpers.tpl new file mode 100644 index 0000000..0c01a8d --- /dev/null +++ b/rallly/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "rallly.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "rallly.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "rallly.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "rallly.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "rallly.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "rallly.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "rallly.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/rallly/templates/rallly.deployment.yaml b/rallly/templates/rallly.deployment.yaml index c40303e..2817f09 100644 --- a/rallly/templates/rallly.deployment.yaml +++ b/rallly/templates/rallly.deployment.yaml @@ -131,7 +131,7 @@ spec: startupProbe: {{ toYaml .Values.rallly.startupProbe | nindent 12}} resources: - {{ toYaml .Values.rallly.resources | nindent 12 }} + {{- include "rallly.resources" .Values.rallly.resources | nindent 12 }} securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true diff --git a/rallly/values.yaml b/rallly/values.yaml index db62bc8..2dcd478 100644 --- a/rallly/values.yaml +++ b/rallly/values.yaml @@ -15,14 +15,14 @@ rallly: emailClaimPath: 'email' nameClaimPath: 'name' resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: cpu: 0.1 memory: 512Mi ephemeral-storage: 100Mi - limits: - cpu: 1 - memory: 768Mi - ephemeral-storage: 250Mi livenessProbe: httpGet: path: / diff --git a/samba/Chart.yaml b/samba/Chart.yaml index 9c405a5..35bf24a 100644 --- a/samba/Chart.yaml +++ b/samba/Chart.yaml @@ -4,6 +4,6 @@ description: A Helm chart for Samba type: application -version: 2.0.0+up4.23.5 +version: 3.0.0+up4.23.5 appVersion: 4.23.5 diff --git a/samba/templates/_helpers.tpl b/samba/templates/_helpers.tpl new file mode 100644 index 0000000..edfcb21 --- /dev/null +++ b/samba/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "samba.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "samba.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "samba.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "samba.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "samba.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "samba.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "samba.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/samba/templates/samba.sfs.yaml b/samba/templates/samba.sfs.yaml index 96ae9a9..6d893f6 100644 --- a/samba/templates/samba.sfs.yaml +++ b/samba/templates/samba.sfs.yaml @@ -46,14 +46,7 @@ spec: startupProbe: {{- toYaml .Values.samba.startupProbe | nindent 12 }} resources: - requests: - memory: "{{ .Values.samba.resources.requests.memory }}" - cpu: "{{ .Values.samba.resources.requests.cpu }}" - ephemeral-storage: "{{ .Values.samba.resources.requests.ephemeralStorage }}" - limits: - memory: "{{ .Values.samba.resources.limits.memory }}" - cpu: "{{ .Values.samba.resources.limits.cpu }}" - ephemeral-storage: "{{ .Values.samba.resources.limits.ephemeralStorage }}" + {{- include "samba.resources" .Values.samba.resources | nindent 12 }} restartPolicy: Always automountServiceAccountToken: false securityContext: diff --git a/samba/values.yaml b/samba/values.yaml index 7de4f2c..a9d5c1b 100644 --- a/samba/values.yaml +++ b/samba/values.yaml @@ -28,14 +28,14 @@ samba: timeoutSeconds: 5 failureThreshold: 30 resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: memory: 50Mi cpu: 0.1 ephemeralStorage: 50Mi - limits: - memory: 100Mi - cpu: 1 - ephemeralStorage: 100Mi globalConfig: null storageClass: longhorn \ No newline at end of file diff --git a/satisfactory/Chart.yaml b/satisfactory/Chart.yaml index 82e9076..6f2c29a 100644 --- a/satisfactory/Chart.yaml +++ b/satisfactory/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: satisfactory description: A Helm chart to deploy a Satisfactory Gameserver on Kubernetes type: application -version: 2.0.0+upv1.9.10 +version: 3.0.0+upv1.9.10 appVersion: "v1.9.10" maintainers: - name: jklein \ No newline at end of file diff --git a/satisfactory/templates/_helpers.tpl b/satisfactory/templates/_helpers.tpl new file mode 100644 index 0000000..0766483 --- /dev/null +++ b/satisfactory/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "satisfactory.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "satisfactory.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "satisfactory.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "satisfactory.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "satisfactory.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "satisfactory.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "satisfactory.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/satisfactory/templates/satisfactory-server.sfs.yaml b/satisfactory/templates/satisfactory-server.sfs.yaml index 2dc10f1..0aecd63 100644 --- a/satisfactory/templates/satisfactory-server.sfs.yaml +++ b/satisfactory/templates/satisfactory-server.sfs.yaml @@ -74,10 +74,8 @@ spec: periodSeconds: 30 timeoutSeconds: 10 failureThreshold: 40 - {{- with .Values.server.resources }} resources: - {{ toYaml . | nindent 12 }} - {{- end }} + {{- include "satisfactory.resources" .Values.server.resources | nindent 12 }} volumeMounts: - name: satisfactory-volume mountPath: /config diff --git a/satisfactory/values.yaml b/satisfactory/values.yaml index e43d2a4..74399f6 100644 --- a/satisfactory/values.yaml +++ b/satisfactory/values.yaml @@ -11,11 +11,13 @@ server: messagingPort: 30888 storage: 20Gi resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + # The game server holds a large world in memory, so the default factor + # stays at 2 to keep the limit at the previously published 8Gi. + limitFactor: 2 requests: memory: "4Gi" cpu: "1" - ephemeral-storage: "5Gi" - limits: - memory: "8Gi" - cpu: "2" - ephemeral-storage: "10Gi" \ No newline at end of file + ephemeral-storage: "5Gi" \ No newline at end of file diff --git a/teamspeak-server/Chart.yaml b/teamspeak-server/Chart.yaml index cb35711..d3da79b 100644 --- a/teamspeak-server/Chart.yaml +++ b/teamspeak-server/Chart.yaml @@ -4,5 +4,5 @@ description: A Helm chart for deploying a teamspeak-server on Kubernetes type: application -version: 2.0.0+upv6.0.0.beta8 +version: 3.0.0+upv6.0.0.beta8 appVersion: "v6.0.0-beta8" diff --git a/teamspeak-server/templates/_helpers.tpl b/teamspeak-server/templates/_helpers.tpl new file mode 100644 index 0000000..4a83f50 --- /dev/null +++ b/teamspeak-server/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "teamspeak-server.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "teamspeak-server.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "teamspeak-server.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "teamspeak-server.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "teamspeak-server.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "teamspeak-server.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "teamspeak-server.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/teamspeak-server/templates/teamspeak-server.sfs.yaml b/teamspeak-server/templates/teamspeak-server.sfs.yaml index 453217b..ffd3e84 100644 --- a/teamspeak-server/templates/teamspeak-server.sfs.yaml +++ b/teamspeak-server/templates/teamspeak-server.sfs.yaml @@ -57,14 +57,7 @@ spec: timeoutSeconds: 5 failureThreshold: 30 resources: - requests: - cpu: "0.2" - memory: "100Mi" - ephemeral-storage: "100Mi" - limits: - cpu: "0.5" - memory: "200Mi" - ephemeral-storage: "200Mi" + {{- include "teamspeak-server.resources" .Values.resources | nindent 12 }} volumeMounts: - name: "teamspeak-volume" mountPath: /var/tsserver/ diff --git a/teamspeak-server/values.yaml b/teamspeak-server/values.yaml index c98112d..c42e098 100644 --- a/teamspeak-server/values.yaml +++ b/teamspeak-server/values.yaml @@ -1,3 +1,13 @@ +resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 + requests: + cpu: 0.2 + memory: 100Mi + ephemeral-storage: 100Mi + storage: size: 25Gi storageClass: longhorn \ No newline at end of file diff --git a/template-chart/templates/_helpers.tpl b/template-chart/templates/_helpers.tpl new file mode 100644 index 0000000..718c203 --- /dev/null +++ b/template-chart/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "xxx.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "xxx.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "xxx.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "xxx.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "xxx.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "xxx.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "xxx.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/template-chart/templates/xxx.deployment.yaml b/template-chart/templates/xxx.deployment.yaml index 8621e6a..7224196 100644 --- a/template-chart/templates/xxx.deployment.yaml +++ b/template-chart/templates/xxx.deployment.yaml @@ -52,7 +52,7 @@ spec: startupProbe: {{- toYaml .Values.xxx.startupProbe | nindent 12 }} resources: - {{- toYaml .Values.xxx.resources | nindent 12 }} + {{- include "xxx.resources" .Values.xxx.resources | nindent 12 }} securityContext: {{- toYaml .Values.xxx.securityContext.container | nindent 12 }} restartPolicy: Always diff --git a/template-chart/templates/xxx.sfs.yaml b/template-chart/templates/xxx.sfs.yaml index 91b1064..abf1372 100644 --- a/template-chart/templates/xxx.sfs.yaml +++ b/template-chart/templates/xxx.sfs.yaml @@ -53,7 +53,7 @@ spec: startupProbe: {{- toYaml .Values.xxx.startupProbe | nindent 12 }} resources: - {{- toYaml .Values.xxx.resources | nindent 12 }} + {{- include "xxx.resources" .Values.xxx.resources | nindent 12 }} securityContext: {{- toYaml .Values.xxx.securityContext.container | nindent 12 }} restartPolicy: Always diff --git a/template-chart/values.yaml b/template-chart/values.yaml index 5a437db..829e27c 100644 --- a/template-chart/values.yaml +++ b/template-chart/values.yaml @@ -3,14 +3,14 @@ secrets: xxx: resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: cpu: 0.1 memory: 512Mi ephemeral-storage: 10Mi - limits: - cpu: 1 - memory: 768Mi - ephemeral-storage: 100Mi livenessProbe: httpGet: path: / diff --git a/urlaubsverwaltung/Chart.yaml b/urlaubsverwaltung/Chart.yaml index 1c1d0af..5a13528 100644 --- a/urlaubsverwaltung/Chart.yaml +++ b/urlaubsverwaltung/Chart.yaml @@ -3,5 +3,5 @@ name: urlaubsverwaltung description: A Helm chart to deploy urlaubsverwaltung on Kubernetes type: application -version: 3.0.0+up6.5.0 +version: 4.0.0+up6.5.0 appVersion: 6.5.0 diff --git a/urlaubsverwaltung/templates/_helpers.tpl b/urlaubsverwaltung/templates/_helpers.tpl new file mode 100644 index 0000000..ffc2dc9 --- /dev/null +++ b/urlaubsverwaltung/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "urlaubsverwaltung.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "urlaubsverwaltung.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "urlaubsverwaltung.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "urlaubsverwaltung.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "urlaubsverwaltung.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "urlaubsverwaltung.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "urlaubsverwaltung.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/urlaubsverwaltung/templates/urlaubsverwaltung.deployment.yaml b/urlaubsverwaltung/templates/urlaubsverwaltung.deployment.yaml index ab9012f..0e882bb 100644 --- a/urlaubsverwaltung/templates/urlaubsverwaltung.deployment.yaml +++ b/urlaubsverwaltung/templates/urlaubsverwaltung.deployment.yaml @@ -110,14 +110,7 @@ spec: - name: UV_SECURITY_OIDC_CLAIM-MAPPERS_GROUP-CLAIM_CLAIM-NAME value: "groups" resources: - requests: - memory: "{{ .Values.urlaubsverwaltung.resources.requests.memory }}" - cpu: "{{ .Values.urlaubsverwaltung.resources.requests.cpu }}" - ephemeral-storage: "{{ .Values.urlaubsverwaltung.resources.requests.ephemeralStorage }}" - limits: - memory: "{{ .Values.urlaubsverwaltung.resources.limits.memory }}" - cpu: "{{ .Values.urlaubsverwaltung.resources.limits.cpu }}" - ephemeral-storage: "{{ .Values.urlaubsverwaltung.resources.limits.ephemeralStorage }}" + {{- include "urlaubsverwaltung.resources" .Values.urlaubsverwaltung.resources | nindent 12 }} readinessProbe: httpGet: port: 8080 diff --git a/urlaubsverwaltung/values.yaml b/urlaubsverwaltung/values.yaml index 8032e92..fc22e02 100644 --- a/urlaubsverwaltung/values.yaml +++ b/urlaubsverwaltung/values.yaml @@ -23,11 +23,11 @@ urlaubsverwaltung: drop: - ALL resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: cpu: 0.1 memory: 768Mi - ephemeralStorage: 10Mi - limits: - cpu: 1 - memory: 1536Mi ephemeralStorage: 10Mi \ No newline at end of file diff --git a/voucher-vault/Chart.yaml b/voucher-vault/Chart.yaml index d4b5316..7a767ca 100644 --- a/voucher-vault/Chart.yaml +++ b/voucher-vault/Chart.yaml @@ -4,7 +4,7 @@ description: A Helm chart to deploy VoucherVault on Kubernetes type: application -version: 2.0.0+up1.27.4 +version: 3.0.0+up1.27.4 appVersion: "1.27.4" maintainers: diff --git a/voucher-vault/templates/_helpers.tpl b/voucher-vault/templates/_helpers.tpl new file mode 100644 index 0000000..7827952 --- /dev/null +++ b/voucher-vault/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "voucher-vault.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "voucher-vault.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "voucher-vault.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "voucher-vault.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "voucher-vault.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "voucher-vault.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "voucher-vault.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/voucher-vault/templates/voucher-vault.sfs.yaml b/voucher-vault/templates/voucher-vault.sfs.yaml index f0f1032..27015bf 100644 --- a/voucher-vault/templates/voucher-vault.sfs.yaml +++ b/voucher-vault/templates/voucher-vault.sfs.yaml @@ -59,7 +59,7 @@ spec: {{- toYaml .Values.voucherVault.startupProbe | nindent 12 }} {{- end }} resources: - {{- toYaml .Values.voucherVault.resources | nindent 12 }} + {{- include "voucher-vault.resources" .Values.voucherVault.resources | nindent 12 }} securityContext: {{- toYaml .Values.voucherVault.securityContext.container | nindent 12 }} volumeMounts: diff --git a/voucher-vault/values.yaml b/voucher-vault/values.yaml index 0749bdf..ab5bec8 100644 --- a/voucher-vault/values.yaml +++ b/voucher-vault/values.yaml @@ -5,14 +5,14 @@ secrets: voucherVault: resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: cpu: 0.1 memory: 256Mi ephemeral-storage: 10Mi - limits: - cpu: 1 - memory: 384Mi - ephemeral-storage: 100Mi # "/" answers with a redirect for anonymous users, which httpGet treats as # success. The Host header must be set to 127.0.0.1 because Django's # ALLOWED_HOSTS only accepts 127.0.0.1 and the configured DOMAIN — probing diff --git a/zipline/Chart.yaml b/zipline/Chart.yaml index 9786702..2ea87e7 100644 --- a/zipline/Chart.yaml +++ b/zipline/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 3.0.0+up4.6.4 +version: 4.0.0+up4.6.4 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/zipline/templates/_helpers.tpl b/zipline/templates/_helpers.tpl new file mode 100644 index 0000000..df273d7 --- /dev/null +++ b/zipline/templates/_helpers.tpl @@ -0,0 +1,85 @@ +{{/* +Render the body of a container "resources:" block from a values dict of the form + + resources: + limitFactor: 3 # optional, default 3 + requests: { cpu, memory, ephemeral-storage / ephemeralStorage, ... } + limits: { ... } # optional, every entry optional + +Rules (variant B, see issue #19): + - requests are rendered as given (camelCase "ephemeralStorage" is normalized + to the Kubernetes key "ephemeral-storage"). + - an explicitly set limit always wins. + - a missing memory / ephemeral-storage limit is computed as + limitFactor x the corresponding request. + - a missing cpu limit is NOT set at all (the kubelet then treats CPU as + unlimited; CPU is compressible, so this cannot kill the workload). + +Usage (the values path to the resources dict varies per chart): + resources: + {{- include "zipline.resources" .Values..resources | nindent 12 }} + +NOTE: charts in this repo deliberately have no dependencies, so this helper is +duplicated into every chart's templates/_helpers.tpl with the chart's name as +define prefix. This file in template-chart is the reference implementation. +*/}} +{{- define "zipline.resources" -}} +{{- $resources := . | default dict -}} +{{- $factor := 3.0 -}} +{{- if not (kindIs "invalid" $resources.limitFactor) -}} +{{- $factor = float64 $resources.limitFactor -}} +{{- end -}} +{{- $requests := dict -}} +{{- range $key, $value := ($resources.requests | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $requests (include "zipline.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- $limits := dict -}} +{{- range $key, $value := ($resources.limits | default dict) -}} +{{- if not (kindIs "invalid" $value) -}} +{{- $_ := set $limits (include "zipline.resourceKey" $key) $value -}} +{{- end -}} +{{- end -}} +{{- range $key, $request := $requests -}} +{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}} +{{- $_ := set $limits $key (include "zipline.multiplyQuantity" (dict "quantity" $request "factor" $factor)) -}} +{{- end -}} +{{- end -}} +{{- $out := dict -}} +{{- with $requests }}{{- $_ := set $out "requests" . }}{{- end -}} +{{- with $limits }}{{- $_ := set $out "limits" . }}{{- end -}} +{{- toYaml $out -}} +{{- end -}} + +{{/* +Normalize a resource name from values to its Kubernetes key. +*/}} +{{- define "zipline.resourceKey" -}} +{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}} +{{- end -}} + +{{/* +Multiply a Kubernetes quantity by a factor, keeping its suffix. +Input: dict "quantity" "factor" . +Handles plain numbers ("2", "0.5", 1073741824), decimal ("1.5Gi"), binary +("512Mi", "1Gi", "10Ki") and milli/SI suffixes ("100m", "500M"). Integer +results are printed without a decimal point. +*/}} +{{- define "zipline.multiplyQuantity" -}} +{{- $quantity := printf "%v" .quantity -}} +{{- $number := regexFind "^[0-9]+(\\.[0-9]+)?" $quantity -}} +{{- if not $number -}} +{{- fail (printf "cannot parse resource quantity %q" $quantity) -}} +{{- end -}} +{{- $suffix := trimPrefix $number $quantity -}} +{{- if not (regexMatch "^(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei)?$" $suffix) -}} +{{- fail (printf "unsupported resource quantity suffix %q in %q" $suffix $quantity) -}} +{{- end -}} +{{- $product := mulf (float64 $number) .factor -}} +{{- if eq $product (floor $product) -}} +{{- printf "%d%s" (int64 $product) $suffix -}} +{{- else -}} +{{- printf "%v%s" $product $suffix -}} +{{- end -}} +{{- end -}} diff --git a/zipline/templates/zipline.sfs.yaml b/zipline/templates/zipline.sfs.yaml index c3215f6..f54cb2b 100644 --- a/zipline/templates/zipline.sfs.yaml +++ b/zipline/templates/zipline.sfs.yaml @@ -36,14 +36,7 @@ spec: - name: UPLOADER_ADMIN_LIMIT value: 500mb resources: - requests: - memory: "{{ .Values.zipline.resources.requests.memory }}" - cpu: "{{ .Values.zipline.resources.requests.cpu }}" - ephemeral-storage: "{{ .Values.zipline.resources.requests.ephemeralStorage }}" - limits: - memory: "{{ .Values.zipline.resources.limits.memory }}" - cpu: "{{ .Values.zipline.resources.limits.cpu }}" - ephemeral-storage: "{{ .Values.zipline.resources.limits.ephemeralStorage }}" + {{- include "zipline.resources" .Values.zipline.resources | nindent 12 }} ports: - name: "zipline-server" containerPort: 3000 diff --git a/zipline/values.yaml b/zipline/values.yaml index 7d4a4d0..c47b5d8 100644 --- a/zipline/values.yaml +++ b/zipline/values.yaml @@ -51,11 +51,11 @@ zipline: timeoutSeconds: 5 failureThreshold: 30 resources: + # Limits are optional: memory and ephemeral-storage limits default to + # limitFactor x the request, an explicitly set limit always wins, and a + # CPU limit is only set when configured explicitly under "limits". + limitFactor: 3 requests: cpu: 0.1 memory: 265Mi - ephemeralStorage: 100Mi - limits: - cpu: 1 - memory: 768Mi - ephemeralStorage: 200Mi \ No newline at end of file + ephemeralStorage: 100Mi \ No newline at end of file