Compare commits

...
Author SHA1 Message Date
issue-fix-bot ebb03e7063 fix: [alert] KubePodNotReady (paperless) (#896)
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
ci/woodpecker/pr/pr-review Pipeline was successful
2026-09-21 09:45:31 +00:00
+27 -1
View File
@@ -27,6 +27,24 @@ data:
PAPERLESS_ALLOWED_HOSTS: "*"
PAPERLESS_TIME_ZONE: "Europe/Berlin"
PAPERLESS_OCR_LANGUAGE: "deu+eng"
# OCR concurrency, pinned rather than derived. paperless hands
# THREADS_PER_WORKER to ocrmypdf as its job count, and the default is
# cpu_count() / TASK_WORKERS. The container has no CPU limit, so
# multiprocessing.cpu_count() reports the NODE's cores — 20 on k8s-1 —
# and OCR fans out to "Starting processing with 20 workers concurrently".
# Twenty pages of a 300dpi colour scan rasterised at once blew past
# limits.memory below and the kernel OOMKilled the container (exit 137)
# mid-consume. Because celery re-picks the same document on every restart,
# that is a crash loop and not a one-off: the pod OOMs ~37s in, before the
# webserver ever finishes booting, so it never goes Ready and the archive
# stays down.
#
# TASK_WORKERS is already effectively 1 (20 cores / 1 worker = the 20 jobs
# observed); pinning it keeps that explicit so THREADS_PER_WORKER stays the
# only knob, and neither value silently changes when this lands on a node
# with a different core count.
PAPERLESS_TASK_WORKERS: "1"
PAPERLESS_THREADS_PER_WORKER: "4"
PAPERLESS_CONSUMER_RECURSIVE: "true"
PAPERLESS_CONSUMER_DELETE_DUPLICATES: "true"
PAPERLESS_CONSUMER_ENABLE_BARCODES: "true"
@@ -273,7 +291,15 @@ spec:
cpu: 200m
memory: 512Mi
limits:
memory: 2Gi
# Headroom, not the fix — capping OCR jobs in paperless-config
# is. Sized from what a healthy pod actually uses: the last
# long-lived container held a steady ~1.0Gi working set, so 2Gi
# left barely 1Gi for an OCR burst. 3Gi keeps a 4-job burst
# clear of the ceiling. The crashlooping containers never showed
# this in cadvisor (~820Mi peak) because they lived 37s against
# a ~30s scrape interval — the spike fell between samples, so
# the OOMKilled status, not the metric, is the reliable signal.
memory: 3Gi
securityContext:
runAsNonRoot: false
allowPrivilegeEscalation: true