Skip to content

fix(compose): stop a crash filling the card with core dumps - #3418

Merged
vpetersson merged 1 commit into
masterfrom
agent/anthias-claude/core-dumps
Oct 24, 2026
Merged

vpetersson merged 1 commit into
masterfrom
agent/anthias-claude/core-dumps

Conversation

@vpetersson-bot

Copy link
Copy Markdown
Contributor

Issues Fixed

Fixes #3417.

Description

A process that crashes inside a container writes core.<pid> into its working directory. That is WORKDIR /usr/src/app: inside the container, on no mount, and reachable by no cleanup we have. The host's core_pattern is the kernel default core, a relative path, and core_uses_pid=1 means every crash adds a file rather than replacing one. ulimit -c is unlimited in a container by default, so nothing bounds it.

The result is invisible. docker images does not list it, and docker image prune cannot touch a live container's writable layer, so the space goes missing with nothing to account for it. A device in the field reached 24.2 GB of dumps in anthias-celery before its card filled: https://forums.screenly.io/t/sd-card-completely-full/6778

  • ulimits: core: 0 on every service in all three compose templates, written as one anchor aliased everywhere else so the rule cannot drift between services or between the Debian and balena deployments.
  • Tests asserting every service in every template resolves to core: 0. The real risk is a sixth service added later by someone who does not know this rule exists, so the test also checks the three templates agree on which services exist.

Changing the service definition also recreates the containers on the next upgrade, which discards the layer holding any dumps already accumulated. That is what repairs devices already affected.

Verification

Pi 4 testbed, Docker 29.6.1, containerd image store. Deployed through the real envsubst path rather than by hand editing the generated compose file.

Before, crashing Python three times inside anthias-celery:

-rw------- 1 root root 4861952 /usr/src/app/core.94
-rw------- 1 root root 4861952 /usr/src/app/core.101
-rw------- 1 root root 4861952 /usr/src/app/core.108

writable layer: 1.21MB -> 11.4MB

That size is what ties it to the field report: 4992 added paths under /usr/src/app there, and 4992 x 4861952 = 24.3 GB against the 24.2 GB observed.

After, with the patched template rendered and the stack brought up:

anthias-anthias-celery-1     ulimit -c = 0
anthias-anthias-server-1     ulimit -c = 0
anthias-anthias-viewer-1     ulimit -c = 0
anthias-redis-1              ulimit -c = 0

core files left by the previous run: 0   (the recreate cleaned them up)

Six crashes across celery and server then produced zero core files, and every writable layer stayed at its normal size (467kB / 1.21MB / 1.24MB / 4.1kB). Stack healthy afterwards: /api/v2/assets 200, celery 1 node online, viewer generating its asset list with both CEC adapters present. Testbed restored to baseline and its lock released.

Also confirmed the new test fails if a service loses the alias, rather than passing vacuously.

Tradeoff

This gives up core dumps on devices. Sentry already reports crashes, and nobody debugs a core file on a field SD card, so the dumps bought nothing while costing the card. docker-compose.dev.yml and docker-compose.test.yml are deliberately untouched: those run on workstations with room to spare, where a dump is actually useful.

Why the worker was crashing in the first place is a separate question and not addressed here. A crash should not cost the device its storage whatever the crash is.

Checklist

  • I have performed a self-review of my own code.
  • New and existing unit tests pass locally and on CI with my changes.
  • I have done an end-to-end test for Raspberry Pi devices.
  • I have tested my changes for x86 devices.
  • I added a documentation for the changes I have made (when necessary).

🤖 Generated with Claude Code

A process that crashes inside a container writes `core.<pid>` into its
working directory. That is `WORKDIR /usr/src/app`: inside the container,
on no mount, and reachable by no cleanup we have. The host's
`core_pattern` is the kernel default `core`, a relative path, and
`core_uses_pid=1` means every crash adds a file rather than replacing
one. `ulimit -c` is `unlimited` in a container by default, so nothing
bounds it.

The result is invisible: `docker images` does not list it and `docker
image prune` cannot touch a live container's writable layer, so the
space goes missing with nothing to account for it. A device in the field
reached 24.2 GB of dumps in anthias-celery before its card filled.

- Set `ulimits: core: 0` on every service in all three compose
  templates, as one anchor aliased everywhere so the rule cannot drift
  between services or between deployments.
- Add tests asserting every service in every template resolves to
  `core: 0`, since the real risk is a sixth service added later by
  someone who does not know this rule exists.

Changing the service definition also recreates the containers on the
next upgrade, which discards the layer holding any dumps already there.

Measured on a Pi 4: before, three crashes left three files of 4,861,952
bytes each and grew the layer from 1.21 MB to 11.4 MB. After, six
crashes across celery and server left none, and the worker stayed
healthy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
@vpetersson-bot
vpetersson-bot requested a review from a team as a code owner October 24, 2026 18:16
Copilot AI lite review requested due to automatic review settings October 24, 2026 18:16
@vpetersson-bot vpetersson-bot self-assigned this Oct 24, 2026

Copilot AI 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.

Copilot encountered an error: Your billing is not configured or you have Copilot licenses from multiple standalone organizations or enterprises. To use premium requests, select a billing entity via the GitHub site, under Settings > Copilot > Features.

@vpetersson-bot
vpetersson-bot requested a lite review from Copilot October 24, 2026 18:16

Copilot AI 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.

Copilot encountered an error: Your billing is not configured or you have Copilot licenses from multiple standalone organizations or enterprises. To use premium requests, select a billing entity via the GitHub site, under Settings > Copilot > Features.

@sonarqubecloud

Copy link
Copy Markdown

@vpetersson
vpetersson merged commit d5f1410 into master Oct 24, 2026
9 checks passed
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.

A crash inside a container fills the card: core dumps accumulate in the container's writable layer

3 participants