
Operating on Media Generation
Last updated 2026-07-15 ·0b3d5f7
This is the operational companion to Media Generation, which covers the GPU time-slicing architecture, custom Docker images, and storage layout. Here you’ll find the commands to run, check, and fix the stack day-to-day.
Before any commands, source the environment:
source .envWhat Healthy Looks Like
- The GPU-switcher control pod is
Running. - The ComfyUI StatefulSet is
Runningwith one or more replicas. - The active GPU profile matches the intended workload (e.g.,
videofor video generation). - ComfyUI web UI is accessible on its internal ClusterIP service.
graph LR
subgraph media["media namespace"]
gs["GPU Switcher<br/>Deployment"]
cfy["ComfyUI<br/>StatefulSet"]
vol["Ollama<br/>Deployment"]
subgraph pvcs["Persistent Volumes"]
pvcM["comfyui-models<br/>200Gi RWX"]
pvcO["comfyui-output<br/>100Gi RWX"]
pvcC["comfyui-config<br/>10Gi RWX"]
end
cfy --- pvcM
cfy --- pvcO
cfy --- pvcC
end
subgraph gpunode["gpu-1 node"]
gpu["nvidia.com/gpu: 1"]
end
gs -->|scale 1 / scale 0| cfy
gs -->|scale 1 / scale 0| vol
cfy ---|requests| gpu
vol ---|requests| gpu
Verify
Check Stack Status
# Check GPU-switcher pod (controls GPU profiles)
kubectl get pods -n media -l app.kubernetes.io/name=gpu-switcher
# Check ComfyUI pods
kubectl get pods -n media -l app.kubernetes.io/name=comfyui
# Check persistent volumes
kubectl get pvc -n media
# Check GPU profile
kubectl logs -n media -l app.kubernetes.io/name=gpu-switcher --tail=10$ kubectl get pods -n media
NAME READY STATUS RESTARTS AGE
comfyui-0 1/1 Running 0 12d
gpu-switcher-544b8c9f96-4x9j2 1/1 Running 0 12d
$ kubectl get pvc -n media
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
comfyui-config Bound pvc-xxx 10Gi RWX rook-cephfs 12d
comfyui-models Bound pvc-yyy 200Gi RWX rook-cephfs 12d
comfyui-output Bound pvc-zzz 100Gi RWX rook-cephfs 10d
Access ComfyUI Web UI
# Port-forward to the ComfyUI service
kubectl port-forward -n media service/comfyui 18188:18188Then open http://localhost:18188 in a browser.
Steps
Switch GPU Profile
# Check available profiles
kubectl exec -n media deploy/gpu-switcher -- ls /profiles/
# Switch to video profile
kubectl exec -n media deploy/gpu-switcher -- ./switch.sh video
# Verify
kubectl logs -n media deploy/gpu-switcher --tail=10Upload a Model
# Copy a model file to the ComfyUI models directory
kubectl cp ./checkpoint.safetensors -n media comfyui-0:/app/models/checkpoints/
# Verify
kubectl exec -n media comfyui-0 -- ls -la /app/models/checkpoints/checkpoint.safetensorsDownload Output Files
# List output files
kubectl exec -n media comfyui-0 -- ls -la /app/output/
# Copy output to local machine
kubectl cp -n media comfyui-0:/app/output/generated-image.png ./generated-image.png
# Or tar multiple outputs
kubectl exec -n media comfyui-0 -- tar czf /tmp/outputs.tar.gz -C /app/output/ .
kubectl cp -n media comfyui-0:/tmp/outputs.tar.gz ./outputs.tar.gzRestart ComfyUI
kubectl rollout restart -n media statefulset/comfyui
kubectl rollout status -n media statefulset/comfyuiRecover
ComfyUI Pod Stuck in CrashLoopBackOff
The most common cause is a Python dependency conflict — typically torchaudio version mismatch or a custom node failing to load.
# Check the logs
kubectl logs -n media comfyui-0 --tail=50
# Check for the specific error
kubectl logs -n media comfyui-0 --tail=20 | grep -i errorKnown fixes:
torchaudio mismatch — The PIP-installed torchaudio may conflict with the PyTorch wheel bundled in the image. Pin it to match:
kubectl exec -n media comfyui-0 -- pip install torchaudio==torchCustom node permission error — Some custom nodes write to site-packages at import time. The fix was version-gating the PersistentVolumeClaimA Kubernetes request for durable storage. The pod names a claim and the storage layer — Longhorn on Frank — binds real disk behind it, so the data outlives the pod. seed: the stoa3→stoa4 upgrade introduced a PVC for custom nodes that needed the right fsGroup:
# In the ComfyUI StatefulSet
securityContext:
fsGroup: 1000If the pod won’t start at all, you can’t exec in. Instead, edit the StatefulSet directly:
kubectl edit statefulset -n media comfyuiUnder spec.template.spec.securityContext, ensure fsGroup: 1000 is set.
ComfyUI Pod Crashes on Large Model Load
# Check GPU memory
kubectl exec -n media comfyui-0 -- nvidia-smi
# Check if the GPU profile is correct for the model
kubectl logs -n media deploy/gpu-switcher --tail=10The GPU switcher must be on the right profile — video models need the video profile, image models the image profile. If the profile is wrong, large models Out Of MemoryWhat the kernel does when memory runs out — it kills a process by score, not by fault. A container hitting its cgroup limit is killed the same way, which is why the victim is often not the culprit. immediately.
Pod Pending (No Available GPU)
kubectl describe pod -n media comfyui-0 | grep -A 10 EventsIf the pod is Pending with 0/1 nodes are available: 1 Insufficient nvidia.com/gpu, there are no GPU nodes available or the GPUs are fully allocated.
GPU Switcher Issues
The GPU switcher is a lightweight Go binary. Common issues:
# Check logs
kubectl logs -n media deploy/gpu-switcher
# If the image fails due to platform mismatch
# (cross-compiled for wrong arch)
# The fix was using explicit ARG target platform:
kubectl logs -n media deploy/gpu-switcher | grep "platform\|architecture"If the GPU switcher pod doesn’t start, check it was built with --platform=linux/amd64 — the node runs amd64 even if the build machine is arm64.
Output PVC Not Mounted
If ComfyUI starts but outputs aren’t persistent:
# Check PVC is bound
kubectl get pvc -n media comfyui-output
# Check it's mounted in the pod
kubectl exec -n media comfyui-0 -- mount | grep outputThe comfyui-output PVC and comfyui-config PVC were added separately from the comfyui-models PVC in PR #566. If outputs disappear after a pod restart, the PVC is either missing from the StatefulSet template or not bound.
Missteps
| What we assumed | Why it was wrong | What it cost |
|---|---|---|
pip install torchaudio would get the right version | The PIP index distributes a different build than the Compute Unified Device ArchitectureNVIDIA's GPU programming platform. Practically, the layer every local inference engine sits on, and the reason a driver/toolkit version mismatch stops a model loading. 12.8 wheel baked into the image. Installing without pinning broke audio-capable custom nodes (Wan, FishSpeech). | Two iterations to discover torchaudio==torch as the pin. |
| Custom node PVC could be seeded at any time | The stoa3→stoa5 PersistentVolumeThe actual piece of storage a PVC binds to. The claim is the request; the PV is what satisfies it. hardening broke existing custom-node PVCs that didn’t have the right version gate. | Three separate fixes across stoa3, stoa4, stoa5 (#549, #562). |
| Cross-compiling a Go binary “just works” | The first gpu-switcher build used emulated amd64 (Quick EmulatorThe emulator and virtualiser underneath most Linux virtualisation, including KubeVirt's virtual machines.), which produced corrupted binaries. The second attempt passed the wrong platform string. The binary had to be rebuilt three times. | Three rebuild cycles and a force-push. |
| ComfyUI output directory is always persistent | The original ComfyUI manifest had no output PVC. After a pod restart, all generated media was gone. | Lost output files, then added the PVC in a follow-up PR. |
Quick Reference
| Command | What It Does |
|---|---|
kubectl get pods -n media | Check media stack pods |
kubectl get pvc -n media | Check PVCs (models, output, config) |
kubectl port-forward -n media svc/comfyui 18188:18188 | Access ComfyUI web UI |
kubectl exec -n media deploy/gpu-switcher -- ./switch.sh <profile> | Switch GPU profile |
kubectl cp <file> -n media comfyui-0:<path> | Upload/download files |
kubectl rollout restart -n media sts/comfyui | Restart ComfyUI |
kubectl logs -n media comfyui-0 | grep -i error | Check ComfyUI startup errors |
kubectl exec -n media comfyui-0 -- nvidia-smi | Check GPU memory usage |
