Files
serverAppConfigs/dankclaw/comfyui/quadlet/comfyui.container
T
Frank 03d44d3308 comfyui: replace the stale compose container with a Quadlet unit
ComfyUI had failed 9,146 times and had been down ~7 hours when this was found:
its container was created 2026-09-15 14:12, BEFORE the GPU declarations were
added to the compose service, and `restart: unless-stopped` kept restarting
that stale container — no /dev/kfd, no /dev/dri, no keep-groups — so it died
every time on `RuntimeError: No HIP GPUs are available`. Its "unit" was a
hand-written ~/.config/systemd/user/comfyui.service that shelled out to
`podman compose up -d`, which is not repo-tracked state and collides by name
with the Quadlet the generator produces.

  - dankclaw/comfyui/quadlet/comfyui.container: image comfyui-rocm:gfx1151
    (built from Containerfile.comfyui), /dev/kfd + /dev/dri, keep-groups,
    the four comfyui-data volumes, loopback-only publish (an unguarded service
    is internal-only here; the homepage card probes 127.0.0.1:8188), Restart=
    always, WantedBy=default.target.
  - the compose service is deleted — one owner per container name.
  - deploy_comfyui builds the image, installs the unit, retires the compose-era
    unit into ~/.AGENTTRASH, removes the stale container so the unit's own can
    take the name, and waits on :8188.
  - the healthcheck is a file, because the podman 5.x v1 generator splits
    HealthCmd on spaces and an inline `python3 -c "..."` becomes a quoting
    puzzle that fails silently.

The comfyui seam now reads the unit instead of compose for devices, command and
groups (and resolves the Containerfile from the deployer's declaration, not
from a directory listing).
2026-09-16 07:13:27 -07:00

69 lines
3.0 KiB
INI

# Quadlet unit: ComfyUI (rootless, boot-persistent).
#
# Install path on dankclaw: ~/.config/containers/systemd/comfyui.container
# Unit name: comfyui.service (container name: comfyui)
#
# WHY THIS FILE EXISTS. 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 2026-09-15 14:12, BEFORE the
# GPU declarations were added to the compose service, and `restart:
# unless-stopped` then kept restarting that stale container — so it started
# without /dev/kfd, without /dev/dri and without keep-groups, died on
# `RuntimeError: No HIP GPUs are available`, and had restarted 9,146 times when
# this was found. A recreate via compose would have fixed the container; a unit
# fixes the class: one owner per container name, repo-tracked, boot-persistent
# through the generator.
#
# GPU ACCESS. /dev/kfd + /dev/dri plus keep-groups. A literal `render` group
# entry cannot work under rootless Podman (the group name does not resolve
# inside the user namespace), and the companion udev rule
# (dankclaw/udev/99-comfyui-gpu-access.rules) keeps those nodes MODE 0666 so a
# user-unit spawn — which carries no supplementary groups — can still open them.
# Both halves are asserted by tests/comfyui_rocm.bats.
#
# EXPOSURE. Loopback only. ComfyUI has no authentication and executes arbitrary
# node graphs, and it has no Caddy vhost, so the repository's rule applies:
# an unguarded service is internal-only. The homepage status card probes
# 127.0.0.1:8188, which this satisfies. To reach the UI from another machine,
# guard it behind the auth chain and give it a vhost — do not widen the bind.
#
# DATA. Models, input, output and custom_nodes live under
# /home/dank/comfyui-data (host state, not in the repo).
[Unit]
Description=ComfyUI (gfx1151 ROCm image generation)
After=network-online.target
Wants=network-online.target
[Container]
ContainerName=comfyui
Image=localhost/comfyui-rocm:gfx1151
Pull=never
Network=dankclaw_default
PublishPort=127.0.0.1:8188:8188
AddDevice=/dev/kfd
AddDevice=/dev/dri
GroupAdd=keep-groups
Volume=/home/dank/comfyui-data/models:/opt/ComfyUI/models
Volume=/home/dank/comfyui-data/input:/opt/ComfyUI/input
Volume=/home/dank/comfyui-data/output:/opt/ComfyUI/output
Volume=/home/dank/comfyui-data/custom_nodes:/opt/ComfyUI/custom_nodes
Volume=/home/dank/serverAppConfigs/dankclaw/comfyui/comfyui-healthcheck.py:/usr/local/bin/comfyui-healthcheck.py:ro
Exec=python main.py --listen 0.0.0.0 --port 8188
# The probe lives in a file because the podman 5.x v1 generator splits
# HealthCmd on spaces into an argv array; an inline `python3 -c "..."` becomes
# a puzzle of quoting that fails silently.
HealthCmd=python3 /usr/local/bin/comfyui-healthcheck.py
HealthInterval=30s
HealthTimeout=10s
HealthRetries=3
# First start loads torch and the node graph; give it room before the probe
# counts against it.
HealthStartPeriod=300s
[Service]
Restart=always
RestartSec=10
[Install]
WantedBy=default.target