fix: auto-enable cgroup swap accounting on Pi before starting containers

runc (used by Podman) always writes memory.swap.max when initializing the
cgroup v2 memory controller, even without explicit --memory flags. On
Raspberry Pi OS this file is absent because swap accounting is disabled
by default in the kernel, causing every container start to fail with:

  openat2 …/memory.swap.max: no such file or directory

start.sh now detects this condition early, patches the kernel cmdline
(cgroup_enable=memory cgroup_memory=1 swapaccount=1) in either
/boot/firmware/cmdline.txt (Pi OS Bookworm) or /boot/cmdline.txt
(older releases), and tells the user to reboot once before continuing.

https://claude.ai/code/session_01FKCW3FDjNFj6jve4niMFXH
This commit is contained in:
Claude 2026-03-22 18:05:11 +00:00
parent 63a1ae6065
commit e7fd2a4365
No known key found for this signature in database

View file

@ -59,6 +59,51 @@ EOF
echo "[hiy] Generated proxy/caddy.json for ${DOMAIN_SUFFIX}" echo "[hiy] Generated proxy/caddy.json for ${DOMAIN_SUFFIX}"
# ── Ensure cgroup swap accounting is enabled (required by runc/Podman) ────────
# runc always writes memory.swap.max when the memory cgroup controller is
# present. On Raspberry Pi OS swap accounting is disabled by default, so that
# file simply does not exist and every container start fails with:
# "openat2 …/memory.swap.max: no such file or directory"
# Fix: add cgroup_memory=1 cgroup_enable=memory swapaccount=1 to the kernel
# boot cmdline and ask the user to reboot once.
_SWAP_OK=false
if [ -f /sys/fs/cgroup/memory.swap.max ] 2>/dev/null; then
_SWAP_OK=true
elif [ -d /sys/fs/cgroup/user.slice ] && \
ls /sys/fs/cgroup/user.slice/*/memory.swap.max 2>/dev/null | head -1 | grep -q .; then
_SWAP_OK=true
fi
if [ "$_SWAP_OK" = "false" ]; then
echo "[hiy] WARNING: cgroup swap accounting is not enabled."
# Detect the Pi boot cmdline file (Bookworm: /boot/firmware/cmdline.txt,
# older releases: /boot/cmdline.txt).
_CMDLINE=""
for _f in /boot/firmware/cmdline.txt /boot/cmdline.txt; do
[ -f "$_f" ] && { _CMDLINE="$_f"; break; }
done
if [ -n "$_CMDLINE" ]; then
_CURRENT=$(cat "$_CMDLINE")
_CHANGED=false
if ! echo "$_CURRENT" | grep -q "swapaccount=1"; then
_CURRENT="$_CURRENT cgroup_enable=memory cgroup_memory=1 swapaccount=1"
_CHANGED=true
fi
if [ "$_CHANGED" = "true" ]; then
echo "[hiy] Patching $_CMDLINE to enable swap accounting…"
echo "$_CURRENT" | sudo tee "$_CMDLINE" > /dev/null
echo "[hiy] *** REBOOT REQUIRED ***"
echo "[hiy] Run: sudo reboot"
echo "[hiy] Then re-run ./infra/start.sh"
exit 0
fi
else
echo "[hiy] Could not find /boot/cmdline.txt — add these to your kernel cmdline manually:"
echo "[hiy] cgroup_enable=memory cgroup_memory=1 swapaccount=1"
echo "[hiy] Then reboot and re-run this script."
exit 1
fi
fi
# ── Ensure newuidmap/newgidmap setuid binaries are present ──────────────────── # ── Ensure newuidmap/newgidmap setuid binaries are present ────────────────────
# These binaries (from the 'uidmap' package) allow rootless Podman to map a # These binaries (from the 'uidmap' package) allow rootless Podman to map a
# full range of UIDs/GIDs in user namespaces. Without them Podman can only # full range of UIDs/GIDs in user namespaces. Without them Podman can only