Publish paperless-ngx-helm chart for upstream v3.3.2
Validate, publish and promote Paperless-ngx / chart (push) Successful in 35s
Validate, publish and promote Paperless-ngx / chart (push) Successful in 35s
This commit is contained in:
commit
fb5db18f00
13 files changed
+361
No files matched your search
@@ -0,0 +1,71 @@
|
||||
name: Validate, publish and promote Paperless-ngx
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
jobs:
|
||||
chart:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: azure/setup-helm@v4
|
||||
with:
|
||||
version: v4.3.0
|
||||
- name: Validate chart
|
||||
run: |
|
||||
python3 -m venv "${RUNNER_TEMP}/chart-test"
|
||||
"${RUNNER_TEMP}/chart-test/bin/pip" install PyYAML
|
||||
PATH="${RUNNER_TEMP}/chart-test/bin:${PATH}" ./test.sh
|
||||
- name: Select immutable chart version
|
||||
if: gitea.ref == 'refs/heads/main'
|
||||
run: printf 'CHART_VERSION=%s\n' "$(./scripts/chart-version.sh)" >> "${GITHUB_ENV}"
|
||||
- name: Package and publish chart
|
||||
if: gitea.ref == 'refs/heads/main'
|
||||
env:
|
||||
PACKAGE_USERNAME: ${{ secrets.PACKAGE_USERNAME }}
|
||||
PACKAGE_TOKEN: ${{ secrets.PACKAGE_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
test -n "${PACKAGE_USERNAME}" && test -n "${PACKAGE_TOKEN}"
|
||||
mkdir -p .chart-packages
|
||||
helm package chart/paperless-ngx --destination .chart-packages --version "${CHART_VERSION}"
|
||||
curl --fail --silent --show-error --user "${PACKAGE_USERNAME}:${PACKAGE_TOKEN}" \
|
||||
--request POST --upload-file ".chart-packages/paperless-ngx-${CHART_VERSION}.tgz" \
|
||||
https://code.brunner.ninja/api/packages/feedc0de/helm/api/charts
|
||||
- name: Check current main
|
||||
id: current-main
|
||||
if: gitea.ref == 'refs/heads/main'
|
||||
env:
|
||||
COMMIT_SHA: ${{ gitea.sha }}
|
||||
run: |
|
||||
git fetch --no-tags origin main
|
||||
if test "$(git rev-parse FETCH_HEAD)" = "${COMMIT_SHA}"; then
|
||||
echo 'promote=true' >> "${GITEA_OUTPUT}"
|
||||
else
|
||||
echo 'promote=false' >> "${GITEA_OUTPUT}"
|
||||
fi
|
||||
- uses: actions/checkout@v4
|
||||
if: steps.current-main.outputs.promote == 'true'
|
||||
with:
|
||||
repository: feedc0de/homelab-gitops
|
||||
ref: main
|
||||
token: ${{ secrets.GITOPS_TOKEN }}
|
||||
path: homelab-gitops
|
||||
- name: Promote chart
|
||||
if: steps.current-main.outputs.promote == 'true'
|
||||
working-directory: homelab-gitops
|
||||
run: |
|
||||
set -euo pipefail
|
||||
./scripts/update-chart-version.sh paperless "${CHART_VERSION}"
|
||||
git config user.name feedc0de
|
||||
git config user.email feedc0de@users.noreply.code.brunner.ninja
|
||||
git add bootstrap/paperless.yaml
|
||||
if git diff --cached --quiet; then exit 0; fi
|
||||
git commit -m "Deploy paperless chart ${CHART_VERSION}"
|
||||
for attempt in 1 2 3; do
|
||||
git push origin HEAD:main && exit 0
|
||||
test "${attempt}" = 3 && exit 1
|
||||
git fetch origin main
|
||||
git rebase origin/main
|
||||
done
|
||||
@@ -0,0 +1,27 @@
|
||||
# Paperless-ngx Helm chart
|
||||
|
||||
This independent chart packages the upstream Paperless-ngx image without bundling
|
||||
PostgreSQL or Valkey. It declares the Paperless Deployment, Service, Ingress,
|
||||
probes, Secret references, and optional PVCs. The chart Git tag follows the
|
||||
upstream application release (`v3.3.2`); later chart-only commits append Git
|
||||
describe's count and hash. The default image tag comes from `appVersion`.
|
||||
|
||||
Supply existing Secret names for the Paperless key and PostgreSQL password.
|
||||
The chart never renders credentials. Set `persistence.data.existingClaim` and
|
||||
`persistence.runtime.existingClaim` to retain existing claims. The shared data
|
||||
claim may also be mounted by a separate scanner release. Scheduling affinity,
|
||||
tolerations, OCR worker count, and cluster hostname are values, not chart
|
||||
constants. The homelab deployment is in
|
||||
[homelab-gitops/apps/paperless](https://code.brunner.ninja/feedc0de/homelab-gitops/src/branch/main/apps/paperless).
|
||||
|
||||
```sh
|
||||
helm repo add brunner.ninja https://brunner.ninja/charts
|
||||
helm repo update brunner.ninja
|
||||
helm upgrade --install paperless brunner.ninja/paperless-ngx \
|
||||
--namespace paperless-ngx --create-namespace -f values.yaml --wait --timeout 15m
|
||||
```
|
||||
|
||||
For local testing run `./test.sh`; `./install.sh values.yaml` uses the current
|
||||
Kubernetes context and the chart in this checkout. CI publishes the chart,
|
||||
then promotes only its chart version to GitOps. Required Actions secrets are
|
||||
`PACKAGE_USERNAME`, `PACKAGE_TOKEN`, and `GITOPS_TOKEN`.
|
||||
@@ -0,0 +1,6 @@
|
||||
apiVersion: v2
|
||||
name: paperless-ngx
|
||||
description: Paperless-ngx application without a bundled database or cache
|
||||
type: application
|
||||
version: 0.0.0
|
||||
appVersion: 3.3.2
|
||||
@@ -0,0 +1,91 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: paperless
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels: {app: paperless}
|
||||
template:
|
||||
metadata:
|
||||
labels: {app: paperless}
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
enableServiceLinks: false
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{ toYaml . | indent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: paperless
|
||||
image: {{ printf "%s:%s" .Values.image.repository (.Values.image.tag | default .Chart.AppVersion) | quote }}
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports: [{name: http, containerPort: 8000}]
|
||||
env:
|
||||
- {name: PAPERLESS_URL, value: {{ .Values.url | quote }}}
|
||||
- {name: PAPERLESS_REDIS, value: {{ .Values.cache.url | quote }}}
|
||||
- {name: PAPERLESS_DBENGINE, value: postgresql}
|
||||
- {name: PAPERLESS_DBHOST, value: {{ .Values.database.host | quote }}}
|
||||
- {name: PAPERLESS_DBNAME, value: {{ .Values.database.name | quote }}}
|
||||
- {name: PAPERLESS_DBUSER, value: {{ .Values.database.user | quote }}}
|
||||
- name: PAPERLESS_DBPASS
|
||||
valueFrom:
|
||||
secretKeyRef: {name: {{ .Values.database.passwordSecretName }}, key: {{ .Values.database.passwordSecretKey }}}
|
||||
- {name: PAPERLESS_TIME_ZONE, value: {{ .Values.timeZone | quote }}}
|
||||
- {name: PAPERLESS_OCR_LANGUAGE, value: {{ .Values.ocrLanguage | quote }}}
|
||||
- {name: PAPERLESS_TASK_WORKERS, value: {{ .Values.taskWorkers | quote }}}
|
||||
- {name: PAPERLESS_THREADS_PER_WORKER, value: {{ .Values.threadsPerWorker | quote }}}
|
||||
- {name: PAPERLESS_CONSUMER_POLLING_INTERVAL, value: {{ .Values.consumerPollingInterval | quote }}}
|
||||
{{- if .Values.oidc.enabled }}
|
||||
- {name: PAPERLESS_APPS, value: allauth.socialaccount.providers.openid_connect}
|
||||
- {name: PAPERLESS_SOCIAL_AUTO_SIGNUP, value: "true"}
|
||||
- {name: PAPERLESS_SOCIAL_ACCOUNT_SYNC_GROUPS, value: "true"}
|
||||
- {name: PAPERLESS_SOCIAL_ACCOUNT_SYNC_SUPERUSER_GROUP, value: {{ .Values.oidc.adminGroup | quote }}}
|
||||
- name: PAPERLESS_SOCIALACCOUNT_PROVIDERS
|
||||
valueFrom:
|
||||
secretKeyRef: {name: {{ .Values.oidc.providersSecretName }}, key: {{ .Values.oidc.providersSecretKey }}}
|
||||
{{- end }}
|
||||
- name: PAPERLESS_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef: {name: {{ .Values.secretKey.secretName }}, key: {{ .Values.secretKey.secretKey }}}
|
||||
volumeMounts:
|
||||
- {name: runtime, mountPath: /usr/src/paperless/data}
|
||||
- {name: data, mountPath: /usr/src/paperless/media, subPath: media}
|
||||
- {name: data, mountPath: /usr/src/paperless/consume, subPath: consume}
|
||||
- {name: data, mountPath: /usr/src/paperless/export, subPath: export}
|
||||
startupProbe:
|
||||
httpGet: {path: /, port: http}
|
||||
periodSeconds: 10
|
||||
failureThreshold: 60
|
||||
timeoutSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet: {path: /, port: http}
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 10
|
||||
failureThreshold: 6
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- sh
|
||||
- -ec
|
||||
- |
|
||||
for service in svc-worker svc-webserver svc-consumer svc-scheduler; do
|
||||
pid="$(s6-svstat -o pid "/run/service/$service")"
|
||||
[ "$pid" -gt 0 ]
|
||||
done
|
||||
periodSeconds: 60
|
||||
timeoutSeconds: 30
|
||||
failureThreshold: 30
|
||||
resources:
|
||||
{{ toYaml .Values.resources | indent 12 }}
|
||||
volumes:
|
||||
- name: runtime
|
||||
persistentVolumeClaim: {claimName: {{ .Values.persistence.runtime.existingClaim | default "paperless-runtime" }}}
|
||||
- name: data
|
||||
persistentVolumeClaim: {claimName: {{ .Values.persistence.data.existingClaim | default "paperless-data" }}}
|
||||
@@ -0,0 +1,24 @@
|
||||
{{- if .Values.ingress.enabled }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: paperless
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{ toYaml . | indent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.ingress.className }}
|
||||
ingressClassName: {{ . }}
|
||||
{{- end }}
|
||||
rules:
|
||||
- host: {{ .Values.ingress.host | quote }}
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: paperless
|
||||
port: {name: http}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,33 @@
|
||||
{{- if not .Values.persistence.data.existingClaim }}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: paperless-data
|
||||
annotations:
|
||||
helm.sh/resource-policy: keep
|
||||
spec:
|
||||
accessModes: [ReadWriteMany]
|
||||
{{- with .Values.persistence.data.storageClassName }}
|
||||
storageClassName: {{ . }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.persistence.data.size }}
|
||||
---
|
||||
{{- end }}
|
||||
{{- if not .Values.persistence.runtime.existingClaim }}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: paperless-runtime
|
||||
annotations:
|
||||
helm.sh/resource-policy: keep
|
||||
spec:
|
||||
accessModes: [ReadWriteOnce]
|
||||
{{- with .Values.persistence.runtime.storageClassName }}
|
||||
storageClassName: {{ . }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.persistence.runtime.size }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: paperless
|
||||
spec:
|
||||
selector: {app: paperless}
|
||||
ports: [{name: http, port: 8000, targetPort: http}]
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"required": ["database", "secretKey"],
|
||||
"properties": {
|
||||
"database": {"type": "object", "required": ["passwordSecretName"], "properties": {"passwordSecretName": {"type": "string", "minLength": 1}}},
|
||||
"secretKey": {"type": "object", "required": ["secretName"], "properties": {"secretName": {"type": "string", "minLength": 1}}},
|
||||
"persistence": {"type": "object", "properties": {
|
||||
"data": {"type": "object", "properties": {"existingClaim": {"type": "string"}}},
|
||||
"runtime": {"type": "object", "properties": {"existingClaim": {"type": "string"}}}
|
||||
}}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
image:
|
||||
repository: ghcr.io/paperless-ngx/paperless-ngx
|
||||
tag: ""
|
||||
pullPolicy: IfNotPresent
|
||||
replicaCount: 1
|
||||
url: ""
|
||||
timeZone: UTC
|
||||
ocrLanguage: eng
|
||||
taskWorkers: 2
|
||||
threadsPerWorker: 1
|
||||
consumerPollingInterval: 5
|
||||
database:
|
||||
host: postgresql
|
||||
name: paperless
|
||||
user: paperless
|
||||
passwordSecretName: ""
|
||||
passwordSecretKey: USERDB_PASSWORD
|
||||
cache:
|
||||
url: redis://valkey:6379
|
||||
secretKey:
|
||||
secretName: ""
|
||||
secretKey: secret-key
|
||||
oidc:
|
||||
enabled: false
|
||||
providersSecretName: ""
|
||||
providersSecretKey: providers
|
||||
adminGroup: Paperless Admins
|
||||
persistence:
|
||||
data:
|
||||
existingClaim: ""
|
||||
size: 20Gi
|
||||
storageClassName: ""
|
||||
runtime:
|
||||
existingClaim: ""
|
||||
size: 4Gi
|
||||
storageClassName: ""
|
||||
ingress:
|
||||
enabled: false
|
||||
className: ""
|
||||
host: ""
|
||||
annotations: {}
|
||||
affinity: {}
|
||||
tolerations: []
|
||||
resources: {}
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
values=${1:?usage: ./install.sh VALUES_FILE}
|
||||
./test.sh
|
||||
helm upgrade --install paperless chart/paperless-ngx --namespace paperless-ngx --create-namespace --values "$values" --wait --timeout 15m
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
description=$(git describe --tags --long --match 'v[0-9]*' --dirty)
|
||||
case "$description" in *-dirty) echo 'Refusing to package a dirty tree' >&2; exit 1 ;; esac
|
||||
version=${description#v}
|
||||
case "$version" in *-0-g*) version=${version%%-0-g*} ;; esac
|
||||
printf '%s\n' "$version"
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
cd "$(dirname "$0")"
|
||||
helm lint --strict chart/paperless-ngx -f values.example.yaml
|
||||
helm template paperless chart/paperless-ngx -n example -f values.example.yaml | python3 -c '
|
||||
import sys, yaml
|
||||
objects=[x for x in yaml.safe_load_all(sys.stdin) if x]
|
||||
one=lambda kind,name: next(x for x in objects if x["kind"]==kind and x["metadata"]["name"]==name)
|
||||
d=one("Deployment","paperless")
|
||||
s=one("Service","paperless")
|
||||
assert d["spec"]["selector"]["matchLabels"]==s["spec"]["selector"]
|
||||
c=d["spec"]["template"]["spec"]["containers"][0]
|
||||
assert all(k in c for k in ("startupProbe","readinessProbe","livenessProbe"))
|
||||
assert {v["name"] for v in d["spec"]["template"]["spec"]["volumes"]}=={"data","runtime"}
|
||||
assert any(e["name"]=="PAPERLESS_DBPASS" and "secretKeyRef" in e["valueFrom"] for e in c["env"])
|
||||
assert not any(x["kind"]=="Secret" for x in objects)
|
||||
assert one("PersistentVolumeClaim","paperless-data") and one("PersistentVolumeClaim","paperless-runtime")
|
||||
'
|
||||
@@ -0,0 +1,14 @@
|
||||
url: https://paper.example.com
|
||||
database:
|
||||
passwordSecretName: paperless-postgres
|
||||
secretKey:
|
||||
secretName: paperless-secret-key
|
||||
persistence:
|
||||
data:
|
||||
size: 20Gi
|
||||
runtime:
|
||||
size: 4Gi
|
||||
ingress:
|
||||
enabled: true
|
||||
className: traefik
|
||||
host: paper.example.com
|
||||
Reference in new issue
Block a user