Compare commits

...
Author SHA1 Message Date
claude-botandClaude Opus 5 2d263113c4 feat(monitoring): alert on CrowdSec, starting with the failure that hides
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
Three rules, and the first one is firing right now for a real reason.

CrowdsecNotReadingLogs. Both agents are frozen at their line counts —
29,917 and 35,449 — with zero increase over an hour, while Traefik keeps
logging and Loki keeps ingesting. cs_bucket_poured_total has not moved in two
hours either: nothing is flowing into any scenario. CrowdSec has not detected
anything since 2026-08-27.

Nothing else shows it. Pods are Running, the LAPI answers, the bouncers pull
and enforce. The line counters are cumulative, so `cscli metrics` reports a
large number and reads as healthy; only the rate distinguishes "has read" from
"is reading". I made exactly that mistake earlier in the day: I checked the
cumulative figure, concluded the pipeline was working, and dismissed a wiki
note about the tailer not reattaching after a log rotation as stale. It was
not stale. And the absence of alerts since 08-27, which I read as a quiet
period, was the symptom.

CrowdsecEdgeBouncerNotPulling counts rather than names. The LAPI registers a
new bouncer per observed client address, and what it observes is the
netbird-ingress pod IP, so `edge@10.244.0.113` and its successors come and go
as those pods roll — a name-based rule would decay. `or vector(0)` is there
because without it the total-failure case is the one the alert misses: all
bouncers silent means the inner filter is empty, count() returns no series,
and nothing fires.

CrowdsecTargetDown is the ordinary one.

Both expressions were run against live data before being written down: the
bouncer count returns 2, and the acquisition rate returns 0 — which is how the
outage was found in the first place.

This does not fix the stalled tailer. Restarting the agents picks up the
current file, but the reattach behaviour is the actual bug and belongs in its
own change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 06:45:36 +02:00
k.renner 87cc238d33 Merge pull request 'fix(llama-server): one slot, so 16k belongs to one request' (#771) from llama-single-slot into master
ci/woodpecker/cron/issue-fix Pipeline was successful
ci/woodpecker/cron/alert-monitor Pipeline was successful
Reviewed-on: k.renner/homelab#771
2026-09-02 19:34:27 +00:00
claude-botandClaude Opus 5 353b7882d7 fix(llama-server): one slot, so 16k belongs to one request
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
Four Paperless requests overlapped and all four died:

    decode: failed to find free space in the KV cache
    srv decode: Context size has been exceeded.

They wanted 6209, 6472, 4303 and 1271 tokens from a shared pool of
16384. Auto slot count opens four of them and is also what enables
--kv-unified, so they draw on one buffer rather than a quarter each --
generous for a single caller, and impossible for four.

They overlapped because a client timeout does not stop the generation
behind it. The eval abandons a request after 300 s and moves to the next
document; the abandoned one keeps consuming the budget the next one
needs, and one slow document is enough to start the pile-up. With one
slot they queue instead, which is what should happen: nothing calls this
server in parallel on purpose, and Paperless's celery worker runs at
concurrency 1.

Deliberately no liveness probe alongside this. /health answered 200 in
0.4 ms throughout, which looks like the probe failing at its job -- but
the server drained the batch and served again by itself, so a probe that
restarted the pod would have turned a self-healing incident into an
outage. With a single slot, a probe asking for a real completion would
also queue behind live work and kill healthy pods mid-document.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 21:31:05 +02:00
k.renner 403a8e0e90 Merge pull request 'fix(llama-server): back to 16k — 32k per slot corrupts inference' (#770) from llama-ctx-revert into master
ci/woodpecker/cron/alert-monitor Pipeline was successful
Reviewed-on: k.renner/homelab#770
2026-09-02 19:06:25 +00:00
3 changed files with 104 additions and 4 deletions
+22 -4
View File
@@ -89,12 +89,30 @@ spec:
# against a generation that is read, not against a server that
# merely starts.
#
# Slots stay unset, which is also what keeps --kv-unified on
# (`llama-server --help`: enabled "if number of slots is auto"), so
# the four auto slots share one buffer and each may draw the full
# 16384 rather than a quarter of it.
- --ctx-size
- "16384"
# One slot, so the 16384 belongs to one request at a time.
#
# Left on auto, llama.cpp opens four slots and — because auto is
# also what enables --kv-unified — has them share a single buffer
# of this size. Four Paperless requests at once wanted 6209, 6472,
# 4303 and 1271 tokens against those 16384, and all four died with
# "Context size has been exceeded".
#
# They were concurrent because a client timeout does not stop the
# generation behind it: each abandoned request keeps consuming the
# shared budget the next one needs, so one slow document is enough
# to start the pile-up. Queueing is the behaviour worth having
# here — nothing calls this server in parallel on purpose, and
# Paperless's celery worker runs at concurrency 1.
#
# No liveness probe change goes with this. The server recovered on
# its own once the batch drained, so a probe that restarted the pod
# would have made the incident worse; with a single slot, one that
# asked for a real completion would also queue behind live work and
# kill healthy pods during a long document.
- --parallel
- "1"
# A micro-batch of 2048 or more makes this Vulkan/Mesa stack fail
# with ErrorDeviceLost.
- --ubatch-size
@@ -24,6 +24,7 @@ resources:
- alloy-servicemonitor.yaml
- cnpg-podmonitors.yaml
- crowdsec-servicemonitor.yaml
- prometheusrule-crowdsec.yaml
- home-assistant-servicemonitor.yaml
- immich-servicemonitor.yaml
- loki-servicemonitor.yaml
@@ -0,0 +1,81 @@
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: crowdsec
namespace: monitoring
labels:
# kube-prometheus-stack's Prometheus selects on this label.
release: kube-prometheus-stack
spec:
groups:
- name: crowdsec.rules
rules:
- alert: CrowdsecNotReadingLogs
# The failure that hides. Everything stays green — pods Running,
# LAPI answering, bouncers pulling, decisions being enforced — while
# the agents read nothing and therefore detect nothing. The counters
# are cumulative, so `cscli metrics` keeps showing a large number and
# looks healthy; only the rate tells the truth.
#
# This alert was written after finding exactly that state: both
# agents frozen at their line counts for hours while Traefik kept
# logging, and zero events poured into any scenario. It had been that
# way since 2026-08-27, and the only outward sign was an absence of
# alerts, which reads like quiet rather than blindness.
#
# Known cause per the wiki: the tailer does not reattach after the
# container log rotates.
expr: |
sum(rate(cs_filesource_hits_total[30m])) == 0
for: 30m
labels:
severity: critical
annotations:
summary: "CrowdSec liest seit 30min keine Logzeilen"
description: >-
Die Agents lesen nichts mehr, obwohl Traefik weiter loggt — es
wird also nichts erkannt. Prüfen: `cscli metrics` im Agent-Pod,
und ob die getailte Datei unter /var/log/containers noch dem
laufenden Traefik-Pod entspricht. Ein Neustart der Agents nimmt
die aktuelle Datei wieder auf.
- alert: CrowdsecEdgeBouncerNotPulling
# Both proxies must be fetching decisions. A bouncer that stops
# pulling keeps enforcing whatever it last held, and a bouncer whose
# process died enforces nothing at all — a clean shutdown deletes its
# nftables tables. Neither shows up anywhere else.
#
# Counted rather than named on purpose. The LAPI registers a new
# bouncer entry per observed client address, and what it observes is
# the netbird-ingress pod IP, so names like `edge@10.244.0.113` come
# and go as those pods roll. The count is stable; the names are not.
#
# `or vector(0)` matters: without it, all bouncers going silent makes
# the inner filter empty, count() returns no series, and the alert
# never fires — the total-failure case would be the one it misses.
expr: |
(count(sum by (bouncer) (rate(cs_lapi_bouncer_requests_total[15m])) > 0) or vector(0)) < 2
for: 15m
labels:
severity: critical
annotations:
summary: "Weniger als zwei CrowdSec-Bouncer holen Decisions ab"
description: >-
Erwartet werden proxy-1 und proxy-2. Holt einer nichts mehr ab,
setzt er einen veralteten Stand durch; ist sein Dienst beendet,
setzt er gar nichts mehr durch, weil ein sauberer Stop die
nftables-Tabellen löscht. Prüfen: `systemctl status
crowdsec-firewall-bouncer` auf beiden Hosts.
- alert: CrowdsecTargetDown
expr: |
up{namespace="crowdsec"} == 0
for: 10m
labels:
severity: warning
annotations:
summary: "CrowdSec-Scrape-Target {{ $labels.pod }} antwortet nicht"
description: >-
Ein LAPI- oder Agent-Pod ist nicht erreichbar. Für sich noch kein
Ausfall der Durchsetzung — die Bouncer behalten ihren letzten
Stand —, aber solange das anhält, kommen keine neuen Decisions an.