diff --git a/README.md b/README.md index 2296d11..5c7a5f6 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ README is mirrored to `gh-pages`. | Chart | Description | Source | |-------|-------------|--------| | [ipsec-vpn-server](charts/ipsec-vpn-server) | Deploy IPsec VPN server inside K8s with optional sealed-secrets | [taskmedia/helm](https://github.com/taskmedia/helm/tree/main/charts/ipsec-vpn-server) | +| [outprint](charts/outprint) | PDF export for self-hosted Outline: Gateway, network-less Worker and injector | [taskmedia/helm](https://github.com/taskmedia/helm/tree/main/charts/outprint) | | [paperless-gpt](charts/paperless-gpt) | LLM-powered OCR and metadata assistant for paperless-ngx | [taskmedia/helm](https://github.com/taskmedia/helm/tree/main/charts/paperless-gpt) | | [paperlessngx-backup](charts/paperlessngx-backup) | Backup paperless-ngx via K8s cronjob to FTP | [taskmedia/helm](https://github.com/taskmedia/helm/tree/main/charts/paperlessngx-backup) | | [paperlessngx-ftp-bridge](charts/paperlessngx-ftp-bridge) | Embedded FTP/FTPS server that forwards scanner uploads to paperless-ngx | [taskmedia/helm](https://github.com/taskmedia/helm/tree/main/charts/paperlessngx-ftp-bridge) | diff --git a/charts/outprint/.helmignore b/charts/outprint/.helmignore new file mode 100644 index 0000000..5357942 --- /dev/null +++ b/charts/outprint/.helmignore @@ -0,0 +1,2 @@ +.git +*.swp diff --git a/charts/outprint/Chart.yaml b/charts/outprint/Chart.yaml new file mode 100644 index 0000000..760c722 --- /dev/null +++ b/charts/outprint/Chart.yaml @@ -0,0 +1,36 @@ +apiVersion: v2 +name: outprint +description: Outprint for Outline - Gateway, network-less Worker and injector +home: https://helm.task.media/outprint +keywords: + - outprint + - outline + - pdf + - latex +maintainers: + - name: fty4 + url: https://github.com/fty4 +sources: + - https://github.com/taskmedia/outprint + - https://github.com/taskmedia/helm +icon: https://media.task.media/images/logo.png +type: application +version: 1.0.0 +# outprint release tag without the leading v +appVersion: "1.0.0" + +annotations: + artifacthub.io/category: skip-prediction + artifacthub.io/links: | + - name: support + url: https://github.com/taskmedia/helm/issues + - name: source + url: https://github.com/taskmedia/helm/tree/main/charts/outprint + artifacthub.io/images: | + - name: outprint + image: ghcr.io/taskmedia/outprint:1.0.0 + - name: outprint-injector + image: ghcr.io/taskmedia/outprint-injector:1.0.0 + artifacthub.io/changes: | + - kind: added + description: Initial chart for the Gateway, the Worker and the injector diff --git a/charts/outprint/README.md b/charts/outprint/README.md new file mode 100644 index 0000000..1414d41 --- /dev/null +++ b/charts/outprint/README.md @@ -0,0 +1,25 @@ +# outprint + +Helm chart for [Outprint](https://github.com/taskmedia/outprint), PDF export for a self-hosted +[Outline](https://www.getoutline.com/). It runs the Gateway, the network-less Worker and, optionally, +the injector for Outline's Export menu. Images: `ghcr.io/taskmedia/outprint` and +`ghcr.io/taskmedia/outprint-injector`; the tag defaults to the chart's `appVersion`. + +Documentation (concepts, the Worker security baseline, scaling, routing): +[Helm and Kubernetes](https://github.com/taskmedia/outprint/blob/main/docs/deploy/helm-kubernetes.md). + +## Usage + +```bash +helm repo add taskmedia https://helm.task.media +helm install outprint taskmedia/outprint \ + --namespace outprint --create-namespace \ + --set outline.url=http://outline.outline.svc:3000 +``` + +Then route your edge proxy to the Service `outprint-injector` instead of Outline. Do not expose the +Gateway or the Worker. For PDF by link only, set `injector.enabled=false`. + +## Values + +See [values.yaml](values.yaml); every option is commented. `outline.url` is required. diff --git a/charts/outprint/ci/ct-values.yaml b/charts/outprint/ci/ct-values.yaml new file mode 100644 index 0000000..e7aa2bc --- /dev/null +++ b/charts/outprint/ci/ct-values.yaml @@ -0,0 +1,3 @@ +# Minimal overrides so `ct lint` and `ct install` can render the chart. +outline: + url: http://outline.example.invalid:3000 diff --git a/charts/outprint/templates/NOTES.txt b/charts/outprint/templates/NOTES.txt new file mode 100644 index 0000000..a58a881 --- /dev/null +++ b/charts/outprint/templates/NOTES.txt @@ -0,0 +1,17 @@ +Outprint {{ .Chart.AppVersion }} is installed. + +Gateway, Worker{{ if .Values.injector.enabled }} and injector{{ end }} run in namespace {{ .Release.Namespace }}. +{{- if .Values.injector.enabled }} + +Route your edge proxy to the Service {{ include "outprint.fullname" . }}-injector +(port {{ .Values.injector.service.port }}) instead of to Outline. The injector forwards everything +else to Outline and /pdf/* to the Gateway. Do not expose the Gateway or the Worker. +{{- else }} + +The injector is disabled. Route /pdf on the address of Outline to the Service +{{ include "outprint.fullname" . }}-gateway (port 8080), with the /pdf prefix removed. +{{- end }} +{{- if not .Values.worker.networkPolicy.enabled }} + +WARNING: worker.networkPolicy.enabled is false. The Worker is not cut off from the network. +{{- end }} diff --git a/charts/outprint/templates/_helpers.tpl b/charts/outprint/templates/_helpers.tpl new file mode 100644 index 0000000..453ae0f --- /dev/null +++ b/charts/outprint/templates/_helpers.tpl @@ -0,0 +1,59 @@ +{{- define "outprint.fullname" -}} +{{- if contains .Chart.Name .Release.Name -}}{{ .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else -}}{{ printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" }}{{- end -}} +{{- end -}} + +{{- define "outprint.labels" -}} +helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +app.kubernetes.io/name: outprint +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* call with (dict "root" . "component" "worker") */}} +{{- define "outprint.selector" -}} +app.kubernetes.io/name: outprint +app.kubernetes.io/instance: {{ .root.Release.Name }} +app.kubernetes.io/component: {{ .component }} +{{- end -}} + +{{- define "outprint.image" -}} +{{ .repository }}:{{ .tag | default .appVersion }} +{{- end -}} + +{{- define "outprint.tokenSecretName" -}} +{{- default (printf "%s-worker-token" (include "outprint.fullname" .)) .Values.workerToken.existingSecret -}} +{{- end -}} + +{{- define "outprint.tokenEnv" -}} +{{- if .Values.workerToken.enabled }} +- name: OUTPRINT_WORKER_TOKEN + valueFrom: + secretKeyRef: + name: {{ include "outprint.tokenSecretName" . }} + key: token +{{- end }} +{{- end -}} + +{{- define "outprint.extraEnv" -}} +{{- range $k, $v := . }} +- name: {{ $k }} + value: {{ $v | quote }} +{{- end }} +{{- end -}} + +{{- define "outprint.containerSecurity" -}} +allowPrivilegeEscalation: false +readOnlyRootFilesystem: true +capabilities: + drop: [ALL] +{{- end -}} + +{{- define "outprint.podSecurity" -}} +runAsNonRoot: true +runAsUser: {{ .uid }} +runAsGroup: {{ .uid }} +seccompProfile: + type: RuntimeDefault +{{- end -}} diff --git a/charts/outprint/templates/configmap.yaml b/charts/outprint/templates/configmap.yaml new file mode 100644 index 0000000..ea49fb7 --- /dev/null +++ b/charts/outprint/templates/configmap.yaml @@ -0,0 +1,11 @@ +{{- $cfg := deepCopy .Values.serviceConfig -}} +{{- $_ := set $cfg "admission" (merge (dict "slots" (int .Values.worker.replicas)) (default (dict) $cfg.admission)) -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "outprint.fullname" . }}-service + labels: + {{- include "outprint.labels" . | nindent 4 }} +data: + service.yaml: | + {{- toYaml $cfg | nindent 4 }} diff --git a/charts/outprint/templates/gateway.yaml b/charts/outprint/templates/gateway.yaml new file mode 100644 index 0000000..0b24694 --- /dev/null +++ b/charts/outprint/templates/gateway.yaml @@ -0,0 +1,105 @@ +{{- $name := printf "%s-gateway" (include "outprint.fullname" .) -}} +{{- $sel := include "outprint.selector" (dict "root" . "component" "gateway") -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $name }} + labels: + {{- include "outprint.labels" . | nindent 4 }} + app.kubernetes.io/component: gateway +spec: + replicas: {{ .Values.gateway.replicas }} + selector: + matchLabels: + {{- $sel | nindent 6 }} + template: + metadata: + labels: + {{- include "outprint.labels" . | nindent 8 }} + app.kubernetes.io/component: gateway + annotations: + checksum/service-config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.gateway.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + automountServiceAccountToken: false + enableServiceLinks: false + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- include "outprint.podSecurity" (dict "uid" 10001) | nindent 8 }} + containers: + - name: gateway + image: {{ include "outprint.image" (dict "repository" .Values.image.repository "tag" .Values.image.tag "appVersion" .Chart.AppVersion) | quote }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: ["gateway"] + securityContext: + {{- include "outprint.containerSecurity" . | nindent 12 }} + env: + - name: OUTPRINT_LISTEN + value: ":8080" + - name: OUTPRINT_WORKER_URL + value: {{ printf "http://%s-worker:8081" (include "outprint.fullname" .) | quote }} + - name: OUTPRINT_SERVICE_CONFIG + value: /etc/outprint/service.yaml + - name: OUTLINE_URL + value: {{ required "outline.url is required: the base URL of your Outline" .Values.outline.url | quote }} + {{- with .Values.outline.publicUrl }} + - name: OUTLINE_PUBLIC_URL + value: {{ . | quote }} + {{- end }} + {{- include "outprint.tokenEnv" . | nindent 12 }} + {{- include "outprint.extraEnv" .Values.gateway.env | nindent 12 }} + ports: + - name: http + containerPort: 8080 + startupProbe: + httpGet: { path: /healthz, port: http } + periodSeconds: 2 + failureThreshold: 30 + readinessProbe: + httpGet: { path: /healthz, port: http } + periodSeconds: 10 + livenessProbe: + httpGet: { path: /healthz, port: http } + periodSeconds: 10 + failureThreshold: 3 + resources: + {{- toYaml .Values.gateway.resources | nindent 12 }} + volumeMounts: + - { name: service-config, mountPath: /etc/outprint, readOnly: true } + volumes: + - name: service-config + configMap: + name: {{ include "outprint.fullname" . }}-service + {{- with .Values.gateway.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.gateway.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.gateway.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ $name }} + labels: + {{- include "outprint.labels" . | nindent 4 }} + app.kubernetes.io/component: gateway +spec: + type: ClusterIP + selector: + {{- $sel | nindent 4 }} + ports: + - name: http + port: 8080 + targetPort: http diff --git a/charts/outprint/templates/injector.yaml b/charts/outprint/templates/injector.yaml new file mode 100644 index 0000000..7d2473b --- /dev/null +++ b/charts/outprint/templates/injector.yaml @@ -0,0 +1,131 @@ +{{- if .Values.injector.enabled -}} +{{- $name := printf "%s-injector" (include "outprint.fullname" .) -}} +{{- $sel := include "outprint.selector" (dict "root" . "component" "injector") -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $name }} + labels: + {{- include "outprint.labels" . | nindent 4 }} + app.kubernetes.io/component: injector +spec: + replicas: {{ .Values.injector.replicas }} + selector: + matchLabels: + {{- $sel | nindent 6 }} + template: + metadata: + labels: + {{- include "outprint.labels" . | nindent 8 }} + app.kubernetes.io/component: injector + {{- with .Values.injector.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + automountServiceAccountToken: false + enableServiceLinks: false + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- include "outprint.podSecurity" (dict "uid" 65532) | nindent 8 }} + containers: + - name: injector + image: {{ include "outprint.image" (dict "repository" .Values.injector.image.repository "tag" .Values.injector.image.tag "appVersion" .Chart.AppVersion) | quote }} + imagePullPolicy: {{ .Values.injector.image.pullPolicy }} + securityContext: + {{- include "outprint.containerSecurity" . | nindent 12 }} + env: + - name: OUTPRINT_INJECTOR_LISTEN + value: ":8090" + - name: OUTPRINT_INJECTOR_UPSTREAM + value: {{ required "outline.url (or injector.upstream) is required: where the injector reaches Outline" (default .Values.outline.url .Values.injector.upstream) | quote }} + - name: OUTPRINT_INJECTOR_GATEWAY_URL + value: {{ printf "http://%s-gateway:8080" (include "outprint.fullname" .) | quote }} + - name: OUTPRINT_INJECTOR_GATEWAY_PREFIX + value: /pdf + - name: OUTPRINT_INJECTOR_CSP_ALLOW_SELF + value: {{ .Values.injector.cspAllowSelf | quote }} + {{- include "outprint.extraEnv" .Values.injector.env | nindent 12 }} + ports: + - name: http + containerPort: 8090 + startupProbe: + httpGet: { path: /_injector/healthz, port: http } + periodSeconds: 2 + failureThreshold: 30 + readinessProbe: + httpGet: { path: /_injector/healthz, port: http } + periodSeconds: 10 + livenessProbe: + httpGet: { path: /_injector/healthz, port: http } + periodSeconds: 10 + failureThreshold: 3 + resources: + {{- toYaml .Values.injector.resources | nindent 12 }} + {{- with .Values.injector.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.injector.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.injector.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ $name }} + labels: + {{- include "outprint.labels" . | nindent 4 }} + app.kubernetes.io/component: injector +spec: + type: {{ .Values.injector.service.type }} + selector: + {{- $sel | nindent 4 }} + ports: + - name: http + port: {{ .Values.injector.service.port }} + targetPort: http +{{- if .Values.injector.ingress.enabled }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ $name }} + labels: + {{- include "outprint.labels" . | nindent 4 }} + app.kubernetes.io/component: injector + {{- with .Values.injector.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with .Values.injector.ingress.className }} + ingressClassName: {{ . }} + {{- end }} + {{- with .Values.injector.ingress.tls }} + tls: + {{- toYaml . | nindent 4 }} + {{- end }} + rules: + {{- range .Values.injector.ingress.hosts }} + - host: {{ . | quote }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ $name }} + port: + name: http + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/outprint/templates/secret.yaml b/charts/outprint/templates/secret.yaml new file mode 100644 index 0000000..debb39a --- /dev/null +++ b/charts/outprint/templates/secret.yaml @@ -0,0 +1,13 @@ +{{- if and .Values.workerToken.enabled (not .Values.workerToken.existingSecret) }} +{{- $name := printf "%s-worker-token" (include "outprint.fullname" .) }} +{{- $existing := lookup "v1" "Secret" .Release.Namespace $name }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ $name }} + labels: + {{- include "outprint.labels" . | nindent 4 }} +type: Opaque +data: + token: {{ if $existing }}{{ index $existing.data "token" }}{{ else }}{{ randAlphaNum 48 | b64enc }}{{ end }} +{{- end }} diff --git a/charts/outprint/templates/worker.yaml b/charts/outprint/templates/worker.yaml new file mode 100644 index 0000000..aa67c64 --- /dev/null +++ b/charts/outprint/templates/worker.yaml @@ -0,0 +1,132 @@ +{{- $name := printf "%s-worker" (include "outprint.fullname" .) -}} +{{- $sel := include "outprint.selector" (dict "root" . "component" "worker") -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $name }} + labels: + {{- include "outprint.labels" . | nindent 4 }} + app.kubernetes.io/component: worker +spec: + replicas: {{ .Values.worker.replicas }} + selector: + matchLabels: + {{- $sel | nindent 6 }} + template: + metadata: + labels: + {{- include "outprint.labels" . | nindent 8 }} + app.kubernetes.io/component: worker + annotations: + checksum/service-config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.worker.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + # The Worker needs no Kubernetes API, no token and no service links. + automountServiceAccountToken: false + enableServiceLinks: false + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- include "outprint.podSecurity" (dict "uid" 10001) | nindent 8 }} + fsGroup: 10001 + containers: + - name: worker + image: {{ include "outprint.image" (dict "repository" .Values.image.repository "tag" .Values.image.tag "appVersion" .Chart.AppVersion) | quote }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: ["worker"] + securityContext: + {{- include "outprint.containerSecurity" . | nindent 12 }} + env: + - name: OUTPRINT_LISTEN + value: ":8081" + - name: OUTPRINT_WORK_DIR + value: /work + - name: OUTPRINT_SERVICE_CONFIG + value: /etc/outprint/service.yaml + {{- include "outprint.tokenEnv" . | nindent 12 }} + {{- include "outprint.extraEnv" .Values.worker.env | nindent 12 }} + ports: + - name: http + containerPort: 8081 + startupProbe: + httpGet: { path: /healthz, port: http } + periodSeconds: 2 + failureThreshold: 30 + readinessProbe: + httpGet: { path: /healthz, port: http } + periodSeconds: 10 + livenessProbe: + httpGet: { path: /healthz, port: http } + periodSeconds: 10 + failureThreshold: 3 + resources: + {{- toYaml .Values.worker.resources | nindent 12 }} + volumeMounts: + - { name: work, mountPath: /work } + - { name: tmp, mountPath: /tmp } + - { name: service-config, mountPath: /etc/outprint, readOnly: true } + volumes: + - name: work + emptyDir: { medium: Memory, sizeLimit: {{ .Values.worker.workDirSize }} } + - name: tmp + emptyDir: { medium: Memory, sizeLimit: {{ .Values.worker.tmpSize }} } + - name: service-config + configMap: + name: {{ include "outprint.fullname" . }}-service + {{- with .Values.worker.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.worker.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.worker.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ $name }} + labels: + {{- include "outprint.labels" . | nindent 4 }} + app.kubernetes.io/component: worker +spec: + type: ClusterIP + selector: + {{- $sel | nindent 4 }} + ports: + - name: http + port: 8081 + targetPort: http +{{- if .Values.worker.networkPolicy.enabled }} +--- +# Egress is empty on purpose: the Worker has no route to the internet, to +# Outline, to DNS or to the cluster. Ingress only from the Gateway. +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ $name }} + labels: + {{- include "outprint.labels" . | nindent 4 }} + app.kubernetes.io/component: worker +spec: + podSelector: + matchLabels: + {{- $sel | nindent 6 }} + policyTypes: [Ingress, Egress] + ingress: + - from: + - podSelector: + matchLabels: + {{- include "outprint.selector" (dict "root" . "component" "gateway") | nindent 14 }} + ports: + - { protocol: TCP, port: 8081 } + egress: [] +{{- end }} diff --git a/charts/outprint/values.yaml b/charts/outprint/values.yaml new file mode 100644 index 0000000..2ae8807 --- /dev/null +++ b/charts/outprint/values.yaml @@ -0,0 +1,114 @@ +# Outprint chart (https://github.com/taskmedia/outprint, docs: Deploy > Helm and Kubernetes). Gateway, Worker and injector +# from the two release images. The Worker keeps the baseline of ADR 0001 +# (https://github.com/taskmedia/outprint/blob/main/docs/adr/0001-split-renderer-into-gateway-and-worker.md): +# non-root, read-only root file system, no network, no secrets but an +# optional shared token, resource limits. + +# Your self-hosted Outline. Required. +outline: + # Base URL of Outline as the Gateway reaches it (an in-cluster address is fine). + url: "" + # Outline's own URL setting, when `url` is an internal address. + # See "Image fetching" in the outprint docs. Empty = not set. + publicUrl: "" + +image: + repository: ghcr.io/taskmedia/outprint + # Empty = the chart's appVersion. + tag: "" + pullPolicy: IfNotPresent + +imagePullSecrets: [] + +# Service configuration (config/service.yaml in the image): the allow-list of +# Bindings and the default Binding. The Template and Configuration roots point +# at the packages baked into the image. To ship your own packages, build an +# image on top of the release image and set image.repository / image.tag. +serviceConfig: + templatesRoot: /opt/outprint/templates + configurationsRoot: /opt/outprint/configurations + bindings: + - template: neutral + configuration: example + defaultBinding: + template: neutral + configuration: example + # imageHosts: [] + # Admission control. The number of slots follows worker.replicas. + admission: + queueDepth: 4 + perUser: 1 + maxWait: 60s + +# Bearer token shared by Gateway and Worker; the one secret the Worker may +# hold. Use existingSecret (key: token) to bring your own; otherwise the chart +# creates a Secret with a random token and keeps it across upgrades. +# Set enabled: false for no token. +workerToken: + enabled: true + existingSecret: "" + +worker: + # One job per replica. Throughput scales with replicas. + replicas: 1 + resources: + requests: {cpu: 500m, memory: 512Mi} + limits: {cpu: "1", memory: 1Gi} + # Job directories (OUTPRINT_WORK_DIR) and scratch space; in memory, gone + # with the pod. Memory-backed volumes count against the memory limit. + workDirSize: 256Mi + tmpSize: 64Mi + # Extra environment, for example OUTPRINT_TIMEOUT, OUTPRINT_MAX_PAGES. + env: {} + nodeSelector: {} + tolerations: [] + affinity: {} + podAnnotations: {} + # Default-deny egress, ingress only from the Gateway. Needs a CNI that + # enforces NetworkPolicy. Turning this off weakens the Worker baseline. + networkPolicy: + enabled: true + +gateway: + replicas: 1 + resources: + requests: {cpu: 100m, memory: 128Mi} + limits: {cpu: "1", memory: 256Mi} + # Extra environment, for example the OUTPRINT_BUTTON_* placement options. + env: {} + nodeSelector: {} + tolerations: [] + affinity: {} + podAnnotations: {} + +# The injector sits between your edge proxy and Outline (Export menu way). +# Disable it for the PDF by link way. +injector: + enabled: true + image: + repository: ghcr.io/taskmedia/outprint-injector + tag: "" + pullPolicy: IfNotPresent + # Where the injector reaches Outline. Empty = outline.url. + upstream: "" + cspAllowSelf: false + replicas: 1 + resources: + requests: {cpu: 50m, memory: 64Mi} + limits: {cpu: 500m, memory: 128Mi} + env: {} + nodeSelector: {} + tolerations: [] + affinity: {} + podAnnotations: {} + service: + type: ClusterIP + port: 80 + # Optional. Many clusters route in their own way; then point your edge + # at the injector Service instead. + ingress: + enabled: false + className: "" + annotations: {} + hosts: [] # for example [wiki.example.test] + tls: []