diff --git a/charts/outprint/Chart.yaml b/charts/outprint/Chart.yaml index eb67fe7..d8902ac 100644 --- a/charts/outprint/Chart.yaml +++ b/charts/outprint/Chart.yaml @@ -15,7 +15,7 @@ sources: - https://github.com/taskmedia/helm icon: https://media.task.media/images/logo.png type: application -version: 1.1.1 +version: 1.2.0 # outprint release tag without the leading v appVersion: "1.0.1" @@ -32,5 +32,7 @@ annotations: - name: outprint-injector image: ghcr.io/taskmedia/outprint-injector:1.0.1 artifacthub.io/changes: | - - kind: changed - description: Bump Outprint to 1.0.1 + - kind: added + description: packages.git, packages.image and packages.existingClaim mount your own Template and Configuration packages + - kind: added + description: extraVolumes and extraVolumeMounts for Gateway and Worker diff --git a/charts/outprint/README.md b/charts/outprint/README.md index a812345..fbc080d 100644 --- a/charts/outprint/README.md +++ b/charts/outprint/README.md @@ -47,3 +47,37 @@ ingressRoute: ``` Needs `injector.enabled` and the Traefik (and, for the certificate, cert-manager) CRDs in the cluster. + +## Your own Templates and Configurations + +The chart ships `neutral` and `example` in the image. To use your own packages, set one source under +`packages` (documentation: Install > Run Outprint > Your own Templates and Configurations): + +```yaml +packages: + git: + url: git@github.com:example/letters.git + ref: v1.0.0 # tag, branch or commit + path: outprint # folder with templates/ and configurations/ + sshKeySecret: letters-deploy-key # key `ssh-privatekey`, optional `known_hosts` +serviceConfig: + bindings: + - template: letter + configuration: acme + defaultBinding: + template: letter + configuration: acme +``` + +With `git`, a Job (at install and on a change of `url`, `ref`, `commit` or `path`) and a CronJob (every +`packages.git.interval`) resolve `ref` to a commit. On a change they clone it (Git LFS included), run +`outprint validate` against the service configuration and switch over only if it passes; then they restart +Gateway and Worker. A broken revision never replaces a working one. `packages.git.commit` refuses any other +commit. Only the Job has network access; the Worker keeps its NetworkPolicy. The revisions live on a +`ReadWriteOnce` PVC, so on a multi-node cluster pin Gateway, Worker and the Job to one node or use a +ReadWriteMany storage class. When a change adds a Binding that the running revision does not have yet, the +Gateway and the Worker restart until the Job has switched over. + +`packages.image` mounts an OCI image as a Kubernetes image volume (Kubernetes 1.35+ or the `ImageVolume` +feature gate); `packages.existingClaim` mounts a PVC you maintain. `gateway.extraVolumes` / +`gateway.extraVolumeMounts` (and the same under `worker`) cover everything else. diff --git a/charts/outprint/files/packages-activate.sh b/charts/outprint/files/packages-activate.sh new file mode 100644 index 0000000..38b0b2f --- /dev/null +++ b/charts/outprint/files/packages-activate.sh @@ -0,0 +1,25 @@ +# Switch /packages/current to the validated revision, then restart Gateway and +# Worker so they load it. +set -eu + +PK=/packages +[ -f "$PK/.pending" ] || { echo "no change"; exit 0; } +sha="$(cat "$PK/.pending")" +had_revision=false +[ -f "$PK/.revision" ] && had_revision=true + +ln -sfn "rev-$sha" "$PK/.current.tmp" +mv -T "$PK/.current.tmp" "$PK/current" +printf '%s\n' "$sha" >"$PK/.revision" +rm -f "$PK/.pending" +echo "activated $sha" + +# newest first; the active revision is the newest +ls -dt "$PK"/rev-* | tail -n +"$((KEEP_REVISIONS + 2))" | xargs -r rm -rf + +# On the first sync Gateway and Worker are still waiting for the packages. +if [ "$had_revision" = true ]; then + for d in $DEPLOYMENTS; do + kubectl --namespace "$NAMESPACE" rollout restart "deployment/$d" + done +fi diff --git a/charts/outprint/files/packages-sync.sh b/charts/outprint/files/packages-sync.sh new file mode 100644 index 0000000..79969f5 --- /dev/null +++ b/charts/outprint/files/packages-sync.sh @@ -0,0 +1,71 @@ +# Resolve GIT_REF to a commit and, if it differs from the active one, check it +# out (Git LFS included) as /packages/rev-. Leaves /packages/.pending +# for the validate and activate steps. Never touches the active revision. +set -eu + +PK=/packages +rm -f "$PK/.pending" + +apk add --no-cache git-lfs openssh-client >/dev/null + +if [ -f /ssh/ssh-privatekey ]; then + install -m 600 /ssh/ssh-privatekey /tmp/id + check=accept-new + if [ -f /ssh/known_hosts ]; then + cp /ssh/known_hosts /tmp/known_hosts + check=yes + fi + export GIT_SSH_COMMAND="ssh -i /tmp/id -o IdentitiesOnly=yes -o StrictHostKeyChecking=$check -o UserKnownHostsFile=/tmp/known_hosts" +fi + +if printf '%s' "$GIT_REF" | grep -Eq '^[0-9a-f]{40}$'; then + sha="$GIT_REF" +else + sha="" + for candidate in "refs/tags/$GIT_REF^{}" "refs/tags/$GIT_REF" "refs/heads/$GIT_REF"; do + sha="$(git ls-remote "$GIT_URL" "$candidate" | awk 'NR==1 {print $1}')" + [ -n "$sha" ] && break + done +fi +if [ -z "$sha" ]; then + echo "cannot resolve ref '$GIT_REF' in $GIT_URL" >&2 + exit 1 +fi +echo "ref '$GIT_REF' resolves to $sha" + +if [ -n "$GIT_COMMIT" ]; then + case "$sha" in + "$GIT_COMMIT"*) ;; + *) echo "ref resolves to $sha, packages.git.commit expects $GIT_COMMIT: keeping the active revision" >&2; exit 1 ;; + esac +fi + +if [ "$sha" = "$(cat "$PK/.revision" 2>/dev/null || true)" ] && [ -d "$PK/current/templates" ]; then + echo "revision $sha is already active" + exit 0 +fi + +rm -rf "$PK/.work" "$PK/rev-$sha" +mkdir "$PK/.work" +cd "$PK/.work" +git init -q . +git remote add origin "$GIT_URL" +git lfs install --local >/dev/null +git fetch -q --depth 1 origin "$sha" +git checkout -q FETCH_HEAD +git lfs pull + +src="$PK/.work${PKG_PATH:+/$PKG_PATH}" +for dir in templates configurations; do + if [ ! -d "$src/$dir" ]; then + echo "$src/$dir not found: set packages.git.path to the folder with templates/ and configurations/" >&2 + exit 1 + fi +done +mkdir "$PK/rev-$sha" +cp -R "$src/templates" "$src/configurations" "$PK/rev-$sha/" +cd "$PK" +rm -rf "$PK/.work" +chmod -R a+rX "$PK/rev-$sha" +printf '%s\n' "$sha" >"$PK/.pending" +chmod a+r "$PK/.pending" diff --git a/charts/outprint/files/packages-validate.sh b/charts/outprint/files/packages-validate.sh new file mode 100644 index 0000000..a946fa1 --- /dev/null +++ b/charts/outprint/files/packages-validate.sh @@ -0,0 +1,9 @@ +# Check the pending revision with the same code the Gateway runs at start-up. +# With a service configuration the roots come from the environment. +set -eu + +[ -f /packages/.pending ] || { echo "nothing to validate"; exit 0; } +sha="$(cat /packages/.pending)" +export OUTPRINT_TEMPLATES_ROOT="/packages/rev-$sha/templates" +export OUTPRINT_CONFIGURATIONS_ROOT="/packages/rev-$sha/configurations" +exec outprint validate --service-config /etc/outprint/service.yaml diff --git a/charts/outprint/templates/_helpers.tpl b/charts/outprint/templates/_helpers.tpl index 453ae0f..50769e5 100644 --- a/charts/outprint/templates/_helpers.tpl +++ b/charts/outprint/templates/_helpers.tpl @@ -57,3 +57,88 @@ runAsGroup: {{ .uid }} seccompProfile: type: RuntimeDefault {{- end -}} + +{{/* The packages source in use: git, image, existingClaim or empty. At most one may be set. */}} +{{- define "outprint.packagesSource" -}} +{{- $sources := list -}} +{{- if .Values.packages.git.url }}{{ $sources = append $sources "git" }}{{ end -}} +{{- if .Values.packages.image.reference }}{{ $sources = append $sources "image" }}{{ end -}} +{{- if .Values.packages.existingClaim }}{{ $sources = append $sources "existingClaim" }}{{ end -}} +{{- if gt (len $sources) 1 -}} +{{- fail (printf "packages: set only one source, got %s" (join ", " $sources)) -}} +{{- end -}} +{{- first (append $sources "") -}} +{{- end -}} + +{{/* Folder that holds templates/ and configurations/ inside the packages mount. */}} +{{- define "outprint.packagesRoot" -}} +{{- if eq (include "outprint.packagesSource" .) "git" -}} +/packages/current +{{- else -}} +{{- printf "/packages/%s" (trimAll "/" .Values.packages.path) | trimSuffix "/" -}} +{{- end -}} +{{- end -}} + +{{- define "outprint.packagesClaimName" -}} +{{- default (printf "%s-packages" (include "outprint.fullname" .)) .Values.packages.existingClaim -}} +{{- end -}} + +{{/* Env for Gateway and Worker; the env vars win over the service config file. */}} +{{- define "outprint.packagesEnv" -}} +{{- if include "outprint.packagesSource" . }} +- name: OUTPRINT_TEMPLATES_ROOT + value: {{ printf "%s/templates" (include "outprint.packagesRoot" .) | quote }} +- name: OUTPRINT_CONFIGURATIONS_ROOT + value: {{ printf "%s/configurations" (include "outprint.packagesRoot" .) | quote }} +{{- end }} +{{- end -}} + +{{- define "outprint.packagesVolumeMount" -}} +{{- if include "outprint.packagesSource" . }} +- { name: packages, mountPath: /packages, readOnly: true } +{{- end }} +{{- end -}} + +{{- define "outprint.packagesVolume" -}} +{{- $source := include "outprint.packagesSource" . -}} +{{- if eq $source "image" }} +- name: packages + image: + reference: {{ .Values.packages.image.reference | quote }} + pullPolicy: {{ .Values.packages.image.pullPolicy }} +{{- else if $source }} +- name: packages + persistentVolumeClaim: + claimName: {{ include "outprint.packagesClaimName" . }} + readOnly: true +{{- end }} +{{- end -}} + +{{/* Gateway and Worker wait here until the first sync has produced packages. */}} +{{- define "outprint.packagesWait" -}} +{{- if eq (include "outprint.packagesSource" .) "git" }} +initContainers: + - name: wait-for-packages + image: {{ include "outprint.image" (dict "repository" .Values.image.repository "tag" .Values.image.tag "appVersion" .Chart.AppVersion) | quote }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ["sh", "-c", "until [ -d /packages/current/templates ] && [ -d /packages/current/configurations ]; do echo waiting for packages; sleep 2; done"] + securityContext: + {{- include "outprint.containerSecurity" . | nindent 6 }} + resources: + requests: {cpu: 10m, memory: 16Mi} + limits: {cpu: 100m, memory: 32Mi} + volumeMounts: + - { name: packages, mountPath: /packages, readOnly: true } +{{- end }} +{{- end -}} + +{{/* Minutes (5m) and hours (2h) become a cron expression; anything else is taken as one. */}} +{{- define "outprint.packagesSchedule" -}} +{{- if regexMatch "^[0-9]+m$" . -}} +*/{{ trimSuffix "m" . }} * * * * +{{- else if regexMatch "^[0-9]+h$" . -}} +0 */{{ trimSuffix "h" . }} * * * +{{- else -}} +{{ . }} +{{- end -}} +{{- end -}} diff --git a/charts/outprint/templates/_packages-sync.tpl b/charts/outprint/templates/_packages-sync.tpl new file mode 100644 index 0000000..6899b50 --- /dev/null +++ b/charts/outprint/templates/_packages-sync.tpl @@ -0,0 +1,96 @@ +{{- define "outprint.packagesSyncPod" }} +{{- $git := .Values.packages.git }} +{{- $name := printf "%s-packages" (include "outprint.fullname" .) }} +serviceAccountName: {{ $name }} +restartPolicy: Never +{{- with .Values.imagePullSecrets }} +imagePullSecrets: + {{- toYaml . | nindent 2 }} +{{- end }} +securityContext: + seccompProfile: + type: RuntimeDefault +initContainers: + - name: sync + image: {{ printf "%s:%s" $git.image.repository $git.image.tag | quote }} + imagePullPolicy: {{ $git.image.pullPolicy }} + command: ["sh", "/scripts/sync.sh"] + env: + - { name: GIT_URL, value: {{ $git.url | quote }} } + - { name: GIT_REF, value: {{ $git.ref | quote }} } + - { name: GIT_COMMIT, value: {{ $git.commit | quote }} } + - { name: PKG_PATH, value: {{ trimAll "/" $git.path | quote }} } + securityContext: + runAsUser: 0 + allowPrivilegeEscalation: false + capabilities: + drop: [ALL] + add: [CHOWN, DAC_OVERRIDE, FOWNER, SETUID, SETGID] + resources: + {{- toYaml $git.resources | nindent 6 }} + volumeMounts: + - { name: packages, mountPath: /packages } + - { name: scripts, mountPath: /scripts, readOnly: true } + {{- if $git.sshKeySecret }} + - { name: ssh, mountPath: /ssh, readOnly: true } + {{- end }} + - name: validate + image: {{ include "outprint.image" (dict "repository" .Values.image.repository "tag" .Values.image.tag "appVersion" .Chart.AppVersion) | quote }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ["sh", "/scripts/validate.sh"] + securityContext: + {{- include "outprint.containerSecurity" . | nindent 6 }} + runAsNonRoot: true + runAsUser: 10001 + runAsGroup: 10001 + resources: + requests: {cpu: 50m, memory: 64Mi} + limits: {cpu: 500m, memory: 256Mi} + volumeMounts: + - { name: packages, mountPath: /packages, readOnly: true } + - { name: scripts, mountPath: /scripts, readOnly: true } + - { name: service-config, mountPath: /etc/outprint, readOnly: true } + - { name: tmp, mountPath: /tmp } +containers: + - name: activate + image: {{ printf "%s:%s" $git.image.repository $git.image.tag | quote }} + imagePullPolicy: {{ $git.image.pullPolicy }} + command: ["sh", "/scripts/activate.sh"] + env: + - name: NAMESPACE + valueFrom: { fieldRef: { fieldPath: metadata.namespace } } + - { name: DEPLOYMENTS, value: {{ printf "%s-gateway %s-worker" (include "outprint.fullname" .) (include "outprint.fullname" .) | quote }} } + - { name: KEEP_REVISIONS, value: {{ $git.keepRevisions | quote }} } + securityContext: + runAsUser: 0 + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: [ALL] + add: [CHOWN, DAC_OVERRIDE, FOWNER] + resources: + requests: {cpu: 10m, memory: 32Mi} + limits: {cpu: 200m, memory: 128Mi} + volumeMounts: + - { name: packages, mountPath: /packages } + - { name: scripts, mountPath: /scripts, readOnly: true } + - { name: tmp, mountPath: /tmp } +volumes: + - name: packages + persistentVolumeClaim: + claimName: {{ $name }} + - name: scripts + configMap: + name: {{ $name }}-sync + - name: service-config + configMap: + name: {{ include "outprint.fullname" . }}-service + - name: tmp + emptyDir: { sizeLimit: 64Mi } + {{- if $git.sshKeySecret }} + - name: ssh + secret: + secretName: {{ $git.sshKeySecret }} + defaultMode: 0400 + {{- end }} +{{- end }} diff --git a/charts/outprint/templates/gateway.yaml b/charts/outprint/templates/gateway.yaml index 0b24694..3c4ac29 100644 --- a/charts/outprint/templates/gateway.yaml +++ b/charts/outprint/templates/gateway.yaml @@ -31,6 +31,7 @@ spec: {{- end }} securityContext: {{- include "outprint.podSecurity" (dict "uid" 10001) | nindent 8 }} + {{- include "outprint.packagesWait" . | nindent 6 }} containers: - name: gateway image: {{ include "outprint.image" (dict "repository" .Values.image.repository "tag" .Values.image.tag "appVersion" .Chart.AppVersion) | quote }} @@ -52,6 +53,7 @@ spec: value: {{ . | quote }} {{- end }} {{- include "outprint.tokenEnv" . | nindent 12 }} + {{- include "outprint.packagesEnv" . | nindent 12 }} {{- include "outprint.extraEnv" .Values.gateway.env | nindent 12 }} ports: - name: http @@ -71,10 +73,18 @@ spec: {{- toYaml .Values.gateway.resources | nindent 12 }} volumeMounts: - { name: service-config, mountPath: /etc/outprint, readOnly: true } + {{- include "outprint.packagesVolumeMount" . | nindent 12 }} + {{- with .Values.gateway.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} volumes: - name: service-config configMap: name: {{ include "outprint.fullname" . }}-service + {{- include "outprint.packagesVolume" . | nindent 8 }} + {{- with .Values.gateway.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} {{- with .Values.gateway.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/charts/outprint/templates/packages-git.yaml b/charts/outprint/templates/packages-git.yaml new file mode 100644 index 0000000..9a3470d --- /dev/null +++ b/charts/outprint/templates/packages-git.yaml @@ -0,0 +1,124 @@ +{{- if eq (include "outprint.packagesSource" .) "git" }} +{{- $git := .Values.packages.git -}} +{{- $name := printf "%s-packages" (include "outprint.fullname" .) -}} +{{- $syncImage := printf "%s:%s" $git.image.repository $git.image.tag -}} +{{- $outprintImage := include "outprint.image" (dict "repository" .Values.image.repository "tag" .Values.image.tag "appVersion" .Chart.AppVersion) -}} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ $name }} + labels: + {{- include "outprint.labels" . | nindent 4 }} + app.kubernetes.io/component: packages + annotations: + helm.sh/resource-policy: keep +spec: + accessModes: [{{ $git.persistence.accessMode }}] + {{- with $git.persistence.storageClass }} + storageClassName: {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ $git.persistence.size }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ $name }} + labels: + {{- include "outprint.labels" . | nindent 4 }} + app.kubernetes.io/component: packages +--- +# The sync Job may restart exactly the Gateway and the Worker, nothing else. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ $name }} + labels: + {{- include "outprint.labels" . | nindent 4 }} + app.kubernetes.io/component: packages +rules: + - apiGroups: [apps] + resources: [deployments] + resourceNames: + - {{ printf "%s-gateway" (include "outprint.fullname" .) }} + - {{ printf "%s-worker" (include "outprint.fullname" .) }} + verbs: [get, patch] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ $name }} + labels: + {{- include "outprint.labels" . | nindent 4 }} + app.kubernetes.io/component: packages +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ $name }} +subjects: + - kind: ServiceAccount + name: {{ $name }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ $name }}-sync + labels: + {{- include "outprint.labels" . | nindent 4 }} + app.kubernetes.io/component: packages +data: + sync.sh: | + {{- .Files.Get "files/packages-sync.sh" | nindent 4 }} + validate.sh: | + {{- .Files.Get "files/packages-validate.sh" | nindent 4 }} + activate.sh: | + {{- .Files.Get "files/packages-activate.sh" | nindent 4 }} +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{ $name }}-sync + labels: + {{- include "outprint.labels" . | nindent 4 }} + app.kubernetes.io/component: packages +spec: + schedule: {{ include "outprint.packagesSchedule" $git.interval | quote }} + concurrencyPolicy: Forbid + successfulJobsHistoryLimit: 1 + failedJobsHistoryLimit: 3 + jobTemplate: + spec: + backoffLimit: 0 + activeDeadlineSeconds: 600 + template: + metadata: + labels: + {{- include "outprint.labels" . | nindent 12 }} + app.kubernetes.io/component: packages + spec: + {{- include "outprint.packagesSyncPod" . | nindent 10 }} +--- +# First sync (and a sync after a change of url, ref, commit or path) without +# waiting for the next CronJob tick. The name carries a hash of those values, +# so a change creates a fresh Job. +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ printf "%s-sync-%s" $name (printf "%s|%s|%s|%s" $git.url $git.ref $git.commit $git.path | sha256sum | trunc 8) }} + labels: + {{- include "outprint.labels" . | nindent 4 }} + app.kubernetes.io/component: packages +spec: + backoffLimit: 3 + activeDeadlineSeconds: 600 + ttlSecondsAfterFinished: 3600 + template: + metadata: + labels: + {{- include "outprint.labels" . | nindent 8 }} + app.kubernetes.io/component: packages + spec: + {{- include "outprint.packagesSyncPod" . | nindent 6 }} +{{- end }} diff --git a/charts/outprint/templates/worker.yaml b/charts/outprint/templates/worker.yaml index aa67c64..682b196 100644 --- a/charts/outprint/templates/worker.yaml +++ b/charts/outprint/templates/worker.yaml @@ -33,6 +33,7 @@ spec: securityContext: {{- include "outprint.podSecurity" (dict "uid" 10001) | nindent 8 }} fsGroup: 10001 + {{- include "outprint.packagesWait" . | nindent 6 }} containers: - name: worker image: {{ include "outprint.image" (dict "repository" .Values.image.repository "tag" .Values.image.tag "appVersion" .Chart.AppVersion) | quote }} @@ -48,6 +49,7 @@ spec: - name: OUTPRINT_SERVICE_CONFIG value: /etc/outprint/service.yaml {{- include "outprint.tokenEnv" . | nindent 12 }} + {{- include "outprint.packagesEnv" . | nindent 12 }} {{- include "outprint.extraEnv" .Values.worker.env | nindent 12 }} ports: - name: http @@ -69,6 +71,10 @@ spec: - { name: work, mountPath: /work } - { name: tmp, mountPath: /tmp } - { name: service-config, mountPath: /etc/outprint, readOnly: true } + {{- include "outprint.packagesVolumeMount" . | nindent 12 }} + {{- with .Values.worker.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} volumes: - name: work emptyDir: { medium: Memory, sizeLimit: {{ .Values.worker.workDirSize }} } @@ -77,6 +83,10 @@ spec: - name: service-config configMap: name: {{ include "outprint.fullname" . }}-service + {{- include "outprint.packagesVolume" . | nindent 8 }} + {{- with .Values.worker.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} {{- with .Values.worker.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/charts/outprint/values.yaml b/charts/outprint/values.yaml index fc487c3..157888e 100644 --- a/charts/outprint/values.yaml +++ b/charts/outprint/values.yaml @@ -48,6 +48,59 @@ workerToken: enabled: true existingSecret: "" +# Your own Template and Configuration packages (docs: Install > Run Outprint > +# Your own Templates and Configurations). Set at most one source. Without one, +# the packages baked into the image (neutral, example) are used. +# +# Gateway and Worker mount the packages read-only at /packages and read them +# through OUTPRINT_TEMPLATES_ROOT / OUTPRINT_CONFIGURATIONS_ROOT. Allow the +# pairs you want in serviceConfig.bindings. +packages: + # Packages in a Git repository. A CronJob (and a hook Job on install and + # upgrade) resolves `ref` to a commit; on a change it clones the commit + # (Git LFS included), runs `outprint validate`, switches over only if the + # check passes, then restarts Gateway and Worker. Only this Job has network; + # the Worker keeps its NetworkPolicy. + git: + # SSH or HTTPS URL. Empty = off. + url: "" + # Tag, branch or commit. + ref: main + # Optional integrity check: refuse any other commit (full or abbreviated SHA). + commit: "" + # Folder in the repository that holds templates/ and configurations/. + path: "" + # Secret with key `ssh-privatekey` (and optionally `known_hosts`) for a + # private repository. Empty = anonymous HTTPS. + sshKeySecret: "" + # How often the CronJob checks `ref`. + interval: 5m + # Needs git, git-lfs (installed at run time), ssh and kubectl. + image: + repository: alpine/k8s + tag: "1.33.4" + pullPolicy: IfNotPresent + resources: + requests: {cpu: 50m, memory: 64Mi} + limits: {cpu: 500m, memory: 256Mi} + persistence: + # Holds the checked out revisions. ReadWriteOnce: Gateway, Worker and the + # Job must run on the same node (single node clusters need nothing). + size: 100Mi + storageClass: "" + accessMode: ReadWriteOnce + # Keep this many old revisions besides the active one. + keepRevisions: 2 + # Packages in an OCI image (Kubernetes image volume, Kubernetes 1.35+ or the + # ImageVolume feature gate). The image holds templates/ and configurations/. + image: + reference: "" + pullPolicy: IfNotPresent + # An existing PersistentVolumeClaim that holds templates/ and configurations/. + existingClaim: "" + # Folder inside the image or claim that holds templates/ and configurations/. + path: "" + worker: # One job per replica. Throughput scales with replicas. replicas: 1 @@ -60,6 +113,8 @@ worker: tmpSize: 64Mi # Extra environment, for example OUTPRINT_TIMEOUT, OUTPRINT_MAX_PAGES. env: {} + extraVolumes: [] + extraVolumeMounts: [] nodeSelector: {} tolerations: [] affinity: {} @@ -76,6 +131,8 @@ gateway: limits: {cpu: "1", memory: 256Mi} # Extra environment, for example the OUTPRINT_BUTTON_* placement options. env: {} + extraVolumes: [] + extraVolumeMounts: [] nodeSelector: {} tolerations: [] affinity: {}