Skip to main content
3-node k3s cluster (v1.36.2+k3s1) on Debian, hostnames pentium / i3 / i5. The nodes share one LAN; flannel (k3s default CNI) rides it directly (no private mesh).

pentium — 192.168.1.16

k3s control-plane, tainted NoSchedule so no workloads land on it — a light bastion and the public door. Diskless for the cluster (no Longhorn disk, holds no persistent data). Runs cloudflared (the Cloudflare tunnel) and the Envoy Gateway managed proxy (hostNetwork :8890); the tolerating DaemonSets (beszel-agent, alloy) also land here. pocket-id/ntfy/bifrost are ordinary workloads and schedule on i3/i5.

i3 — 192.168.1.100

Worker, label kind=storage. Bears a Longhorn disk. Home of the working Intel iGPU (Haswell HD Graphics 4400, /dev/dri card0 + renderD128) that Jellyfin QuickSync uses, and the mail NodePort (k3s runs --disable servicelb, so there is no LoadBalancer controller). Hardware-bound pods pin here.

i5 — 192.168.1.10

Worker, label kind=compute. Bears a Longhorn disk and the better Intel iGPU (Comet Lake — HEVC 8/10-bit, VP9 QuickSync). Heavy execution: the agents (opencode + the workspace framework), Temporal, the in-cluster BuildKit builder, and durable jobs.

macbook — 192.168.1.35 (not a cluster node)

M1 MacBook Pro 13” (2020, 16GB), macOS 26. Lid open (propped, screen dark) on AC beside the fleet, Wi-Fi (DHCP reservation on MAC 3c:06:30:09:b0:06). Not a k3s node — there is no kubelet for darwin. It exists for macOS-only frameworks: the iMessage relay (imsg over SSH), Contacts, iOS/Xcode builds, and Apple Passwords. Lid-open is load-bearing: with no external display attached, closing it sleeps the machine, and no window server means no Accessibility. It also drives Apple Passwords unattended by Accessibility-driving Passwords.app — Apple ships no API (no dictionary, no CLI, no App Intents) and the items sit in Apple-only keychain groups, so security(1) and SecItemCopyMatching see ~1 internet password against the ~1000 in the app. AX covers the lot: the results outline enumerates the vault, File/Edit give create, edit, copy, delete. apw (reverse-engineered CLI) is retired — needed a domain per call so it could not enumerate, and could not delete at all (actDelete is in Apple’s bundled background.js with zero call sites; every ACT variant returns STATUS: 0 and deletes nothing). TCC Accessibility on /usr/libexec/sshd-keygen-wrapper, granted by hand (SIP blocks TCC.db writes even as root), is why SSH is the transport: a LaunchAgent in gui/$uid is its own TCC-responsible process, so osascript inside it hangs on a consent prompt nobody can answer and strands System Events at -609. Three locks — display-sleep, session, and the app’s own — all clear unattended via caffeinate -u plus the account password (SealedSecret here, since app-unlock gates delete and delete is what makes agent create safe); sysadminctl -screenLock off stops idle re-locking and pmset displaysleepnow keeps the panel dark. Detail in the mac-ax and apple-passwords skills. Reached as mac.peripherals.svc.cluster.local via a selector-less Service + hand-written EndpointSlice (cluster/apps/peripherals/mac/); the agent’s SSH key is a SealedSecret in the same leaf. Host-level state is out of git like the other nodes: FileVault off (auto-login is required for Messages to send, and the two are mutually exclusive), SIP on, pmset disablesleep re-asserted by /Library/LaunchDaemons/ai.augustin.nosleep.plist because it drifts, Charge Limit 80%, SSH key-only via /etc/ssh/sshd_config.d/010-hardening.conf. See ATM-259.

Storage — Longhorn

The workers (i3, i5) bear Longhorn disks; Longhorn owns all persistent volumes. Durability comes from replica count, not node locality. Two StorageClasses:
  • platform — 2 replicas across i3+i5, for service/DB state.
  • bulk — 1 replica, RWX-capable, for the large re-downloadable media library.
The media library was migrated off the old bare-metal mergerfs SanDisk pool onto a bulk RWX PVC. See networking and the storage section of AGENTS.md.

GPUs as schedulable resources

Intel iGPUs on i3+i5 are advertised as gpu.intel.com/i915 by the Intel GPU device-plugin DaemonSet (cluster/infra/intel-gpu/, shared-dev-num=3). Workloads request resources.limits.gpu.intel.com/i915: 1 rather than hard-mounting /dev/dri — Jellyfin now consumes the iGPU this way (the old hostPath /dev/dri pin is gone).