You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Found while sizing memory limits for #114, and it is the single largest thing
driving the number that issue has to pick for loki.
What happens
loki.source.docker in stacks/observability/alloy/docker.alloy is fed by discovery.docker "dockerlogs", which has no filter — it discovers every
container on the Docker socket, not just this stack's seven services. That
includes the short-lived containers docker run starts, and one of them writes
a gzip stream to stdout:
docker run --rm --network none --read-only ... "${TAR_IMAGE}" \
tar --numeric-owner -czf - -C /data . | age --recipient ... --output "${out}"
scripts/backup-volumes.sh:520. The tar output is the container's stdout, so
the json-file driver records it and Alloy streams it to Loki as log lines.
Measured
make backup on 2026-08-29 (backups/volumes/20260829T064124Z/) put three
archiver containers through Loki:
container
bytes ingested
goofy_perlman
269,627,560
fervent_lamport
269,305,584
relaxed_yonath
227,065,622
765 MB in about three minutes — sum(rate(loki_distributor_bytes_received_total[2m]))
peaked at 2.7 MiB/s against a baseline of 950 B/s. Sampling the stream back
out of Loki returns binary, as expected:
loki's working set went to 1039 MiB in that window against a 14-day p50 of
117 MiB; alloy reached 512 MiB and grafana 433 MiB at the same time. It is
not a one-off — the same shape, smaller, lands on the other backup timers:
589 MiB on 2026-09-04 (homelab-backup-firewall), 451 MiB on the homelab-verify-backups run before it.
Daily Loki ingest averages 249 MiB, so one make backup is roughly three
days of the estate's real logs, and it is retained as though it were logs.
The archives are encrypted at rest with age, deliberately — the comment in archive_one() says the plaintext never touches the disk. The compressed
plaintext does reach Loki, and loki-data is not encrypted. It is gzip, not
cleartext, but it is a copy of every volume's contents sitting somewhere the
backup design says it should not be.
Loki retention then evicts real logs earlier than it should.
Options
Filter discovery.docker to the stack — relabel on __meta_docker_container_label_com_docker_compose_project and drop what does
not carry it. Narrowest, and it also stops every other ad-hoc docker run
(the restoretest-*, offline-* and homelab-roundtrip-* containers CI
starts) being tailed.
Or give the archiver logging: driver: none in compose.yaml. Narrower
still, but it only fixes the container we happen to know about.
The first looks right; the second is worth doing anyway.
Done when
A make backup run adds no more than a few KB to Loki
loki's working set stays within its routine range across a backup
Found while sizing memory limits for #114, and it is the single largest thing
driving the number that issue has to pick for
loki.What happens
loki.source.dockerinstacks/observability/alloy/docker.alloyis fed bydiscovery.docker "dockerlogs", which has no filter — it discovers everycontainer on the Docker socket, not just this stack's seven services. That
includes the short-lived containers
docker runstarts, and one of them writesa gzip stream to stdout:
scripts/backup-volumes.sh:520. The tar output is the container's stdout, sothe json-file driver records it and Alloy streams it to Loki as log lines.
Measured
make backupon 2026-08-29 (backups/volumes/20260829T064124Z/) put threearchiver containers through Loki:
goofy_perlmanfervent_lamportrelaxed_yonath765 MB in about three minutes —
sum(rate(loki_distributor_bytes_received_total[2m]))peaked at 2.7 MiB/s against a baseline of 950 B/s. Sampling the stream back
out of Loki returns binary, as expected:
loki's working set went to 1039 MiB in that window against a 14-day p50 of117 MiB;
alloyreached 512 MiB andgrafana433 MiB at the same time. It isnot a one-off — the same shape, smaller, lands on the other backup timers:
589 MiB on 2026-09-04 (
homelab-backup-firewall), 451 MiB on thehomelab-verify-backupsrun before it.Daily Loki ingest averages 249 MiB, so one
make backupis roughly threedays of the estate's real logs, and it is retained as though it were logs.
Why it matters beyond the volume
mem_limitonlokiin Set memory limits on the six services to bound the blast radius of a leak #114 has to be 1536m rather than512m. Sizing a limit around a bug is the wrong shape, but the event is
scheduled and recurring, so the limit has to survive it until this is fixed.
age, deliberately — the comment inarchive_one()says the plaintext never touches the disk. The compressedplaintext does reach Loki, and
loki-datais not encrypted. It is gzip, notcleartext, but it is a copy of every volume's contents sitting somewhere the
backup design says it should not be.
Options
discovery.dockerto the stack — relabel on__meta_docker_container_label_com_docker_compose_projectand drop what doesnot carry it. Narrowest, and it also stops every other ad-hoc
docker run(the
restoretest-*,offline-*andhomelab-roundtrip-*containers CIstarts) being tailed.
logging: driver: noneincompose.yaml. Narrowerstill, but it only fixes the container we happen to know about.
The first looks right; the second is worth doing anyway.
Done when
make backuprun adds no more than a few KB to Lokiloki's working set stays within its routine range across a backupmem_limitonlokiis re-derived and lowered, with the commentsaying what it was sized from