Files
serverAppConfigs/dankclaw/comfyui/quadlet/comfyui.container
T
Frank 4b443c86d8 comfyui: bake qwen_image21 patch into image via startup wrapper
The qwen_image21 detection check and GGUF node arch list patch are
applied by a startup wrapper (comfyui-start.sh) that runs before
ComfyUI starts. The patch script and wrapper are baked into the image
so they survive container recreations. The quadlet's Exec now points
at the wrapper instead of main.py directly.
2026-09-21 19:55:00 -07:00

71 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. LAN-reachable, no auth. ComfyUI has no authentication and executes
# arbitrary node graphs. It is internal-only (no public vhost, no guard chain);
# it is reached on the LAN via the Pi-hole DNS record
# (comfyui.franksdank.cloud -> 192.168.0.143, in dankclaw/pihole/addn-hosts),
# which resolves to this host's IP — so the bind is widened from loopback to
# 0.0.0.0:8188. The homepage admin card links to that URL and probes
# 127.0.0.1:8188.
#
# 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=0.0.0.0: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=/opt/ComfyUI/comfyui-start.sh
# 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