Files
serverAppConfigs/serverAppConfigs-docs/Dankclaw/ComfyUI.md
T
Frank 06d3502a2b docs: ComfyUI is a unit now, and three scrape jobs can never be green
ComfyUI's page described a compose service and a systemd unit that shelled out
to `podman compose up`. It now documents the Quadlet, the keep-groups + udev
mechanism (verified inside the running container: torch sees Radeon 8060S), the
9,146-restart incident that forced the move, and the trap that caused it — a
stale container outlives the compose edit that should have replaced it.

The observability page gains the audit result: four jobs read "down" and three
of them always will, because they scrape HTML pages or a /metrics that does not
exist. The page names each error, says plainly that none is an outage, and
refuses the tempting fix (deleting the job makes an absent scrape look like a
healthy one) in favour of the remedy it already recommended: a blackbox exporter
in probe mode, and Gitea's metrics enabled or the job repointed.
2026-09-16 07:17:59 -07:00

105 lines
6.3 KiB
Markdown

# ComfyUI
ComfyUI is a node-based AI image generation engine. Workflows are built from nodes that load models, sample latents, and post-process images; everything is scriptable through a web UI and an API.
**Host:** Dankclaw — **Port:** `8188` published on the host; **no vhost and no
guard chain** — ComfyUI is LAN-only by construction (the Caddyfile routes no
name to it) — **Backend:** ROCm GPU (gfx1151) — **Docs:**
https://github.com/Comfy-Org/ComfyUI
## Facts
| Item | Value |
|------|-------|
| Image | `comfyui-rocm:gfx1151` — built from `dankclaw/Containerfile.comfyui` |
| Base image | `docker.io/rocm/vllm:rocm7.12.0_gfx1151_ubuntu24.04_py3.12_pytorch_2.9.1_vllm_0.16.0` |
| Port | 8188 (host) → 8188 (container) |
| Backend | ROCm GPU (gfx1151 / Radeon 8060S). No `--cpu` flag. |
| Data | `/home/dank/comfyui-data/{models,input,output,custom_nodes}` → `/opt/ComfyUI/...` |
| Run | `./scripts/deploy.sh dankclaw --service comfyui` (Quadlet unit `comfyui.service`) |
| Boot-persistent | Quadlet unit `dankclaw/comfyui/quadlet/comfyui.container` → `~/.config/containers/systemd/` |
## Why the GPU works here
Dankclaw is an AMD Strix Halo APU (gfx1151). Standard PyTorch ROCm wheels do not ship gfx1151 kernels. So `torch.cuda.is_available()` returns `False` and ComfyUI falls back to CPU. AMD publishes a gfx1151-tagged build, and the image above is based on it. On this APU it reports `torch.cuda.is_available() = True`, device `Radeon 8060S`, capability `(11, 5)`. See [[ComfyUI ROCm and Vulkan]] for the full verification.
## How the image is built
`dankclaw/Containerfile.comfyui` starts from the AMD gfx1151 base image and bakes the ComfyUI code in. It installs ComfyUI's dependencies but skips the torch family (torch, torchvision, torchaudio). The base image already ships the matching ROCm builds. Installing an unpinned `torch` from `requirements.txt` clobbers the gfx1151 kernels with a default build, so the Containerfile filters those lines out.
## GPU device access (rootless), and why the unit exists
The unit passes `/dev/kfd` and `/dev/dri` (`AddDevice=`) and uses
`GroupAdd=keep-groups`. A literal `render` entry cannot work: rootless Podman
cannot map the group name into the user namespace. The companion udev rule
`dankclaw/udev/99-comfyui-gpu-access.rules` keeps those nodes `MODE 0666`, which
is what lets a **user-unit spawn** — carrying no supplementary groups — open
them anyway. Verified inside the running container: `torch.cuda.is_available()`
is `True` and the device is `Radeon 8060S Graphics`.
**Incident, 2026-09-16 — why this is a Quadlet now.** ComfyUI ran from
`dankclaw/compose.yaml` through a hand-written `~/.config/systemd/user/
comfyui.service` that called `podman compose up -d`. Its container was created
*before* the GPU declarations were added to the compose service, and
`restart: unless-stopped` then kept restarting that stale container: no
`/dev/kfd`, no `/dev/dri`, no keep-groups, dead on `RuntimeError: No HIP GPUs
are available` — **9,146 restarts** and about seven hours down. The service was
fine; the container was old. A `--force-recreate` would have fixed it that day,
but the class of bug needed the unit: one owner per container name, repo-tracked,
and recreated from the source of truth on every deploy. The compose service is
deleted; `deploy_comfyui` retires any compose-era unit into `~/.AGENTTRASH/`
and removes a stale container before installing the unit.
## Volumes
| Container path | Host path |
|----------------|-----------|
| `/opt/ComfyUI/models` | `/home/dank/comfyui-data/models` |
| `/opt/ComfyUI/input` | `/home/dank/comfyui-data/input` |
| `/opt/ComfyUI/output` | `/home/dank/comfyui-data/output` |
| `/opt/ComfyUI/custom_nodes` | `/home/dank/comfyui-data/custom_nodes` |
The ComfyUI code is baked into the image (not mounted). Rebuild the image to update the code.
## Custom nodes
Custom nodes go in `/home/dank/comfyui-data/custom_nodes` (mounted at `/opt/ComfyUI/custom_nodes`). ComfyUI loads every subdirectory there on start. Because this path is a bind mount, it shadows anything baked into the image — so custom nodes are installed host-side, not in the Containerfile.
**ComfyUI-Manager** is installed here. Install it with a one-time clone, then restart the container:
```bash
git clone https://github.com/ltdrdata/ComfyUI-Manager \
/home/dank/comfyui-data/custom_nodes/ComfyUI-Manager
systemctl --user restart comfyui
```
ComfyUI-Manager self-installs its own pip dependencies on start (GitPython, PyGithub, matrix-nio, transformers, and more). To confirm it loaded, query `GET /manager/version` (returns a version like `V3.41`). Its pip installs live in the container's writable layer, so they survive a restart and a reboot but not an image rebuild; after a rebuild, Manager re-installs them on the next start.
## Boot persistence
The Quadlet unit carries `[Install] WantedBy=default.target` with
`Restart=always`, so the generator wires it into `default.target` and it comes
back on its own (user linger is on). Inspect it with
`systemctl --user is-enabled comfyui.service` → `generated`; an explicit
`systemctl --user enable` fails on generated units.
## Healthcheck
The web UI responds on `/`. ComfyUI also exposes `/system_stats`. On this APU, `/system_stats` reports `device=cuda:0 Radeon 8060S Graphics` (type `cuda`, the ROCm device).
## Gotchas
- The GPU path needs the device passthrough. Do not remove `AddDevice=/dev/kfd` or `AddDevice=/dev/dri` from the unit, and keep `GroupAdd=keep-groups`.
- Do not add the `render` group by name. Rootless podman cannot map it; the udev rule plus `keep-groups` is the mechanism that works.
- **A stale container outlives a compose edit.** If the GPU declarations change, recreate the container (`deploy.sh dankclaw --service comfyui` removes the old one) — `restart: unless-stopped` will happily keep an old config alive forever.
- Do not let pip reinstall the torch family. The Containerfile filters it out on purpose.
- The base image is about 32 GB. A code update means a rebuild, because the code is baked in.
- The model collection starts empty. Add models to `/home/dank/comfyui-data/models` before generating.
## See Also
- [[Dankclaw Stack]]
- [[ComfyUI ROCm and Vulkan]] — the live-verified GPU path research
- [[Lemonade and sd.cpp]] — the ggml-family alternative
- Knowledge base: [[ComfyUI]] (tools)