Kubernetes GPU sidecar rollout
intelli-verse-kube-infra/content-factory/ contains ~25 GPU sidecar
services that back the Content Factory pipelines (image gen, video
gen, TTS, audio synthesis, 3D, motion, …). This skill is the safe
rollout / debug / upgrade workflow for them.
When to use this skill
- "Upgrade comfyui to v0.3.x"
- "Why is musetalk OOMing?"
- "Roll out the new vllm-coder-pro image"
- "Scale up trellis2 — pipelines are queueing"
- "Add a new GPU service — here's the upstream repo"
Prerequisites
kagentdeployed in the cluster (gives MCP tools for Kubernetes / Helm / Argo / Prometheus / Grafana).gastownMCP server (so the swarm can be coordinated).kubectlcontext pointing at the right cluster.- Read access to
intelli-verse-kube-infrarepo.
The workflow
Upgrade / version-bump path
Confirm the target image tag with the user. If they don't know, use
firecrawl scrape <upstream-repo>/releases/latestto find the newest stable tag.Diff the current vs. desired manifest in
intelli-verse-kube-infra/content-factory/<service>/:kubectl -n content-factory get deploy <service> -o yaml | grep image: grep "image:" intelli-verse-kube-infra/content-factory/<service>/deploy.yamlOpen a PR via the gastown swarm (do NOT kubectl apply directly — every change must go through the manifest repo):
gt_sling( repo="intelli-verse-kube-infra", polecat_role="coder", bead_title="Bump <service> to <tag>", body="Upgrade content-factory/<service>/deploy.yaml from <old> to <new>." )After merge, ArgoCD (if installed) or kustomize/helm sync applies the change. Monitor:
kubectl -n content-factory rollout status deploy/<service>- Grafana dashboard for the service (
monitoring.yamldefines one per service).
Debug path (service unhealthy)
Get the symptom from the user (errors, latency, OOMs).
Pull the recent state via kagent MCP tools:
kagent_kubectl_describe(namespace="content-factory", resource="deploy/<service>") kagent_kubectl_logs(namespace="content-factory", pod="<pod>", lines=200) kagent_prometheus_query(query="rate(container_oom_events_total{pod=~'<service>.*'}[5m])")Common causes for this set of services:
- GPU not allocated — check
nodeSelector/tolerationsblock, verify Karpenter has a GPU NodePool. - HPA not scaling — check
keda/ScaledObject; the queue metric source may have drifted. - Image pull error — secret
content-factory-secretsmay have stale registry creds. See README "Bootstrapping / rotating". - PDB blocking eviction —
pdb.yamlmay have minAvailable too high during a single-replica rollout.
- GPU not allocated — check
Escalate via
gt escalateif SLO breached for > 5 min — the deacon will create a P0 bead and notify the on-call.
New service path (adding a GPU sidecar)
Scaffold under
content-factory/<new-service>/:<new-service>-deploy.yaml(withmetadata.namespace: content-factory)<new-service>-service.yaml(ClusterIP)<new-service>-hpa.yaml(queue-based via KEDA preferred)<new-service>-pdb.yaml(minAvailable: 1 if multi-replica, 0 if singleton)- Add a Grafana panel entry to
monitoring.yaml.
Wire secrets via secretKeyRef from
content-factory-secrets— never put credentials in the manifest. Update the README table inintelli-verse-kube-infra/content-factory/README.mdwith the new keys consumed.Wire the Content Factory app side in
~/dev/content-factory/tools/generators/so the pipelines can call the new service. PR the two repos together.
Surfacing results
Always show:
- The diff that's being applied (image tag, resource limits, env vars).
- The rollout strategy (
maxUnavailable,maxSurge) — GPU services are usually single-replica so default RollingUpdate can cause brief outages. - The post-rollout health check command for the user to verify.
Safety guardrails
- Never
kubectl applydirectly — always via PR + ArgoCD/sync. Direct applies cause drift that breaks the next sync. - Never edit
content-factory-secretsin-place — the README's bootstrapping command must re-emit every key. - Always check PDB before draining — single-replica GPU services with PDB minAvailable=1 will block node maintenance.
- HPA + KEDA conflicts — only one autoscaler per deployment. If both are defined, KEDA wins; HPA YAML should be deleted.
Common failures
| Error | Fix |
|---|---|
0/N nodes available: insufficient nvidia.com/gpu |
No GPU NodePool ready. Check karpenter/ for a NodePool matching the deployment's nodeSelector. |
OOMKilled repeatedly |
Bump resources.limits.memory. Some services (musetalk, hymotion) need 16-24 GiB even at idle. |
Stuck in ContainerCreating |
Usually an ImagePullBackOff — check kubectl describe pod. Could be registry creds in content-factory-secrets. |
503 from CF api hitting the service |
Service URL env var in api-deploy.yaml is wrong; or the ClusterIP service name doesn't match what the api expects. |