bentopdf: new chart for the PDF toolbox (1.0.0+up2.8.7)

BentoPDF computes entirely in the visitor's browser; the container only serves
static files through nginx. The chart is therefore close to cyberchef - same
nginx-unprivileged base, uid 101, port 8080, probes on "/" - with four
differences that shaped the design.

Runtime config.json. The one setting reachable at runtime is the tool list.
It is a static file in the middle of the web root, so it is mounted by
subPath: a directory mount would hide the whole application. subPath mounts
are never refreshed by the kubelet, which makes the checksum/config annotation
(#82) load-bearing rather than decorative. bentopdf.config is passed through
verbatim, like searxng's settings, so a key upstream adds tomorrow is a values
change and not a chart change.

Three env switches that would kill the pod. PORT, DISABLE_IPV6 and
ROBOTS_NOINDEX are implemented as "sed -i" against files in the image, run
under "set -e" in /docker-entrypoint.d/, and the base image's entrypoint
aborts when one of them fails. With readOnlyRootFilesystem: true the pod
therefore never starts instead of ignoring the switch - measured in k3d as
CrashLoopBackOff, exit 1, "sed: can't create temp file
'/etc/nginx/nginx.confXXXXXX': Read-only file system". None of the three is
offered as a first-class value; values.yaml names the failure picture and the
escape hatch (env block plus readOnlyRootFilesystem: false).

Writable paths were measured, not copied from the upstream chart.
/etc/nginx/tmp holds the pid file and /var/cache/nginx is where nginx creates
its temp directories at startup - without it the master aborts with
'mkdir() "/var/cache/nginx/client_temp" failed'. /var/run is deliberately not
mounted: the running pod proves it is unnecessary.

Everything else about BentoPDF is a build-time argument and out of reach for
any chart; values.yaml says so explicitly rather than leaving it to be
discovered. Two accepted consequences are named there too: some tools fetch
WASM modules from a public CDN at runtime, and the served pages carry a
canonical link to the vendor's site.

Fixes #174
This commit is contained in:
jklein committed 2026-08-28 18:22:30 +02:00
1 parent ce5f654a8a
commit 8df1913c5c
14 files changed
+1049

No files matched your search

+81
View File
@@ -0,0 +1,81 @@
{{- $replicas := include "bentopdf.replicas" (dict "scaleDown" .Values.scaleDown "replicas" .Values.bentopdf.replicas) -}}
BentoPDF {{ .Chart.AppVersion }} — release {{ .Release.Name }} in namespace {{ .Release.Namespace }}.
{{- if .Values.ingress.enabled }}
ACCESS
https://{{ .Values.ingress.domain }}
The certificate is requested by cert-manager through the "{{ .Values.ingress.clusterIssuer }}"
cluster issuer. Until it has been issued the browser shows a warning; follow it with
kubectl -n {{ .Release.Namespace }} get certificate tls-{{ .Release.Name }}-{{ .Chart.Name }}-ingress
This chart has no secrets and no volumes — the two ingress values above are
everything an installation needs.
{{- else }}
ACCESS — NO INGRESS
ingress.enabled is false, so this release has no Ingress and no certificate;
ingress.domain and ingress.clusterIssuer are not needed. The app is only
reachable inside the cluster, as
{{ .Release.Name }}-{{ .Chart.Name }}-service:80. To open it locally:
kubectl -n {{ .Release.Namespace }} port-forward svc/{{ .Release.Name }}-{{ .Chart.Name }}-service 8080:80
Then browse to http://localhost:8080. Set ingress.enabled=true together with
ingress.domain and ingress.clusterIssuer to publish it instead.
{{- end }}
{{ if eq $replicas "0" }}
SCALED TO ZERO
{{ if .Values.scaleDown }}scaleDown: true{{ else }}bentopdf.replicas: 0{{ end }} — the deployment runs with replicas: 0, so the endpoint
above does not answer until you set it back and upgrade again. Service{{ if .Values.ingress.enabled }} and
Ingress stay in place, so the certificate is not re-issued.{{ else }} stays in
place.{{ end }}
{{ end }}
A GREEN POD ONLY PROVES DELIVERY
BentoPDF computes in the visitor's browser: not one of its tools runs in
this pod, which serves static files and nothing else. The probes hit "/"
because the image has no health endpoint, so they prove that nginx is
handing out index.html — no more. Whether PDF processing works is a
question about the browser, not about this release.
TWO HEADERS HAVE TO SURVIVE YOUR INGRESS CONTROLLER
The image sends Cross-Origin-Opener-Policy: same-origin and
Cross-Origin-Embedder-Policy: credentialless. Without both arriving at the
browser there is no SharedArrayBuffer, and the LibreOffice-backed
conversions (Word, Excel, PowerPoint) fail while everything else keeps
working. Check them through the ingress, not at the pod:
curl -sI https://{{ if .Values.ingress.enabled }}{{ .Values.ingress.domain }}{{ else }}<host>{{ end }}/ | grep -i cross-origin
ANYONE WHO REACHES THE URL CAN USE IT
BentoPDF has no login, and this chart adds none. That is defensible here —
the server takes nothing in, stores nothing and has no session — but a
public instance also gets indexed, and its pages carry a canonical link to
the vendor's site. Both are addressed through ingress.annotations; see
values.yaml.
NOTHING TO BACK UP, NOTHING TO MIGRATE
No database, no volumes, no uploads: documents never leave the visitor's
device. App-version upgrades and rollbacks carry no data risk.
{{- if .Values.bentopdf.config }}
TOOLS ARE DISABLED VIA config.json
bentopdf.config is set and is served as /config.json. A change here rolls
the pods (checksum/config), but browsers may keep the old file for up to a
week — the image serves .json with Cache-Control: max-age=604800. Verify
what is actually being served with:
kubectl -n {{ .Release.Namespace }} exec deploy/{{ .Release.Name }}-{{ .Chart.Name }}-deployment -- wget -qO- localhost:8080/config.json
{{- end }}
{{- if .Values.bentopdf.env }}
bentopdf.env HAS NO EFFECT ON THE APP — AND THREE VALUES BREAK THE POD
The served BentoPDF bundle is static and reads no environment variables;
entries only reach nginx and its entrypoint scripts. Beware of PORT,
DISABLE_IPV6 and ROBOTS_NOINDEX: all three rewrite files with "sed -i" and
abort the entrypoint on a read-only root filesystem, so the pod never
starts. Using them means also setting
securityContext.container.readOnlyRootFilesystem: false.
{{- end }}
+297
View File
@@ -0,0 +1,297 @@
{{/*
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 "bentopdf.resources" .Values.<app>.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 "bentopdf.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 "bentopdf.resourceKey" $key) $value -}}
{{- end -}}
{{- end -}}
{{- $limits := dict -}}
{{- range $key, $value := ($resources.limits | default dict) -}}
{{- if not (kindIs "invalid" $value) -}}
{{- $_ := set $limits (include "bentopdf.resourceKey" $key) $value -}}
{{- end -}}
{{- end -}}
{{- range $key, $request := $requests -}}
{{- if and (ne $key "cpu") (not (hasKey $limits $key)) -}}
{{- $_ := set $limits $key (include "bentopdf.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 "bentopdf.resourceKey" -}}
{{- if eq . "ephemeralStorage" -}}ephemeral-storage{{- else -}}{{ . }}{{- end -}}
{{- end -}}
{{/*
Multiply a Kubernetes quantity by a factor, keeping its suffix.
Input: dict "quantity" <string|number> "factor" <float64>.
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 "bentopdf.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 -}}
{{/*
Render the replica count for a Deployment/StatefulSet.
Input: dict
"scaleDown" the chart-global .Values.scaleDown flag (may be nil)
"replicas" the workload's replicas value (may be nil)
Rules (issue #25):
- scaleDown: true takes precedence and always yields 0.
- otherwise an explicitly set replicas value is used as given, including an
explicit 0 — Helm's "default" would swallow 0, hence the explicit
kindIs "invalid" nil check.
- a missing replicas value defaults to 1.
Usage (the values path to the workload's replicas varies per chart):
replicas: {{ include "bentopdf.replicas" (dict "scaleDown" .Values.scaleDown "replicas" .Values.<app>.replicas) }}
NOTE: like the resources helper above, this 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 "bentopdf.replicas" -}}
{{- if .scaleDown -}}
0
{{- else if not (kindIs "invalid" .replicas) -}}
{{- .replicas -}}
{{- else -}}
1
{{- end -}}
{{- end -}}
{{/*
Merge a user-supplied values sub-tree onto a dict of chart defaults so that a
null / empty override falls back to the defaults instead of erasing them.
Input: dict "defaults" <dict> "given" <dict|nil> "path" <string, optional
values path used in error messages>. Output: YAML of the merged dict (consume
it with fromYaml).
Why this exists (issue #99): Helm merges values maps recursively, but an
override key written without children — e.g. a leftover
securityContext:
after deleting its last remaining sub-key — is YAML null and replaces the
whole default sub-tree. The container then renders with "securityContext:
null": no readOnlyRootFilesystem, no dropped capabilities, no
allowPrivilegeEscalation: false. The workload starts and reports healthy while
being unhardened, so nothing points at the mistake. The same shape erases a
probe (it disappears) or the resources block (no requests, no computed
limits). This helper defines the opposite semantics: an empty block means
"chart defaults apply".
Rules:
- a nil "given" is treated as an empty dict (all defaults apply).
- a key whose override value is null keeps the default (nulls never delete).
- a key present in both as a map is merged recursively, so a partially
filled block only overrides the keys it actually sets.
- a scalar override for a key the defaults define as a map is rejected with
a message naming the values path, instead of failing later with a template
field error.
- any other set value wins as given, including an explicit false or 0 —
Helm's "default" and sprig's "mergeOverwrite" would both swallow those
zero values, hence the explicit kindIs "invalid" nil check.
- keys only present in the override are passed through unchanged.
NOTE: like the helpers above, this is duplicated into every chart's
templates/_helpers.tpl with the chart's name as define prefix, because charts
in this repo deliberately have no dependencies.
*/}}
{{- define "bentopdf.defaultedDict" -}}
{{- $defaults := .defaults | default dict -}}
{{- $given := .given -}}
{{- $path := .path | default "value" -}}
{{- if kindIs "invalid" $given -}}
{{- $given = dict -}}
{{- end -}}
{{- if not (kindIs "map" $given) -}}
{{- fail (printf "%s must be a mapping or null, got %s (%v)" $path (kindOf $given) $given) -}}
{{- end -}}
{{- $out := deepCopy $defaults -}}
{{- range $key, $value := $given -}}
{{- if not (kindIs "invalid" $value) -}}
{{- $default := index $defaults $key -}}
{{- if and (kindIs "map" $value) (kindIs "map" $default) -}}
{{- $_ := set $out $key (fromYaml (include "bentopdf.defaultedDict" (dict "defaults" $default "given" $value "path" (printf "%s.%s" $path $key)))) -}}
{{- else if kindIs "map" $default -}}
{{- fail (printf "%s.%s must be a mapping or null, got %s (%v)" $path $key (kindOf $value) $value) -}}
{{- else -}}
{{- $_ := set $out $key $value -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- toYaml $out -}}
{{- end -}}
{{/*
Pick one sub-block out of a values block that may itself be null.
Input: dict "block" <dict|nil> "key" <string> "path" <string>.
Returns YAML of dict "value" <the sub-block, may be nil>, after rejecting a
non-mapping block with a message that names the values path. Needed because
".Values.bentopdf.securityContext" can itself be erased.
*/}}
{{- define "bentopdf.subBlock" -}}
{{- $block := .block -}}
{{- if kindIs "invalid" $block -}}
{{- $block = dict -}}
{{- end -}}
{{- if not (kindIs "map" $block) -}}
{{- fail (printf "%s must be a mapping or null, got %s (%v)" .path (kindOf $block) $block) -}}
{{- end -}}
{{- toYaml (dict "value" (index $block .key)) -}}
{{- end -}}
{{/*
The effective security contexts, probes and resources (issue #99).
The defaults below MUST stay in sync with the corresponding blocks in
values.yaml, which stays the documented, user-facing place for them; this copy
is only the fallback for the case where an override has erased the block.
The probes address the container port by its name ("http"), so a rebuilt
default probe needs no further context.
*/}}
{{- define "bentopdf.podSecurityContext" -}}
{{- $given := (fromYaml (include "bentopdf.subBlock" (dict "block" . "key" "pod" "path" "bentopdf.securityContext"))).value -}}
{{- $defaults := dict
"runAsNonRoot" true
"runAsUser" 101
"runAsGroup" 101
"seccompProfile" (dict "type" "RuntimeDefault") -}}
{{- include "bentopdf.defaultedDict" (dict "defaults" $defaults "given" $given "path" "bentopdf.securityContext.pod") -}}
{{- end -}}
{{- define "bentopdf.containerSecurityContext" -}}
{{- $given := (fromYaml (include "bentopdf.subBlock" (dict "block" . "key" "container" "path" "bentopdf.securityContext"))).value -}}
{{- $defaults := dict
"allowPrivilegeEscalation" false
"readOnlyRootFilesystem" true
"runAsNonRoot" true
"capabilities" (dict "drop" (list "ALL")) -}}
{{- include "bentopdf.defaultedDict" (dict "defaults" $defaults "given" $given "path" "bentopdf.securityContext.container") -}}
{{- end -}}
{{- define "bentopdf.livenessProbe" -}}
{{- $defaults := dict
"httpGet" (dict "path" "/" "port" "http")
"periodSeconds" 10
"timeoutSeconds" 5
"failureThreshold" 3 -}}
{{- include "bentopdf.defaultedDict" (dict "defaults" $defaults "given" . "path" "bentopdf.livenessProbe") -}}
{{- end -}}
{{- define "bentopdf.readinessProbe" -}}
{{- $defaults := dict
"httpGet" (dict "path" "/" "port" "http")
"periodSeconds" 10
"timeoutSeconds" 5
"failureThreshold" 3 -}}
{{- include "bentopdf.defaultedDict" (dict "defaults" $defaults "given" . "path" "bentopdf.readinessProbe") -}}
{{- end -}}
{{- define "bentopdf.startupProbe" -}}
{{- $defaults := dict
"httpGet" (dict "path" "/" "port" "http")
"periodSeconds" 5
"timeoutSeconds" 5
"failureThreshold" 30 -}}
{{- include "bentopdf.defaultedDict" (dict "defaults" $defaults "given" . "path" "bentopdf.startupProbe") -}}
{{- end -}}
{{/*
The effective resources block, fed into the resources helper above so that an
erased "resources:" still yields the chart's requests and computed limits
instead of a container without any resource accounting.
*/}}
{{- define "bentopdf.effectiveResources" -}}
{{- $defaults := dict
"limitFactor" 3
"requests" (dict "cpu" 0.1 "memory" "128Mi" "ephemeralStorage" "16Mi") -}}
{{- $merged := fromYaml (include "bentopdf.defaultedDict" (dict "defaults" $defaults "given" . "path" "bentopdf.resources")) -}}
{{- include "bentopdf.resources" $merged -}}
{{- end -}}
{{/*
The body of config.json, rendered from bentopdf.config.
The block is passed through verbatim rather than being built from named keys:
the schema of this file is upstream's (today "disabledTools" and
"editorDisabledCategories"), so a key it adds tomorrow is a values change and
not a chart change.
Unlike the probe and securityContext helpers, this one does NOT merge onto
chart defaults - there are none to merge onto, and inventing some would mean
disabling tools nobody asked to disable. An erased or missing block therefore
renders "{}", which is the same file the image itself ships. What the helper
does add is the null check plus a typed error: a scalar under bentopdf.config
would otherwise reach toJson and produce a config.json that is valid JSON,
serves with 200 and configures nothing.
*/}}
{{- define "bentopdf.configJson" -}}
{{- $config := . -}}
{{- if kindIs "invalid" $config -}}
{{- $config = dict -}}
{{- end -}}
{{- if not (kindIs "map" $config) -}}
{{- fail (printf "bentopdf.config must be a mapping or null, got %s (%v)" (kindOf $config) $config) -}}
{{- end -}}
{{- toPrettyJson $config -}}
{{- end -}}
@@ -0,0 +1,17 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: "{{ .Release.Name }}-{{ .Chart.Name }}-configmap"
data:
# Mounted at /usr/share/nginx/html/config.json via subPath. The subPath is
# not a matter of taste here: the file sits in the middle of the web root,
# and a plain directory mount would hide the entire served application
# behind an almost empty volume.
#
# It is always rendered, even for an empty config - a file that sometimes
# exists and sometimes does not would mean the path through checksum, mount
# and subPath is normally never exercised and first fails when someone
# actually uses it. Empty renders as "{}", which is byte-identical to the
# config.json the image ships anyway.
config.json: |
{{- include "bentopdf.configJson" .Values.bentopdf.config | nindent 4 }}
+120
View File
@@ -0,0 +1,120 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-{{ .Chart.Name }}-deployment
labels:
app: {{ .Release.Name }}-{{ .Chart.Name }}-deployment
spec:
replicas: {{ include "bentopdf.replicas" (dict "scaleDown" .Values.scaleDown "replicas" .Values.bentopdf.replicas) }}
selector:
matchLabels:
app: {{ .Release.Name }}-{{ .Chart.Name }}-deployment
template:
metadata:
name: {{ .Release.Name }}-{{ .Chart.Name }}-deployment
labels:
app: {{ .Release.Name }}-{{ .Chart.Name }}-deployment
annotations:
# Hash of the rendered ConfigMap: a changed config.json changes the pod
# template and thus rolls the pods. Mandatory here rather than nice to
# have - config.json is a subPath mount, which the kubelet never
# refreshes, so without this annotation a changed tool list would stay
# invisible until someone restarted the pods for an unrelated reason.
checksum/config: {{ include (print $.Template.BasePath "/bentopdf.configmap.yaml") . | sha256sum }}
spec:
automountServiceAccountToken: false
securityContext:
{{- include "bentopdf.podSecurityContext" .Values.bentopdf.securityContext | nindent 8 }}
containers:
- name: {{ .Release.Name }}-{{ .Chart.Name }}-deployment
# The "-simple" variant on purpose: it is built from the same
# Dockerfile as ghcr.io/alam00000/bentopdf, the difference being the
# SIMPLE_MODE build argument, which strips the marketing surface of
# the commercial site. That has no place on an internal instance.
image: "ghcr.io/alam00000/bentopdf-simple:{{ .Chart.AppVersion }}"
imagePullPolicy: IfNotPresent
{{- if .Values.bentopdf.env }}
env:
{{- range $value := .Values.bentopdf.env }}
{{- if $value.value }}
- name: {{ $value.name | quote }}
value: {{ tpl $value.value $ | quote }}
{{- else if $value.valueFrom }}
{{- if $value.valueFrom.secretKeyRef }}
- name: {{ $value.name | quote }}
valueFrom:
secretKeyRef:
name: {{ tpl $value.valueFrom.secretKeyRef.name $ | quote }}
key: {{ tpl $value.valueFrom.secretKeyRef.key $ | quote }}
{{- else if $value.valueFrom.configMapKeyRef }}
- name: {{ $value.name | quote }}
valueFrom:
configMapKeyRef:
name: {{ tpl $value.valueFrom.configMapKeyRef.name $ | quote }}
key: {{ tpl $value.valueFrom.configMapKeyRef.key $ | quote }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
securityContext:
{{- include "bentopdf.containerSecurityContext" .Values.bentopdf.securityContext | nindent 12 }}
volumeMounts:
- name: config
mountPath: /usr/share/nginx/html/config.json
subPath: config.json
readOnly: true
# The two writable paths below are what keeps
# readOnlyRootFilesystem: true possible. Both are image facts, not
# user configuration, so neither is a value - and both are here
# because a run without them failed, not because the upstream
# chart mounts them.
- name: nginx-tmp
# The nginx.conf puts its pid file at /etc/nginx/tmp/nginx.pid.
mountPath: /etc/nginx/tmp
- name: nginx-cache
# NOT optional: nginx creates its temp directories at startup and
# the image ships /var/cache/nginx without them. Missing this
# mount, the master process aborts before serving anything, with
# [emerg] mkdir() "/var/cache/nginx/client_temp" failed
# (30: Read-only file system)
mountPath: /var/cache/nginx
# /var/run is deliberately NOT mounted. The upstream chart mounts
# it, but this image keeps its pid file under /etc/nginx/tmp, and a
# run with only the two mounts above serves / and /config.json with
# 200. An emptyDir nobody writes to is a claim the chart cannot
# back up.
ports:
# 8080 is the image's EXPOSE and the port its nginx.conf listens
# on. It is not a value, because a value here would lie: the image
# switch that moves the port (PORT) rewrites nginx.conf with sed
# and therefore cannot run with a read-only root filesystem at all
# - see the comment in values.yaml. Moving the port means changing
# the chart, on purpose.
#
# The port NAME is load-bearing and must not be renamed: the
# Service selects it by name and so do all three probes.
- containerPort: 8080
protocol: TCP
name: http
# Probes, resources and both security contexts go through the
# null-safe helpers (#99): an erased block means "chart defaults
# apply" instead of a vanished probe or an unhardened container.
# Never wrap these in an "if" - a guard hides the erased case
# completely instead of rendering a visible null.
livenessProbe:
{{- include "bentopdf.livenessProbe" .Values.bentopdf.livenessProbe | nindent 12 }}
readinessProbe:
{{- include "bentopdf.readinessProbe" .Values.bentopdf.readinessProbe | nindent 12 }}
startupProbe:
{{- include "bentopdf.startupProbe" .Values.bentopdf.startupProbe | nindent 12 }}
resources:
{{- include "bentopdf.effectiveResources" .Values.bentopdf.resources | nindent 12 }}
volumes:
- name: config
configMap:
name: "{{ .Release.Name }}-{{ .Chart.Name }}-configmap"
- name: nginx-tmp
emptyDir: {}
- name: nginx-cache
emptyDir: {}
restartPolicy: Always
+28
View File
@@ -0,0 +1,28 @@
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ .Release.Name }}-{{ .Chart.Name }}-ingress
annotations:
cert-manager.io/cluster-issuer: {{ required "A Cluster-Issuer must be provided" .Values.ingress.clusterIssuer }}
{{- with .Values.ingress.annotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
ingressClassName: {{ .Values.ingress.className }}
rules:
- host: {{ required "A Domain/Host must be provided" .Values.ingress.domain }}
http:
paths:
- backend:
service:
name: {{ .Release.Name }}-{{ .Chart.Name }}-service
port:
name: http
path: /
pathType: Prefix
tls:
- hosts:
- {{ required "A Domain/Host must be provided" .Values.ingress.domain }}
secretName: tls-{{ .Release.Name }}-{{ .Chart.Name }}-ingress
{{- end }}
+13
View File
@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-{{ .Chart.Name }}-service
spec:
selector:
app: {{ .Release.Name }}-{{ .Chart.Name }}-deployment
ports:
- protocol: TCP
port: 80
targetPort: http
name: http
type: ClusterIP