homelab-codex-ws/hosts/piha/runtime/kb-postgres/docker-compose.override.yml
oskar 2b3cb89144 refactor(kb-postgres): relokacja SOLARIA→PIHA — arm64, mem_limit 1g, tuning pod małą maszynę
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:59:58 +02:00

103 lines
5.5 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PIHA-specific overrides for kb-postgres (KB spine).
#
# WHY PIHA: the KB store must answer queries 24/7. SOLARIA (GPU/compute) is
# powered down intermittently; PIHA (Raspberry Pi 5, always-on, mains power) is
# the right home for an always-available spine. Embeddings/models still run on
# SOLARIA's GPU — only the Postgres+pgvector store lives here.
#
# IMAGE / ARCH: pgvector/pgvector:pg16 is multi-arch and publishes a linux/arm64
# manifest, so it runs natively on the Pi 5 (arm64) — no emulation. We do NOT
# change the pg16 tag; arch is handled by the manifest list, not the tag.
#
# RESOURCE CONTEXT: PIHA has 8 GB RAM, but ~6 GB is already resident
# (Home Assistant, Immich, monitoring). Only ~2 GB is free (+4 GB swap). This is
# a RAM-bound box shared with Home Assistant — Postgres MUST NOT starve HA.
# Everything below is sized to keep kb-postgres's resident set near ~0.50.8 GB
# under normal load, with a hard 1 GB ceiling.
services:
kb-postgres:
# Hard cgroup ceiling. ~1 GB (not the 4 GB used on SOLARIA). If Postgres ever
# exceeds this, the cgroup OOM killer restarts the container via Docker —
# Postgres recovers cleanly via crash recovery — instead of letting the host
# OOM killer pick a victim (which could be Home Assistant). 1 GB comfortably
# covers the worst-case allocation below.
mem_limit: 1g
# Soft floor for the scheduler: reserve enough that shared_buffers (256 MB)
# plus connection/backend overhead is not constantly contended under memory
# pressure, without hard-pinning a full GB away from HA.
mem_reservation: 512m
# Postgres tuning for a tight, shared RAM budget. Passed as server args so we
# need no mounted postgresql.conf. Defaults (shared_buffers 128 MB, work_mem
# 4 MB, max_connections 100) assume a dedicated box — far too loose here.
#
# shared_buffers=256MB Postgres's own page cache. ~25% of the 1 GB
# ceiling — the standard rule of thumb. Bigger
# would crowd HA; smaller hurts cache hit rate
# for the envelope + pgvector working set.
# effective_cache_size=512MB Planner hint only (allocates nothing). Tells
# the planner how much OS+PG cache it can assume
# for this DB's share of the box, so it favours
# index scans appropriately. Conservative given
# the page cache is shared with HA/Immich.
# work_mem=8MB Per-sort/hash node. With max_connections=30 the
# worst case is bounded (~30 * a few nodes * 8MB);
# keeps a runaway analytic query from blowing the
# budget. Small enough for a Pi, big enough for
# typical KB lookups.
# maintenance_work_mem=64MB For VACUUM / CREATE INDEX (incl. building the
# pgvector ivfflat/hnsw index). One-at-a-time and
# transient, so a larger value than work_mem is
# safe and speeds index builds.
# max_connections=30 KB clients are a handful of agents/jobs, not a
# web fleet. Capping at 30 bounds per-backend RAM
# (each backend ~510 MB) and the work_mem blast
# radius. Raise only if a real client count needs it.
#
# Sanity check on the ceiling: 256 MB shared_buffers + ~30 backends * ~10 MB
# overhead (~300 MB) + bounded work_mem spikes stays well under mem_limit=1g.
command:
- "postgres"
- "-c"
- "shared_buffers=256MB"
- "-c"
- "effective_cache_size=512MB"
- "-c"
- "work_mem=8MB"
- "-c"
- "maintenance_work_mem=64MB"
- "-c"
- "max_connections=30"
# ---------------------------------------------------------------------------
# DATA PLACEMENT — must land on the NVMe (/home, ~170 GB free), NEVER the SD card.
#
# The base compose uses the Docker-managed named volume `kb_postgres_data`, which
# physically lives under Docker's data-root. On PIHA, Immich already stores its
# (large) photo library in Docker volumes here, which is only possible if the
# data-root sits on the NVMe — so the plain named volume should already land on
# NVMe and is the convention used by other PIHA services (e.g. vikunja).
#
# BEFORE FIRST DEPLOY, verify on PIHA:
# docker info -f '{{.DockerRootDir}}' # expect a path on the NVMe
# df -h "$(docker info -f '{{.DockerRootDir}}')" # confirm it's the NVMe fs
#
# If (and only if) the data-root is NOT on the NVMe, pin the volume explicitly to
# an NVMe path by uncommenting the block below. The official postgres entrypoint
# runs as root and chowns PGDATA to the in-container postgres user (uid 999) on
# startup, so PIHA's host-uid 1004-vs-1000 skew does not apply to PGDATA itself —
# but the bind *device* directory must pre-exist (Docker will not create it):
# sudo mkdir -p /home/oskar/homelab-data/kb-postgres
# sudo chown 1004:1004 /home/oskar/homelab-data/kb-postgres # host owner; PG re-chowns PGDATA to 999 inside
#
# volumes:
# kb_postgres_data:
# name: kb_postgres_data
# driver: local
# driver_opts:
# type: none
# o: bind
# device: /home/oskar/homelab-data/kb-postgres
# ---------------------------------------------------------------------------