feat(paperless): deploy Paperless-ngx on shared PostgreSQL
ci / Compose (pull_request) Canceled after 0s
ci / Workflows (pull_request) Canceled after 0s
ci / Shell (pull_request) Canceled after 0s
ci / Formatting (pull_request) Canceled after 0s
ci / Python and tests (pull_request) Canceled after 0s
ci / YAML (pull_request) Canceled after 0s
ci / Dockerfiles (pull_request) Canceled after 0s
ci / Kubernetes (pull_request) Canceled after 0s
ci / image-plan (pull_request) Canceled after 0s
ci / Image (${{ matrix.name }}) (pull_request) Canceled after 0s
ci / build (pull_request) Canceled after 0s

This commit is contained in:
forust committed 2026-10-08 00:32:54 +02:00
1 parent 4c7c53e0f2
commit fb46fb48b5
14 files changed
+455 -4

No files matched your search

+1
View File
@@ -0,0 +1 @@
+28
View File
@@ -0,0 +1,28 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: paperless-prod-tls
namespace: paperless
spec:
secretName: paperless-prod-tls
dnsNames:
- papers.forust.xyz
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: internal-wildcard-tls
namespace: paperless
spec:
secretName: internal-wildcard-tls
dnsNames:
- "*.workstation.internal"
- "*.gigaforust.internal"
- workstation.internal
- gigaforust.internal
issuerRef:
name: internal-ca
kind: ClusterIssuer
+58
View File
@@ -0,0 +1,58 @@
apiVersion: batch/v1
kind: Job
metadata:
name: paperless-database-init
namespace: database
spec:
backoffLimit: 5
template:
metadata:
labels:
app.kubernetes.io/name: paperless-database-init
spec:
restartPolicy: OnFailure
containers:
- name: create-database
image: postgres:17.11-alpine
command:
- /bin/sh
- -ec
- |
PGPASSWORD="$POSTGRES_ADMIN_PASSWORD" psql \
--host postgres \
--username postgres \
--dbname postgres \
--set ON_ERROR_STOP=1 \
--set paperless_password="$PAPERLESS_DB_PASSWORD" <<'SQL'
SELECT format(
'CREATE ROLE paperless LOGIN PASSWORD %L',
:'paperless_password'
)
WHERE NOT EXISTS (
SELECT FROM pg_roles WHERE rolname = 'paperless'
)
\gexec
SELECT format('CREATE DATABASE paperless OWNER paperless')
WHERE NOT EXISTS (
SELECT FROM pg_database WHERE datname = 'paperless'
)
\gexec
SQL
env:
- name: POSTGRES_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-shared-secrets
key: POSTGRES_ADMIN_PASSWORD
- name: PAPERLESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-shared-secrets
key: PAPERLESS_DB_PASSWORD
resources:
requests:
cpu: 10m
memory: 32Mi
limits:
cpu: 100m
memory: 128Mi
+33
View File
@@ -0,0 +1,33 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: paperless-prod
namespace: paperless
spec:
entryPoints:
- websecure
routes:
- match: Host(`papers.forust.xyz`)
kind: Rule
services:
- name: paperless
port: 8000
tls:
secretName: paperless-prod-tls
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: paperless-local
namespace: paperless
spec:
entryPoints:
- websecure
routes:
- match: Host(`papers.workstation.internal`)
kind: Rule
services:
- name: paperless
port: 8000
tls:
secretName: internal-wildcard-tls
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: paperless
+39
View File
@@ -0,0 +1,39 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: paperless-ingress
namespace: paperless
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: paperless
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: traefik
ports:
- protocol: TCP
port: 8000
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: paperless-valkey-ingress
namespace: paperless
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: paperless-valkey
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: paperless
ports:
- protocol: TCP
port: 6379
+210
View File
@@ -0,0 +1,210 @@
apiVersion: v1
kind: Service
metadata:
name: paperless
namespace: paperless
labels:
app.kubernetes.io/name: paperless
spec:
selector:
app.kubernetes.io/name: paperless
ports:
- name: http
port: 8000
targetPort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: paperless
namespace: paperless
labels:
app.kubernetes.io/name: paperless
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/name: paperless
template:
metadata:
labels:
app.kubernetes.io/name: paperless
spec:
enableServiceLinks: false
containers:
- name: paperless
image: ghcr.io/paperless-ngx/paperless-ngx:3.2.1
ports:
- name: http
containerPort: 8000
env:
- name: PAPERLESS_URL
value: https://papers.forust.xyz
- name: PAPERLESS_ALLOWED_HOSTS
value: papers.forust.xyz,papers.workstation.internal
- name: PAPERLESS_CSRF_TRUSTED_ORIGINS
value: https://papers.forust.xyz,https://papers.workstation.internal
- name: PAPERLESS_TIME_ZONE
value: Europe/Bratislava
- name: PAPERLESS_REDIS
value: redis://paperless-valkey:6379
- name: PAPERLESS_DBENGINE
value: postgresql
- name: PAPERLESS_DBHOST
value: postgres.database.svc.cluster.local
- name: PAPERLESS_DBNAME
value: paperless
- name: PAPERLESS_DBUSER
value: paperless
- name: PAPERLESS_DBPASS
valueFrom:
secretKeyRef:
name: paperless-secrets
key: PAPERLESS_DB_PASSWORD
- name: PAPERLESS_OCR_LANGUAGE
value: rus+eng
- name: PAPERLESS_OCR_LANGUAGES
value: rus
- name: PAPERLESS_TASK_WORKERS
value: "1"
- name: PAPERLESS_ADMIN_USER
value: admin
- name: PAPERLESS_SECRET_KEY
valueFrom:
secretKeyRef:
name: paperless-secrets
key: PAPERLESS_SECRET_KEY
- name: PAPERLESS_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: paperless-secrets
key: PAPERLESS_ADMIN_PASSWORD
volumeMounts:
- name: documents
mountPath: /usr/src/paperless/data
subPath: data
- name: documents
mountPath: /usr/src/paperless/media
subPath: media
- name: documents
mountPath: /usr/src/paperless/export
subPath: export
- name: documents
mountPath: /usr/src/paperless/consume
subPath: consume
startupProbe:
httpGet:
path: /
port: http
httpHeaders:
- name: Host
value: papers.workstation.internal
failureThreshold: 60
periodSeconds: 10
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /
port: http
httpHeaders:
- name: Host
value: papers.workstation.internal
periodSeconds: 10
timeoutSeconds: 5
livenessProbe:
httpGet:
path: /
port: http
httpHeaders:
- name: Host
value: papers.workstation.internal
periodSeconds: 30
timeoutSeconds: 5
resources:
requests:
cpu: 100m
memory: 512Mi
limits:
cpu: "2"
memory: 2Gi
volumes:
- name: documents
persistentVolumeClaim:
claimName: paperless-data
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: paperless-data
namespace: paperless
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-path-retain
resources:
requests:
storage: 50Gi
---
apiVersion: v1
kind: Service
metadata:
name: paperless-valkey
namespace: paperless
labels:
app.kubernetes.io/name: paperless-valkey
spec:
selector:
app.kubernetes.io/name: paperless-valkey
ports:
- name: redis
port: 6379
targetPort: redis
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: paperless-valkey
namespace: paperless
labels:
app.kubernetes.io/name: paperless-valkey
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/name: paperless-valkey
template:
metadata:
labels:
app.kubernetes.io/name: paperless-valkey
spec:
containers:
- name: valkey
image: valkey/valkey:9.0.3-alpine
args:
- valkey-server
- --save
- ""
- --appendonly
- "no"
ports:
- name: redis
containerPort: 6379
readinessProbe:
exec:
command: ["valkey-cli", "ping"]
periodSeconds: 10
livenessProbe:
exec:
command: ["valkey-cli", "ping"]
periodSeconds: 30
resources:
requests:
cpu: 25m
memory: 64Mi
limits:
cpu: 250m
memory: 256Mi
+10
View File
@@ -0,0 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: paperless-secrets
namespace: paperless
type: Opaque
stringData:
PAPERLESS_SECRET_KEY: "<GENERATE_WITH_python3_-c_import_secrets;_print(secrets.token_urlsafe(64))>"
PAPERLESS_ADMIN_PASSWORD: "<SET_A_LONG_UNIQUE_PASSWORD>"
PAPERLESS_DB_PASSWORD: "<SET_THE_SAME_VALUE_AS_database_PAPERLESS_DB_PASSWORD>"