Skip to content

fix(nautobot): enable prometheus multiprocess mode in the image - #181

Open
dmathur0 wants to merge 3 commits into
mainfrom
davesh/nautobot-prometheus-multiproc
Open

fix(nautobot): enable prometheus multiprocess mode in the image#181
dmathur0 wants to merge 3 commits into
mainfrom
davesh/nautobot-prometheus-multiproc

Conversation

@dmathur0

@dmathur0 dmathur0 commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

Enable prometheus_client multiprocess mode for Nautobot by baking
prometheus_multiproc_dir=/prom_cache into the image — exactly how the stock
Nautobot image does it. This makes the /metrics self-deadlock structurally
impossible
(not just mitigated) and produces metrics aggregated across all
uWSGI workers instead of whichever single worker answers the scrape.

Multiprocess mode brings one liability with it: prometheus_client keys its
metric files by PID and never reaps them, so /prom_cache grows for as long as
a pod lives. This PR also bounds that directory and stops the celery probes
from feeding it, so the mode is enabled and contained in a single change.

Supersedes the mitigation in #174, whose uwsgi.ini preload is removed here as
part of the same change.

No new Helm values or knobs.

Root cause (condensed)

The web server runs multiple uWSGI workers. With no PROMETHEUS_MULTIPROC_DIR,
prometheus_client uses the global in-process registry created with
auto_describe=True:

  1. A scrape calls REGISTRY.register(NautobotAppMetricsCollector()).
  2. The collector has no describe(), so with auto_describe=True, register()
    calls collect() while holding the non-reentrant REGISTRY._lock.
  3. collect() touches Django's cache → lazily imports
    django_prometheus.cache.backends.redisdjango_prometheus.cache.metrics,
    which instantiates Counter()s at import time, each re-acquiring the lock
    the same thread already holds
    → self-deadlock.

Setting prometheus_multiproc_dir switches every worker to a fresh
CollectorRegistry(auto_describe=False), so register() never calls collect()
under the lock. Full reproduction/proof is in #174.

Environments that already use the stock Nautobot image never hit this because
that image bakes prometheus_multiproc_dir=/prom_cache; our custom distroless
image did not. This change brings our image in line.

The liability that comes with multiprocess mode

prometheus_client writes one set of *.db files per PID and only reaps
live-gauge files — counters and histograms are cumulative, so deleting them
would make metrics go backwards. Anything that spawns short-lived
nautobot-server processes therefore leaves orphans behind permanently, and
every /metrics scrape has to read the whole directory.

This is not theoretical. A sibling deployment that has run in multiprocess mode
all along accumulated 49,636 files (778 MB) in /prom_cache after 22 days,
at which point concurrent scrapes became GIL-bound on file I/O and timed out. A
uwsgi --connect-and-read tracebacker dump on that live pod showed every worker
thread parked in prometheus_client/mmap_dict.py:read_all_values_from_file. It
presents like a deadlock but is a throughput collapse — no lock involved. Its
cause was an exec: nautobot-server health_check liveness probe forking a new
PID every 120s.

Change

build/nautobot.Dockerfile

  • ENV prometheus_multiproc_dir=/prom_cache (+ upper-case PROMETHEUS_MULTIPROC_DIR
    alias for cross-version compatibility).
  • Create /prom_cache in the builder stage and COPY --chown=1000:1000 it into
    the runtime image (the distroless runtime has no shell, so it can't mkdir at
    build time; this mirrors the existing media/.cache dirs and makes it
    writable by the runtime uid). prometheus_client requires the dir to exist.

deploy/helm/templates/_nautobot-configmap-data.tpl

  • Remove import = django_prometheus.cache.metrics. With multiprocess mode on,
    the /metrics handler builds a per-request CollectorRegistry();
    CollectorRegistry defaults to auto_describe=False, and register() only
    substitutes collector.collect() for a missing describe() when
    auto_describe is set. collect() is therefore never invoked while the
    registry lock is held, the lazy django_prometheus.cache.metrics import can no
    longer re-enter it, and the preload is dead weight. The template is now
    byte-identical to its pre-fix(nautobot): prevent uWSGI /metrics self-deadlock and fix scrape path #174 content.

deploy/helm/templates/nautobot.yaml

  • /prom_cache becomes an emptyDir with a 256Mi sizeLimit on the web and
    celery pods. The image still creates the directory; the volume only adds
    lifecycle management — it starts empty on every pod start and cannot grow
    without bound. Steady state is a handful of files per uWSGI worker (tens of
    KB each), so the limit is a regression signal, not something normal operation
    approaches. fsGroup: 1000 is already set on these pods and the image chowns
    the directory to 1000:1000, so the mount is writable.
  • The celery liveness/readiness probes drop $prometheus_multiproc_dir and
    $PROMETHEUS_MULTIPROC_DIR from the environment
    of the nautobot-server
    process they fork. A celery worker has no HTTP listener, so these probes can't
    become httpGet the way the web pod's already are. Without the variable the
    forked process keeps prometheus_client in single-process mode and writes no
    files at all. celery inspect ping never touches /metrics, so nothing is
    lost.

The env is image-wide (matching the stock Nautobot image), so it applies to the
web server as well as celery/beat — consistent with the stock image's behavior.

Validation

  • Confirmed against the pinned Nautobot 2.4.36 that NautobotMetricsView.get()
    selects CollectorRegistry() + MultiProcessCollector when either env spelling
    is present (nautobot/core/views/__init__.py:489-501), and against
    prometheus_client/registry.py that CollectorRegistry.__init__ defaults to
    auto_describe=False and _get_names() only falls back to collector.collect
    when _auto_describe is truthy. That is what makes the preload removal safe.

  • helm template ... --values values-ci.yaml renders; the emitted uwsgi.ini
    contains no import directive and is otherwise unchanged. Also renders clean
    with values-observability.yaml layered, and helm lint passes (only the
    pre-existing temporal name-length warnings).

  • Audited every rendered Nautobot pod for probe handler and mount:

    test-nv-config-manager-nautobot / nautobot
        startup/liveness/readiness = httpGet /health/:http
        /prom_cache -> emptyDir sizeLimit 256Mi
    test-nv-config-manager-nautobot-celery / celery
        liveness/readiness = exec, strips prom env before forking
        /prom_cache -> emptyDir sizeLimit 256Mi
    test-nv-config-manager-nautobot-celery-beat / celery-beat
        liveness = exec, file-mtime check (never forks nautobot-server)
    

    Re-rendered with nautobot.customJobs.enabled=true to cover the restructured
    celery volumes/volumeMounts blocks, which were previously wrapped entirely
    in that conditional; both prom-cache and custom-jobs appear.

  • Executed the new probe one-liner with both env spellings set and confirmed the
    forked child sees neither, still sees HOSTNAME, and that the exit code
    propagates (so probe semantics are unchanged).

  • Checked the runtime image is actually able to use the directory: the distroless
    base runs as nvs = uid/gid 1000 (matching the --chown), and the chart's
    container security context does not set readOnlyRootFilesystem, so
    /prom_cache is writable.

  • Diffed our image against the upstream nautobot:2.4.36 final stage: its
    complete production ENV set is PYTHONUNBUFFERED, NAUTOBOT_ROOT and
    prometheus_multiproc_dir, so this was the only missing environment
    variable. Everything else stock provides is either already covered
    (docker-entrypoint.sh's post_upgrade/superuser work is done by
    migration_runner.py; uwsgi.ini comes from the chart ConfigMap;
    /etc/mime.types is already in the distroless base;
    INSTALLATION_METRICS_ENABLED=False is set in nautobot_config.py) or
    deliberately unused (self-signed certs + https/8443, libmariadb3,
    libxmlsec1).

Notes

  • No metrics.multiproc.* values / toggle (removed from an earlier revision of
    this PR at review request — matches the stock image exactly).
  • Takes effect on image rebuild + rollout.
  • The web pod needed no probe change: its startup/liveness/readiness probes are
    already httpGet /health/ (fix(helm): use /health endpoint for nautobot readiness #173), served by the existing uWSGI workers, so it
    creates no new PIDs. Before that fix it would have been the worst offender —
    readiness every 10s plus liveness every 120s.
  • Celery beat is deliberately left alone. Its probe is a /tmp file-mtime
    check that never forks nautobot-server, and the beat process itself is a
    single long-lived PID, so nothing accumulates.
  • Not fully eliminated, and not worth further machinery: a uWSGI worker that is
    respawned (harakiri, OOM, crash) gets a new PID and orphans its predecessor's
    files for the life of the pod. harakiri is 1210s and none of
    max-requests / max-worker-lifetime / reload-on-rss / cheaper are set,
    so worker churn is rare, and the emptyDir caps the worst case regardless.

Summary by CodeRabbit

  • Bug Fixes

    • Improved Nautobot Prometheus metrics reliability by aggregating metrics across all web workers.
    • Fixed recurring /metrics/ 404 errors for NVIDIA Config Manager monitoring.
    • Prevented Celery health checks from generating unnecessary metrics artifacts.
  • Operations

    • Added dedicated, ephemeral metrics storage with a 256 MiB limit.
    • Metrics storage resets when a pod restarts, preventing unbounded growth.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Nautobot’s image and Helm workloads now provide shared, size-limited Prometheus multiprocess storage. Both Prometheus environment-variable forms point to /prom_cache, the uWSGI preload import is removed, and Celery probes avoid creating metric files.

Changes

Prometheus multiprocess metrics

Layer / File(s) Summary
Image metrics storage wiring
build/nautobot.Dockerfile
Creates /prom_cache, configures both Prometheus multiprocess environment variables, and copies the directory into the runtime image with explicit ownership.
Workload metrics volume wiring
deploy/helm/templates/nautobot.yaml
Mounts a 256Mi prom-cache emptyDir in Nautobot and Celery pods, and removes Prometheus multiprocess variables from the Celery liveness probe environment.
uWSGI metrics configuration
deploy/helm/templates/_nautobot-configmap-data.tpl, CHANGELOG.md
Removes the django_prometheus.cache.metrics preload import and documents aggregated scraping through /metrics/.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Helm
  participant NautobotPod
  participant Prometheus
  participant CeleryProbe
  Helm->>NautobotPod: Mount 256Mi /prom_cache emptyDir
  NautobotPod->>NautobotPod: Aggregate worker metrics from /prom_cache
  Prometheus->>NautobotPod: Scrape /metrics/
  NautobotPod->>Prometheus: Return aggregated metrics
  CeleryProbe->>NautobotPod: Unset multiprocess variables and run celery inspect ping
Loading

Suggested reviewers: zsblevins, jojung1, polarweasel

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: enabling Prometheus multiprocess mode in the Nautobot image.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch davesh/nautobot-prometheus-multiproc

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@deploy/helm/templates/_nautobot-configmap-data.tpl`:
- Around line 197-199: The _install_metric_reaper hook must also bound the
multiprocess metrics directory during worker shutdown, not only mark the current
process dead. Update the cleanup behavior in
deploy/helm/templates/_nautobot-configmap-data.tpl:197-199 to remove stale
counter, summary, and histogram files while preserving live-gauge reaping;
deploy/helm/values.yaml:2771-2773 and
deploy/helm/templates/nautobot.yaml:792-798 require no direct changes and are
affected configuration/context sites.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7cc822f9-fd8f-489d-b1c3-6a4196c70c2a

📥 Commits

Reviewing files that changed from the base of the PR and between 5f3ee8d and 2652806.

📒 Files selected for processing (3)
  • deploy/helm/templates/_nautobot-configmap-data.tpl
  • deploy/helm/templates/nautobot.yaml
  • deploy/helm/values.yaml

Comment on lines +197 to +199
@uwsgidecorators.postfork
def _install_metric_reaper() -> None:
atexit.register(lambda: multiprocess.mark_process_dead(os.getpid()))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

helm template multiproc-on deploy/helm \
  -f deploy/helm/values-ci.yaml \
  --set nautobot.enabled=true \
  --set nautobot.metrics.multiproc.enabled=true >/tmp/multiproc-on.yaml

helm template multiproc-off deploy/helm \
  -f deploy/helm/values-ci.yaml \
  --set nautobot.enabled=true \
  --set nautobot.metrics.multiproc.enabled=false >/tmp/multiproc-off.yaml

rg -n -C2 'metrics_bootstrap|PROMETHEUS_MULTIPROC_DIR|prometheus-multiproc' \
  /tmp/multiproc-on.yaml /tmp/multiproc-off.yaml

Repository: NVIDIA/nv-config-manager

Length of output: 204


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## _nautobot-configmap-data.tpl\n'
sed -n '180,220p' deploy/helm/templates/_nautobot-configmap-data.tpl | cat -n

printf '\n## values.yaml\n'
sed -n '2758,2785p' deploy/helm/values.yaml | cat -n

printf '\n## nautobot.yaml\n'
sed -n '780,810p' deploy/helm/templates/nautobot.yaml | cat -n

printf '\n## search for multiprocess cleanup/config\n'
rg -n 'mark_process_dead|PROMETHEUS_MULTIPROC_DIR|multiproc|startup-clear|worker reaping' deploy/helm -S

Repository: NVIDIA/nv-config-manager

Length of output: 8338


🌐 Web query:

prometheus_client multiprocess.mark_process_dead removes only gauge_live files counters histograms cleanup semantics

💡 Result:

The function prometheus_client.multiprocess.mark_process_dead specifically targets and removes only the memory-mapped database files associated with Gauges configured with "live" multiprocess modes (e.g., livesum, liveall, livemin, livemax, livemostrecent) for a given process ID [1][2][3]. It does not remove files for other metric types such as Counters, Summaries, or Histograms, nor does it remove files for non-live Gauges [1][4][5]. The rationale for this behavior is that "live" Gauges represent transient state—such as active connections or current queue depth—that becomes stale once the process that generated those metrics exits [1][4][6]. Removing these files prevents stale values from contributing to aggregated metrics [1]. Conversely, other metric types (like Counters or Histograms) track cumulative data, where the final value recorded by a process remains meaningful even after the process has terminated [1][4]. These non-live metric files are intended to persist until the entire multiprocess directory is cleared, which is typically handled by the user or process manager upon application restart or deployment [1][4][6].

Citations:


🌐 Web query:

prometheus_client multiprocess.mark_process_dead only removes gauge_live files documentation source

💡 Result:

The prometheus_client library function mark_process_dead is designed specifically to manage multiprocess gauge files and does not clean up metrics for other types [1][2]. As documented in the official Prometheus client_python documentation, mark_process_dead only removes files corresponding to live gauge modes (such as livesum or liveall) for a given process ID [1][3]. These files are created to ensure that metrics reflecting the current state of living processes do not accumulate stale data after a process exits [1][4]. Files for other metric types (such as Counter, Summary, or Histogram) or non-live Gauge modes are intentionally left in place by mark_process_dead [1][5]. These non-live metrics are designed to persist their last values until the directory is cleared, typically upon application or worker restart [1][5]. The accumulation of these other files is expected behavior in the current design of the multiprocess collector, as they track cumulative data that remains relevant even if a specific process has terminated [1][6].

Citations:


🌐 Web query:

site:github.com prometheus_client multiprocess.py mark_process_dead gauge_live remove files

💡 Result:

In the prometheus_client Python library, the function mark_process_dead(pid, path=None) is specifically designed to perform cleanup for multiprocess applications [1][2]. It operates by removing only the temporary.db files associated with "live" Gauge metrics for a given process ID (PID) [1][2]. These "live" gauge modes (e.g., liveall, livesum, livemin, livemax, livemostrecent) are designed to reflect the state of currently living processes only; therefore, removing their files upon process termination prevents stale data from being included in aggregate calculations [2][3][4]. Key technical details regarding this mechanism include: 1. Scope of Cleanup: The function does not remove files for other metric types, such as Counters, Summaries, or Histograms [5][3]. Deleting those files would lead to the loss of accumulated data, causing metrics to incorrectly reset or go backwards [5]. 2. Usage: It is standard practice to call this function from a process manager's child exit hook (e.g., in Gunicorn) to manage the lifecycle of "live" gauge metrics [2][3]. 3. Persistent Files: Files for non-live metrics remain on disk even after a process dies [2][4]. The library expects the multiprocess directory to be wiped entirely when the application (or server) is restarted to ensure a clean state [2][6][4]. 4. Path Handling: The function looks for the directory defined by the PROMETHEUS_MULTIPROC_DIR environment variable (or the older prometheus_multiproc_dir) [1][7][8]. If the path is not provided as an argument, it automatically detects this variable to locate the files [2][9]. Because mark_process_dead does not perform a full cleanup of all metric types, environments with high process churn (such as frequently rotating workers) may see a accumulation of files over time, which is a known limitation that typically requires a manual cleanup strategy during service restarts or deployments [3][6][4].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## multiproc bootstrap context\n'
sed -n '120,170p' deploy/helm/templates/_nautobot-configmap-data.tpl | cat -n

printf '\n## Prometheus metric definitions in repo\n'
rg -n 'from prometheus_client import|prometheus_client\.(Counter|Histogram|Summary|Gauge)|Gauge\(' . -S

Repository: NVIDIA/nv-config-manager

Length of output: 3909


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '170,220p' deploy/helm/templates/_nautobot-configmap-data.tpl | cat -n

Repository: NVIDIA/nv-config-manager

Length of output: 2267


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '170,210p' deploy/helm/templates/_nautobot-configmap-data.tpl | cat -n

Repository: NVIDIA/nv-config-manager

Length of output: 1663


mark_process_dead() doesn’t bound the multiprocess directory. Startup clears old *.db files, but this hook only reaps live-gauge files; counter/summary/histogram files can still accumulate across worker churn until the next pod restart. The 64Mi emptyDir cap is still the only backstop during a long-lived pod.

📍 Affects 3 files
  • deploy/helm/templates/_nautobot-configmap-data.tpl#L197-L199 (this comment)
  • deploy/helm/values.yaml#L2771-L2773
  • deploy/helm/templates/nautobot.yaml#L792-L798
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/helm/templates/_nautobot-configmap-data.tpl` around lines 197 - 199,
The _install_metric_reaper hook must also bound the multiprocess metrics
directory during worker shutdown, not only mark the current process dead. Update
the cleanup behavior in
deploy/helm/templates/_nautobot-configmap-data.tpl:197-199 to remove stale
counter, summary, and histogram files while preserving live-gauge reaping;
deploy/helm/values.yaml:2771-2773 and
deploy/helm/templates/nautobot.yaml:792-798 require no direct changes and are
affected configuration/context sites.

Source: Coding guidelines

@dmathur0
dmathur0 force-pushed the davesh/nautobot-prometheus-multiproc branch 2 times, most recently from 00091b7 to 32a039a Compare July 24, 2026 20:14

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@build/nautobot.Dockerfile`:
- Around line 84-92: Update the Prometheus environment-variable comment in the
Dockerfile to state that these variables only enable multiprocess mode and
configure the shared metrics directory; clarify that the /metrics handler must
still create an isolated CollectorRegistry and register MultiProcessCollector.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 1d4316bd-b2ba-4845-bc26-2b9ae80f60f6

📥 Commits

Reviewing files that changed from the base of the PR and between 00091b7 and 32a039a.

📒 Files selected for processing (1)
  • build/nautobot.Dockerfile

Comment thread build/nautobot.Dockerfile Outdated
@dmathur0 dmathur0 changed the title fix(nautobot): serve /metrics via prometheus multiprocess mode fix(nautobot): enable prometheus multiprocess mode in the image Jul 24, 2026
The Nautobot web server runs multiple uWSGI workers. Without
PROMETHEUS_MULTIPROC_DIR set, prometheus_client uses the global in-process
registry (auto_describe=True), where the first /metrics scrape self-deadlocks:
the collector registers while holding Prometheus's non-reentrant registry lock,
then touches Django's cache, which lazily imports django_prometheus.cache.metrics
and re-acquires the same lock. (PR #174 mitigated this via a uwsgi preload.)

Match the stock Nautobot image (which bakes prometheus_multiproc_dir) instead of
adding Helm knobs: set prometheus_multiproc_dir=/prom_cache (+ upper-case alias)
in the image and create the dir (writable by uid 1000, via the builder + COPY,
since the distroless runtime has no shell). Every Nautobot worker then uses a
fresh CollectorRegistry(auto_describe=False): the /metrics self-deadlock becomes
structurally impossible and per-worker metrics aggregate correctly.

Signed-off-by: Davesh Mathur <daveshm@nvidia.com>
@dmathur0
dmathur0 force-pushed the davesh/nautobot-prometheus-multiproc branch from 32a039a to 19059c0 Compare July 25, 2026 05:41
With prometheus_multiproc_dir baked into the image, Nautobot's /metrics
handler builds a per-request CollectorRegistry() instead of using the
global REGISTRY. CollectorRegistry defaults to auto_describe=False, and
register() only substitutes collector.collect() for a missing describe()
when auto_describe is set, so collect() is never invoked while the
registry lock is held. The lazy django_prometheus.cache.metrics import
therefore can no longer re-enter that lock, which makes the uwsgi.ini
preload added in #174 dead weight.

Verified against nautobot 2.4.36 (core/views/__init__.py:489-501) and
prometheus_client registry.py (__init__ default, _get_names line 66).

Signed-off-by: Davesh Mathur <daveshm@nvidia.com>
Comment thread build/nautobot.Dockerfile
# global REGISTRY, and metrics aggregate across all uWSGI workers. Nautobot accepts
# either spelling; the stock Nautobot image bakes the lower-case one, so both are set.
ENV prometheus_multiproc_dir=/prom_cache
ENV PROMETHEUS_MULTIPROC_DIR=/prom_cache

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will enable MP mode for every process using this image (including liveness probes that run nautobot-server every few minutes) - is that intended? if so we might need to check how many files this will generate and if it could exchaust container resources

Enabling multiprocess mode makes prometheus_client write one set of *.db
files per PID under /prom_cache, and it only reaps live-gauge files -- so
the directory grows for as long as a pod lives and every /metrics scrape
has to read all of it.  Cerebro, which has run in multiprocess mode all
along, reached 49,636 files (778 MB) after 22 days and its scrapes started
timing out.

Two changes keep that from happening here:

- /prom_cache is now an emptyDir with a 256Mi limit on the web and celery
  pods, so it starts empty on every pod start and cannot grow unbounded.
  The image still creates the directory; the volume only adds lifecycle.

- The celery probes drop $prometheus_multiproc_dir from the environment of
  the nautobot-server process they fork.  Celery has no HTTP listener, so
  these probes cannot become httpGet the way the web pod's already are;
  without the variable the forked process keeps prometheus_client in
  single-process mode and writes no files at all.  `celery inspect ping`
  never touches /metrics, so no metrics are lost.

Celery beat is left alone: its probe is a file-mtime check that never
forks nautobot-server, so nothing accumulates there.

Signed-off-by: Davesh Mathur <daveshm@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants