Files
serverAppConfigs/dankclaw/compose.yaml
T
Frank 88dcd3cc0f ComfyUI: rootless-correct GPU group config (video only)
Rootless podman cannot map the 'render' gid (990) into the container
namespace (dank's subgid range is 100000+), so --group-add render fails to
start the container. GPU access actually comes from the /dev/kfd + /dev/dri
passthrough, checked host-side (the run user is already in 'render' on the
host). So add only the 'video' group (which resolves) and drop 'render'.

Update the group test to assert video present and render ABSENT (with the
rootless rationale), per the approved rootless config.
2026-08-19 15:50:28 -07:00

248 lines
7.4 KiB
YAML

# Dankclaw stack — AI, search, development & observability services.
# Deploy: cd /home/dank/serverAppConfigs && podman-compose -f dankclaw/compose.yaml up -d
# See ../docs/Dankclaw/ and ../docs/Infrastructure/ for service documentation.
services:
# --- SearXNG stack (gluetun + searxng + valkey) --------------------------
# These three services are now boot-persistent Quadlet units, not compose
# services. They live in searxng/quadlet/ and install to
# ~/.config/containers/systemd/ on the host. searxng reuses gluetun's netns
# (Network=gluetun.container) so its traffic exits the WireGuard tunnel.
# Deploy with: scripts/deploy-searxng-quadlet.sh dankclaw
# See ../docs/Dankclaw/SearXNG.md, Gluetun.md, Valkey.md.
# --- AI image generation (ROCm GPU backend, gfx1151) ---------------------
# Built from Containerfile.comfyui on AMD's gfx1151 torch base. The GPU is
# reached via the /dev/kfd + /dev/dri passthrough (checked host-side; the run
# user is already in the render group). Only the 'video' group is added:
# rootless podman cannot map the render gid into the container namespace.
# Models + data persist under /opt/comfyui. See ../docs/Dankclaw/ComfyUI.md.
comfyui:
build:
context: .
dockerfile: Containerfile.comfyui
image: comfyui-rocm:gfx1151
container_name: comfyui
restart: unless-stopped
command: ["python", "main.py", "--listen", "0.0.0.0", "--port", "8188"]
ports:
- "8188:8188"
devices:
- /dev/kfd:/dev/kfd
- /dev/dri:/dev/dri
group_add:
- video
volumes:
- /opt/comfyui/models:/opt/ComfyUI/models
- /opt/comfyui/input:/opt/ComfyUI/input
- /opt/comfyui/output:/opt/ComfyUI/output
- /opt/comfyui/custom_nodes:/opt/ComfyUI/custom_nodes
healthcheck:
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8188/')"]
interval: 30s
timeout: 10s
retries: 5
start_period: 180s
# --- Chat UI + agent -----------------------------------------------------
openwebui:
image: ghcr.io/open-webui/open-webui:main
container_name: openwebui
restart: unless-stopped
environment:
OPENAI_API_BASE_URL: "${OPENAI_API_BASE_URL}"
OPENAI_API_KEY: "${OPENAI_API_KEY}"
ports:
- "3000:8080"
volumes:
- /opt/openwebui/data:/app/backend/data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
hermes:
image: docker.io/nousresearch/hermes-agent:latest
container_name: hermes
restart: unless-stopped
environment:
HERMES_DATA_DIR: /data
ports:
- "8090:8090"
volumes:
- /opt/hermes/data:/data
healthcheck:
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8090/')"]
interval: 30s
timeout: 10s
retries: 3
# --- Git hosting (migrated from /opt/gitea) ------------------------------
postgres:
image: docker.io/library/postgres:16-alpine
container_name: gitea-postgres
restart: unless-stopped
environment:
POSTGRES_USER: gitea
POSTGRES_PASSWORD: "${GITEA_DB_PASSWORD}"
POSTGRES_DB: gitea
volumes:
- /opt/gitea/data/gitea-postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U gitea"]
interval: 30s
timeout: 10s
retries: 3
gitea:
image: docker.io/gitea/gitea:latest
container_name: gitea-server
restart: unless-stopped
environment:
DATABASE_TYPE: postgres
DATABASE_HOST: gitea-postgres
DATABASE_NAME: gitea
DATABASE_USER: gitea
DATABASE_PASSWD: "${GITEA_DB_PASSWORD}"
DATABASE_PORT: "5432"
USER_UID: "1000"
USER_GID: "1000"
ports:
- "3001:3000"
- "2222:22"
volumes:
- /opt/gitea/data/gitea-gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
depends_on:
- postgres
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/"]
interval: 30s
timeout: 10s
retries: 3
# --- Observability -------------------------------------------------------
prometheus:
image: docker.io/prom/prometheus:latest
container_name: prometheus
restart: unless-stopped
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.path=/prometheus
- --storage.tsdb.retention.time=30d
- --web.enable-lifecycle
ports:
- "9090:9090"
volumes:
- /opt/prometheus/config:/etc/prometheus
- /opt/prometheus/data:/prometheus
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:9090/-/healthy"]
interval: 30s
timeout: 10s
retries: 3
grafana:
image: docker.io/grafana/grafana:latest
container_name: grafana
restart: unless-stopped
environment:
GF_SERVER_ROOT_URL: "http://grafana.dankclaw.local"
GF_SECURITY_ADMIN_USER: "${GRAFANA_ADMIN_USER}"
GF_SECURITY_ADMIN_PASSWORD: "${GRAFANA_ADMIN_PASSWORD}"
ports:
- "3002:3000"
volumes:
- /opt/grafana/data:/var/lib/grafana
- /opt/grafana/provisioning:/etc/grafana/provisioning:ro
depends_on:
- prometheus
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
loki:
image: docker.io/grafana/loki:latest
container_name: loki
restart: unless-stopped
command: ["-config.file=/etc/loki/loki-config.yaml"]
ports:
- "3100:3100"
volumes:
- /opt/loki/config:/etc/loki
- /opt/loki/data:/loki
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3100/ready"]
interval: 30s
timeout: 10s
retries: 3
alloy:
image: docker.io/grafana/alloy:latest
container_name: alloy
restart: unless-stopped
volumes:
- /opt/alloy/config:/etc/alloy
- /run/systemd/journal/socket:/run/systemd/journal/socket:ro
- /var/log:/var/log:ro
- /var/lib/containers:/var/lib/containers:ro
depends_on:
- loki
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:12345/-/healthy"]
interval: 30s
timeout: 10s
retries: 3
node-exporter:
image: docker.io/prom/node-exporter:latest
container_name: node-exporter
restart: unless-stopped
network_mode: host
pid: host
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- --path.procfs=/host/proc
- --path.sysfs=/host/sys
- --path.rootfs=/rootfs
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:9100/metrics"]
interval: 30s
timeout: 10s
retries: 3
# --- Reverse proxy + homepage -------------------------------------------
caddy:
image: docker.io/library/caddy:latest
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- /opt/caddy/data:/data
- /opt/caddy/config:/config
- ../shared/homepage:/srv/homepage:ro
depends_on:
- searxng
- comfyui
- openwebui
- hermes
- gitea
- grafana
- prometheus
- loki
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:80/"]
interval: 30s
timeout: 10s
retries: 3