Closing the command-center security queue #70/#71/#72/#73/#74: rolling tags let a rebuild move under a running service with nobody approving it, and make a CVE audit ungradeable. 36 quadlet units across dankclaw, dankserver and frankbook-pro now carry tag@sha256; localhost/* builds stay exempt (their build is the pin). The pihole and copyparty pins pull the fixed builds; valkey 9.1.2 (already running) and redis 7.4.11 are pinned in place, vendor fixes TBD. New gate tests/quadlet_image_pins.bats: no unpinned registry image, no generator-rejected key anywhere. Three seams that pinned the old exact-tag law (frankbook readarr, open_webui, seerr) now require tag AND digest - strictly stronger. Quadlet Lifecycle docs: batch-abort law, entrypoint flags-only law, pin law.
57 lines
2.4 KiB
INI
57 lines
2.4 KiB
INI
# Quadlet unit: cadvisor (rootless, boot-persistent) — DANKCLAW.
|
|
#
|
|
# Install path on dankclaw: ~/.config/containers/systemd/cadvisor.container
|
|
# Unit name: cadvisor.service (container name: cadvisor)
|
|
#
|
|
# WHY THIS EXISTS. The app stack is ~34 rootless Podman containers and until
|
|
# now nothing reported per-container CPU/memory — Grafana could only see the
|
|
# host (node_exporter) and the LLM engines. cadvisor reads the host cgroup
|
|
# tree and exports container_cpu_* / container_memory_* per container.
|
|
#
|
|
# THE LOAD-BEARING FLAG IS --cgroupns=host. Podman starts every container in a
|
|
# PRIVATE cgroup namespace, so an exporter container sees only its OWN cgroup
|
|
# subtree: cadvisor exported a single root series until this flag was added,
|
|
# then it walked the whole tree (996 per-container series measured 2026-10-20).
|
|
# The quadlet unit name is carried in the cgroup path — app.slice/<name>.service/
|
|
# libpod-payload-<hex> — so Prometheus relabels that path into a `container`
|
|
# label (shared/prometheus/prometheus.yml, cadvisor-dankclaw job) and no
|
|
# libpod/podman socket is needed to name containers.
|
|
#
|
|
# BINDING. cadvisor has no per-interface listen flag (unlike node_exporter's
|
|
# --web.listen-address), so it binds 0.0.0.0 INSIDE its own network namespace.
|
|
# The bridge PublishPort is what keeps the unauthenticated endpoint off the
|
|
# host's other interfaces: it publishes exactly loopback (host-local probes and
|
|
# the deployer's health gate) and this host's LAN address (Prometheus, a bridge
|
|
# container, reaches a host-published port at its LAN address — the same netavark
|
|
# rule node-exporter relies on, only here the port really is published).
|
|
#
|
|
# It is rootless on purpose: dank owns the app containers' cgroups, so a
|
|
# rootless cadvisor reads every one of them; root would buy nothing here.
|
|
|
|
[Unit]
|
|
Description=cAdvisor container metrics (Dankclaw)
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Container]
|
|
ContainerName=cadvisor
|
|
Image=gcr.io/cadvisor/cadvisor:v0.49.1@sha256:3cde6faf0791ebf7b41d6f8ae7145466fed712ea6f252c935294d2608b1af388
|
|
PodmanArgs=--pid=host --cgroupns=host
|
|
PublishPort=127.0.0.1:8080:8080
|
|
PublishPort=192.168.0.143:8080:8080
|
|
Volume=/sys:/sys:ro
|
|
Volume=/:/rootfs:ro
|
|
Exec=--housekeeping_interval=30s
|
|
HealthCmd=wget --spider -q http://localhost:8080/healthz
|
|
HealthInterval=30s
|
|
HealthTimeout=10s
|
|
HealthRetries=3
|
|
HealthStartPeriod=40s
|
|
|
|
[Service]
|
|
Restart=always
|
|
RestartSec=10
|
|
|
|
[Install]
|
|
WantedBy=default.target
|