From 5cbccbaae2dda3a009f68cb8ab1099caf1c17d43 Mon Sep 17 00:00:00 2001 From: JJGadgets Date: Sun, 23 Nov 2025 22:54:34 +0800 Subject: [PATCH] feat(paperless-ngx): migrate app-template v4, rm supervisord --- .../apps/paperless-ngx/app/authentik.yaml | 22 -- kube/deploy/apps/paperless-ngx/app/hr.yaml | 221 ++++++++---------- .../deploy/apps/paperless-ngx/app/netpol.yaml | 32 --- kube/deploy/apps/paperless-ngx/ks.yaml | 71 +++--- .../apps/paperless-ngx/kustomization.yaml | 2 + kube/deploy/apps/paperless-ngx/ns.yaml | 5 + kube/deploy/apps/paperless-ngx/vars.yaml | 37 +++ 7 files changed, 190 insertions(+), 200 deletions(-) delete mode 100644 kube/deploy/apps/paperless-ngx/app/authentik.yaml delete mode 100644 kube/deploy/apps/paperless-ngx/app/netpol.yaml create mode 100644 kube/deploy/apps/paperless-ngx/vars.yaml diff --git a/kube/deploy/apps/paperless-ngx/app/authentik.yaml b/kube/deploy/apps/paperless-ngx/app/authentik.yaml deleted file mode 100644 index eeb8ddf7..00000000 --- a/kube/deploy/apps/paperless-ngx/app/authentik.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: paperless-ngx-authentik - namespace: authentik -spec: - ingressClassName: "nginx-internal" - rules: - - host: &host "${APP_DNS_PAPERLESS_NGX}" - http: - paths: - - pathType: Prefix - path: "/outpost.goauthentik.io" - backend: - service: - name: authentik - port: - name: http - tls: - - hosts: - - *host diff --git a/kube/deploy/apps/paperless-ngx/app/hr.yaml b/kube/deploy/apps/paperless-ngx/app/hr.yaml index 35b41a24..715b0875 100644 --- a/kube/deploy/apps/paperless-ngx/app/hr.yaml +++ b/kube/deploy/apps/paperless-ngx/app/hr.yaml @@ -1,4 +1,5 @@ --- +# yaml-language-server: $schema=https://raw.githubusercontent.com/bjw-s/helm-charts/app-template-4.4.0/charts/other/app-template/schemas/helmrelease-helm-v2.schema.json apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -6,40 +7,33 @@ metadata: namespace: *app spec: interval: 5m - chart: - spec: - chart: app-template - version: 2.6.0 - sourceRef: - name: bjw-s - kind: HelmRepository - namespace: flux-system + chartRef: + kind: OCIRepository + name: *app + namespace: *app values: controllers: - main: + app: type: deployment replicas: 1 pod: labels: - db.home.arpa/pg: "pg-home" - ingress.home.arpa/nginx-internal: "allow" - authentik.home.arpa/https: "allow" - # egress.home.arpa/nginx-external: "allow" # authentik # commented out currently because only OIDC needs this + ingress.home.arpa/nginx-internal: allow + authentik.home.arpa/https: allow containers: - main: - image: - repository: "ghcr.io/paperless-ngx/paperless-ngx" - tag: "2.19.6@sha256:719a4e4c4314b417646b00e58bfbfbe55e4cb59017a2dec1533e96d8deb66ec1" - args: ["/usr/local/bin/supervisord", "-c", "/etc/supervisord.conf", "--user", "paperless", "--logfile", "/tmp/supervisord.log", "--pidfile", "/tmp/supervisord.pid"] + app: + image: &img + repository: ghcr.io/paperless-ngx/paperless-ngx + tag: 2.19.6@sha256:719a4e4c4314b417646b00e58bfbfbe55e4cb59017a2dec1533e96d8deb66ec1 env: PAPERLESS_URL: "https://${APP_DNS_PAPERLESS_NGX}" PAPERLESS_PORT: &port "8000" PAPERLESS_TIME_ZONE: "${CONFIG_TZ}" - PAPERLESS_WEBSERVER_WORKERS: "2" + PAPERLESS_WEBSERVER_WORKERS: "2" # TODO: use fieldRef for this PAPERLESS_TASK_WORKERS: "2" PAPERLESS_REDIS: "unix:///sockets/redis.sock" PAPERLESS_CONSUMPTION_DIR: &consume "/data/consume" - PAPERLESS_DATA_DIR: &pvc "/data/data" + PAPERLESS_DATA_DIR: &pvc "/data/data" # including PVC PAPERLESS_EXPORT_DIR: &export "/data/export" PAPERLESS_MEDIA_ROOT: &media "/data/media" PAPERLESS_TRASH_DIR: &trash "/data/trash" @@ -54,34 +48,8 @@ spec: PAPERLESS_TIKA_ENABLED: "true" PAPERLESS_TIKA_ENDPOINT: "http://tika.paperless-ngx.svc.cluster.local" PAPERLESS_TIKA_GOTENBERG_ENDPOINT: "http://gotenberg.paperless-ngx.svc.cluster.local" - PAPERLESS_DBENGINE: "postgresql" - # PAPERLESS_DBSSLMODE: "verify-full" - # PAPERLESS_DBSSLROOTCERT: &pg-ca "/pg-tls/ca.crt" - PAPERLESS_DBHOST: - valueFrom: - secretKeyRef: - name: &pguser "pg-home-pguser-paperless-ngx" - key: "pgbouncer-host" - PAPERLESS_DBPORT: - valueFrom: - secretKeyRef: - name: *pguser - key: "pgbouncer-port" - PAPERLESS_DBNAME: - valueFrom: - secretKeyRef: - name: *pguser - key: "dbname" - PAPERLESS_DBUSER: - valueFrom: - secretKeyRef: - name: *pguser - key: "user" - PAPERLESS_DBPASS: - valueFrom: - secretKeyRef: - name: *pguser - key: "password" + USERMAP_UID: &uid 1000 + USERMAP_GID: *uid envFrom: - secretRef: name: "paperless-ngx-secrets" @@ -93,10 +61,14 @@ spec: resources: requests: cpu: "10m" - memory: "1000Mi" limits: - cpu: "3000m" - memory: "3000Mi" + cpu: "1" + memory: "512Mi" + probes: + liveness: + enabled: true + readiness: + enabled: true redis: image: repository: "public.ecr.aws/docker/library/redis" @@ -116,16 +88,21 @@ spec: containers: main: image: - repository: "ghcr.io/paperless-ngx/tika" - tag: "2.9.1-full@sha256:d59c38244949a418ef16be676eeea770e1616b45986661847d373f4de048a37e" + repository: docker.io/apache/tika + tag: 3.2.3.0@sha256:c0154cb95587cde64be74f35ada1a2bd7892219f3f0ac3c9dc6cab34046b3573 securityContext: *sc resources: # TODO: adjust (Java app) requests: cpu: "10m" memory: "256Mi" limits: - cpu: "3000m" - memory: "6000Mi" + cpu: "1" + memory: "1Gi" + probes: + liveness: + enabled: true + readiness: + enabled: true gotenberg: type: deployment replicas: 1 @@ -141,74 +118,81 @@ spec: cpu: "10m" memory: "64Mi" limits: - cpu: "3000m" - memory: "6000Mi" + cpu: "1" + memory: "1Gi" + probes: + liveness: + enabled: true + readiness: + enabled: true service: - main: + app: + controller: app ports: http: - port: *port + port: 80 + targetPort: *port + protocol: HTTP + appProtocol: http tika: - controller: "tika" + controller: tika ports: - tika: + http: port: 80 targetPort: 9998 + protocol: HTTP + appProtocol: http gotenberg: - controller: "gotenberg" + controller: gotenberg ports: - gotenberg: + http: port: 80 targetPort: 3000 + protocol: HTTP + appProtocol: http ingress: - main: - enabled: true - primary: true - className: "nginx-internal" + app: + className: nginx-internal hosts: - - host: &host "${APP_DNS_PAPERLESS_NGX:=paperless}" - paths: - - path: "/" + - host: &host "${APP_DNS_PAPERLESS_NGX:=paperless-ngx}" + paths: &paths + - path: / pathType: Prefix service: - name: main + identifier: app port: http tls: - - hosts: - - *host + - hosts: [*host] persistence: data: - enabled: true - existingClaim: "paperless-ngx-data" + existingClaim: paperless-ngx-data globalMounts: - subPath: "consume" - path: "/data/consume" + path: *consume - subPath: "data" - path: "/data/data" + path: *pvc - subPath: "export" - path: "/data/export" + path: *export - subPath: "media" - path: "/data/media" + path: *media - subPath: "trash" - path: "/data/trash" - nas: - enabled: true - type: nfs - server: "${IP_TRUENAS:=127.0.0.1}" - path: "${PATH_NAS_PERSIST_K8S:=/data}/paperless-ngx" - advancedMounts: - main: - main: - - path: "/nas" + path: *trash + # nfs: + # type: nfs + # server: "${IP_TRUENAS:=127.0.0.1}" + # path: ${PATH_NAS_PERSIST_K8S:=/data}/paperless-ngx + # globalMounts: + # - path: /nfs tmp: - enabled: true type: emptyDir medium: Memory + sizeLimit: 16Mi + globalMounts: + - subPath: tmp + path: /tmp advancedMounts: main: main: - - subPath: "paperless" - path: "/tmp" - subPath: "apt" path: "/var/lib/apt" - &sockdir @@ -216,49 +200,46 @@ spec: path: "/sockets" redis: - *sockdir - tika: - main: - - subPath: "tika" - path: "/tmp" - gotenberg: - main: - - subPath: "gotenberg" - path: "/tmp" - # pg-tls: - # enabled: true - # type: secret - # name: "pg-paperless-ngx-cluster-cert" - # defaultMode: 0400 - # advancedMounts: - # main: - # main: - # - subPath: "ca.crt" - # path: *pg-ca - # readOnly: true defaultPodOptions: automountServiceAccountToken: false - enableServiceLinks: false # avoid exposing too much info in env vars in case of lateral movement attempt + enableServiceLinks: false hostAliases: - ip: "${APP_IP_AUTHENTIK:=127.0.0.1}" hostnames: ["${APP_DNS_AUTHENTIK:=authentik}"] + dnsConfig: + options: + - name: ndots + value: "1" + # hostUsers: true + # securityContext: + # runAsNonRoot: true + # runAsUser: &uid ${APP_UID_PAPERLESS-NGX:=1000} + hostUsers: false securityContext: - runAsNonRoot: false - runAsUser: &uid 1000 # hardcoded `paperless` user + runAsNonRoot: true + runAsUser: *uid # hardcoded `paperless` user runAsGroup: *uid fsGroup: *uid - fsGroupChangePolicy: "Always" + fsGroupChangePolicy: Always seccompProfile: { type: "RuntimeDefault" } topologySpreadConstraints: - maxSkew: 1 - topologyKey: "kubernetes.io/hostname" - whenUnsatisfiable: "DoNotSchedule" + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: - app.kubernetes.io/name: *app + app.kubernetes.io/name: "{{ .Release.Name }}" affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - - key: "fuckoff.home.arpa/paperless-ngx" - operator: "DoesNotExist" + - key: "fuckoff.home.arpa/{{ .Release.Name }}" + operator: DoesNotExist + networkpolicies: + same-ns: + podSelector: {} + policyTypes: [Ingress, Egress] + rules: + ingress: [from: [{podSelector: {}}]] + egress: [to: [{podSelector: {}}]] diff --git a/kube/deploy/apps/paperless-ngx/app/netpol.yaml b/kube/deploy/apps/paperless-ngx/app/netpol.yaml deleted file mode 100644 index d62f442e..00000000 --- a/kube/deploy/apps/paperless-ngx/app/netpol.yaml +++ /dev/null @@ -1,32 +0,0 @@ ---- -# yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/cilium.io/ciliumnetworkpolicy_v2.json -apiVersion: cilium.io/v2 -kind: CiliumNetworkPolicy -metadata: - name: &app paperless-ngx - namespace: *app -spec: - endpointSelector: {} - egress: - # same namespace - - toEndpoints: - - matchLabels: - io.kubernetes.pod.namespace: *app - # Debian apt repos - - toFQDNs: &apt - - matchName: "deb.debian.org" - - matchName: "debian.map.fastlydns.net" - # toFQDNs - - toEndpoints: - - matchLabels: - "k8s:io.kubernetes.pod.namespace": kube-system - "k8s:k8s-app": kube-dns - - matchLabels: - io.kubernetes.pod.namespace: kube-system - k8s-app: kube-dns - toPorts: - - ports: - - port: "53" - protocol: "ANY" - rules: - dns: *apt diff --git a/kube/deploy/apps/paperless-ngx/ks.yaml b/kube/deploy/apps/paperless-ngx/ks.yaml index 58232110..cec87d49 100644 --- a/kube/deploy/apps/paperless-ngx/ks.yaml +++ b/kube/deploy/apps/paperless-ngx/ks.yaml @@ -3,63 +3,82 @@ apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: name: paperless-ngx-app - namespace: flux-system + namespace: &ns paperless-ngx labels: &l app.kubernetes.io/name: "paperless-ngx" spec: + targetNamespace: *ns commonMetadata: labels: *l path: ./kube/deploy/apps/paperless-ngx/app - targetNamespace: "paperless-ngx" + components: + - ../../../core/flux-system/alerts/template/ + - ../../../../repos/flux/helm/oci/app-template/ dependsOn: - - name: paperless-ngx-db + - name: crds + namespace: flux-system - name: paperless-ngx-pvc + postBuild: + substitute: + APP_TEMPLATE: 4.4.0 --- apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: name: paperless-ngx-pvc - namespace: flux-system + namespace: &ns paperless-ngx labels: &l - app.kubernetes.io/name: "paperless-ngx" + app.kubernetes.io/name: paperless-ngx + pvc.home.arpa/volsync: "true" spec: + targetNamespace: *ns commonMetadata: labels: *l path: ./kube/deploy/core/storage/volsync/template - targetNamespace: "paperless-ngx" dependsOn: - - name: 1-core-storage-volsync-app - - name: 1-core-storage-rook-ceph-cluster + - name: crds + namespace: flux-system postBuild: substitute: - PVC: "paperless-ngx-data" + PVC: &pvc "paperless-ngx-data" SIZE: "100Gi" SC: &sc "file" SNAP: *sc ACCESSMODE: "ReadWriteMany" - RUID: !!str &uid | - ${APP_UID_PAPERLESS_NGX} - RGID: !!str | - ${APP_UID_PAPERLESS_NGX} - RFSG: !!str | - ${APP_UID_PAPERLESS_NGX} + SNAP_ACCESSMODE: "ReadOnlyMany" + VS_APP_CURRENT_VERSION: "ghcr.io/paperless-ngx/paperless-ngx:2.19.6@sha256:719a4e4c4314b417646b00e58bfbfbe55e4cb59017a2dec1533e96d8deb66ec1" + RUID: &uid "1000" + RGID: *uid + RFSG: *uid + healthChecks: + - apiVersion: v1 + kind: PersistentVolumeClaim + name: *pvc + namespace: *ns + - apiVersion: volsync.backube/v1alpha1 + kind: ReplicationSource + name: "paperless-ngx-data-r2-updates-restic" + namespace: *ns + healthCheckExprs: + - apiVersion: volsync.backube/v1alpha1 + kind: ReplicationSource + current: status.conditions.filter(s, s.status == "False").all(s, s.reason == "WaitingForManual" || s.reason == "WaitingForSchedule") && status.latestMoverStatus.result == "Successful" + failed: status.latestMoverStatus.result == "Failed" # TODO: add failed conditions --- apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: - name: paperless-ngx-db + name: authentik-paperless-ngx namespace: flux-system - labels: - prune.flux.home.arpa/enabled: "true" - db.home.arpa/pg: "pg-home" + labels: &l + app.kubernetes.io/name: "paperless-ngx" spec: - path: ./kube/deploy/core/db/pg/clusters/template/pguser - targetNamespace: "pg" + targetNamespace: "authentik" + commonMetadata: + labels: *l + path: ./kube/deploy/apps/authentik/forward-auth dependsOn: - - name: 1-core-db-pg-clusters-home - - name: 1-core-secrets-es-k8s + - name: authentik-app postBuild: substitute: - PG_NAME: "home" - PG_DB_USER: &app "paperless-ngx" - PG_APP_NS: *app \ No newline at end of file + AUTHENTIK_PROXY_HOST: "${APP_DNS_PAPERLESS_NGX:=paperless-ngx}" diff --git a/kube/deploy/apps/paperless-ngx/kustomization.yaml b/kube/deploy/apps/paperless-ngx/kustomization.yaml index 5eeb2657..9b0abfee 100644 --- a/kube/deploy/apps/paperless-ngx/kustomization.yaml +++ b/kube/deploy/apps/paperless-ngx/kustomization.yaml @@ -1,6 +1,8 @@ --- apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization +namespace: paperless-ngx resources: - ns.yaml + - vars.yaml - ks.yaml diff --git a/kube/deploy/apps/paperless-ngx/ns.yaml b/kube/deploy/apps/paperless-ngx/ns.yaml index bfc5ba37..58a09840 100644 --- a/kube/deploy/apps/paperless-ngx/ns.yaml +++ b/kube/deploy/apps/paperless-ngx/ns.yaml @@ -3,3 +3,8 @@ apiVersion: v1 kind: Namespace metadata: name: paperless-ngx + labels: + kustomize.toolkit.fluxcd.io/prune: disabled + pod-security.kubernetes.io/enforce: &ps restricted + pod-security.kubernetes.io/audit: *ps + pod-security.kubernetes.io/warn: *ps diff --git a/kube/deploy/apps/paperless-ngx/vars.yaml b/kube/deploy/apps/paperless-ngx/vars.yaml new file mode 100644 index 00000000..e6efd4e9 --- /dev/null +++ b/kube/deploy/apps/paperless-ngx/vars.yaml @@ -0,0 +1,37 @@ +--- +# yaml-language-server: $schema=https://crds.jank.ing/external-secrets.io/externalsecret_v1.json +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: &name "${CLUSTER_NAME:=biohazard}-vars" + namespace: paperless-ngx +spec: + refreshInterval: 1m + secretStoreRef: + kind: ClusterSecretStore + name: 1p + dataFrom: + - extract: + key: ".${CLUSTER_NAME}-vars" + - extract: + key: "authentik vars - ${CLUSTER_NAME}" + - extract: + key: "paperless-ngx - ${CLUSTER_NAME}" + target: + creationPolicy: Owner + deletionPolicy: Retain + name: *name + template: + type: Opaque + data: + # Core cluster-wide vars + CLUSTER_NAME: "${CLUSTER_NAME:=biohazard}" + CONFIG_TZ: '{{ .CONFIG_TZ }}' + # App specific + APP_DNS_PAPERLESS_NGX: '{{ .APP_DNS_PAPERLESS_NGX }}' + # authentik hostAliases + APP_DNS_AUTHENTIK: '{{ .APP_DNS_AUTHENTIK }}' + APP_IP_AUTHENTIK: '{{ .APP_IP_AUTHENTIK }}' + # Other cluster-wide vars + IP_TRUENAS: '{{ .IP_TRUENAS }}' + PATH_NAS_PERSIST_K8S: '{{ .PATH_NAS_PERSIST_K8S }}'