diff --git a/docs/asset-engine/services.yaml b/docs/asset-engine/services.yaml index ff4d484..7bbd17d 100644 --- a/docs/asset-engine/services.yaml +++ b/docs/asset-engine/services.yaml @@ -28,6 +28,10 @@ services: category: tts version: 2 host: irv-ml1 + lifecycle: + stack: kokoro + vram_gb: 2 + gpu_device_id: null endpoint: http://10.100.79.3:8193/v1/audio/speech method: POST content_type: application/json @@ -201,6 +205,10 @@ services: version: 1 status: down host: irv-ml1 + lifecycle: + stack: chatterbox + vram_gb: 4 + gpu_device_id: 0 endpoint: http://10.100.79.3:8196/v1/audio/speech method: POST content_type: application/json @@ -261,6 +269,10 @@ services: version: 1 status: down host: irv-ml1 + lifecycle: + stack: index-tts + vram_gb: 6 + gpu_device_id: null endpoint: http://10.100.79.3:8192/v1/audio/speech method: POST content_type: application/json @@ -337,6 +349,10 @@ services: version: 1 status: down host: irv-ml1 + lifecycle: + stack: qwen3-tts + vram_gb: 16 + gpu_device_id: null endpoint: http://10.100.79.3:8191/v1/audio/speech method: POST content_type: application/json @@ -394,6 +410,10 @@ services: version: 1 status: down host: irv-ml1 + lifecycle: + stack: cosyvoice + vram_gb: 4 + gpu_device_id: null endpoint: http://10.100.79.3:8190/v1/audio/speech method: POST content_type: application/json @@ -454,6 +474,10 @@ services: category: tts version: 1 host: irv-ml1 + lifecycle: + stack: fish-s2 + vram_gb: 4 + gpu_device_id: 1 endpoint: http://10.100.79.3:8195/v1/tts method: POST content_type: application/json @@ -503,6 +527,10 @@ services: version: 1 status: down host: irv-ml1 + lifecycle: + stack: kyutai-tts + vram_gb: 6 + gpu_device_id: 0 endpoint: http://10.100.79.3:8198/v1/audio/speech method: POST content_type: application/json @@ -552,6 +580,10 @@ services: category: tts version: 2 host: irv-ml1 + lifecycle: + stack: vibevoice + vram_gb: 20 + gpu_device_id: 1 endpoint: http://10.100.79.3:8194/v1/audio/speech method: POST content_type: application/json @@ -636,6 +668,10 @@ services: version: 1 status: down host: irv-ml1 + lifecycle: + stack: voxtral + vram_gb: 12 + gpu_device_id: 1 endpoint: http://10.100.79.3:8197/v1/audio/speech method: POST content_type: application/json @@ -689,6 +725,10 @@ services: category: asr version: 1 host: irv-ml1 + lifecycle: + stack: parakeet + vram_gb: 2 + gpu_device_id: null endpoint: http://10.100.79.3:8765/transcribe method: POST content_type: multipart/form-data @@ -724,6 +764,10 @@ services: category: sfx version: 1 host: irv-ml1 + lifecycle: + stack: stable-audio-open + vram_gb: 6 + gpu_device_id: 1 endpoint: http://10.100.79.3:8211/v1/audio/sfx method: POST content_type: application/json @@ -787,6 +831,10 @@ services: category: music version: 5 host: irv-ml1 + lifecycle: + stack: ace-step + vram_gb: 16 + gpu_device_id: 1 endpoint: http://10.100.79.3:8210/generate method: POST content_type: application/json diff --git a/playbooks/deploy-asset-engine.yaml b/playbooks/deploy-asset-engine.yaml index cc76a4e..3e25c9c 100644 --- a/playbooks/deploy-asset-engine.yaml +++ b/playbooks/deploy-asset-engine.yaml @@ -26,6 +26,7 @@ vars: compose_dir: /opt/docker/compose/asset-engine db_dir: /opt/docker/conf/asset-engine/db outputs_dir: /opt/docker/conf/asset-engine/outputs + ssh_dir: /opt/docker/conf/asset-engine/ssh host_port: "8200" steps: @@ -90,6 +91,11 @@ steps: shell: mkdir -p {{ outputs_dir }} creates: "{{ outputs_dir }}" + - name: Ensure SSH key dir exists (parent only — keys themselves are seeded + out-of-band on the host so the private key never crosses the network) + shell: mkdir -p {{ ssh_dir }} && chmod 700 {{ ssh_dir }} + creates: "{{ ssh_dir }}" + # ── deploy compose files ──────────────────────────────────────────── - name: Upload compose.yaml upload: diff --git a/servers/irv-ml1/README.md b/servers/irv-ml1/README.md index 0089384..60846b3 100644 --- a/servers/irv-ml1/README.md +++ b/servers/irv-ml1/README.md @@ -65,12 +65,29 @@ Docker 29.4.1 with `nvidia` and `runc` runtimes. `lkraven` is in the `docker` group. `traefik-net` external network exists for stacks that need it. -| Stack | Port | Role | -|-------|------|------| -| dockge | 5001 | Per-host Compose UI | -| beszel-agent-irv | 45876 | Metrics agent → Beszel hub on ana-docker (token mode through WG) | -| dozzle-agent-irv | 7007 | Log agent → Dozzle hub on ana-docker | -| comfyui | 8188 | ComfyUI (node-based SD/Flux) — runs independently of `/opt/ComfyUI` native install | +| Stack | Port | GPU | Role | +|-------|------|-----|------| +| dockge | 5001 | — | Per-host Compose UI | +| beszel-agent-irv | 45876 | — | Metrics agent → Beszel hub on ana-docker (token mode through WG) | +| dozzle-agent-irv | 7007 | — | Log agent → Dozzle hub on ana-docker | +| comfyui | 8188 | all | ComfyUI (node-based SD/Flux) — runs independently of `/opt/ComfyUI` native install | +| kokoro | 8193 | all | Kokoro 82M TTS — lowest-latency English TTS, OpenAI-compatible /v1/audio/speech | +| chatterbox | 8196 | 0 (3090) | Chatterbox voice-cloning TTS | +| index-tts | 8192 | all | IndexTTS multilingual TTS | +| qwen3-tts | 8191 | all | Qwen3-TTS — 7B multilingual TTS | +| cosyvoice | 8190 | all | CosyVoice multilingual TTS | +| fish-s2 | 8195 | 1 (A6000) | Fish-Speech S2 TTS | +| kyutai-tts | 8198 | 0 (3090) | Kyutai TTS | +| vibevoice | 8194 | 1 (A6000) | Microsoft VibeVoice TTS | +| voxtral | 8197 | 1 (A6000) | Mistral Voxtral ASR | +| parakeet | 8765 | all | NVIDIA Parakeet ASR (transcription) | +| stable-audio-open | 8211 | 1 (A6000) | Stable Audio Open 1.0 — diffusion SFX/ambience generator | +| ace-step | 8210 | 1 (A6000) | ACE-Step 1.5 — Apache-2.0 hybrid diffusion+LLM music generation | + +GPU pinning comes from the compose `NVIDIA_VISIBLE_DEVICES` default; +`all` means the model picks at runtime (typically GPU 0). The +asset-engine orchestrator (`docs/asset-engine/services.yaml` → per-service +`lifecycle:` block) gates start operations on per-device VRAM headroom. Exposed Docker socket on `*:2375` (for the homepage integration hub on esh-docker-vm, which auto-discovers containers on this host). diff --git a/stacks/asset-engine/.env.example b/stacks/asset-engine/.env.example index 1ce05c7..970e920 100644 --- a/stacks/asset-engine/.env.example +++ b/stacks/asset-engine/.env.example @@ -22,6 +22,13 @@ ASSET_ENGINE_BIND=0.0.0.0 ASSET_ENGINE_DB_DIR=/opt/docker/conf/asset-engine/db ASSET_ENGINE_OUTPUTS_DIR=/opt/docker/conf/asset-engine/outputs +# SSH key dir for orchestrating irv-ml1 services (bring up / down via SSH + +# docker compose). Holds id_ed25519 (mode 600) + known_hosts (mode 644) +# pre-populated with irv-ml1's pinned ed25519 fingerprint. Generated on the +# host directly so the private key never crosses the network. Bind-mounted +# read-only into the container at /app/runtime/ssh. +ASSET_ENGINE_SSH_DIR=/opt/docker/conf/asset-engine/ssh + # Inference target. Default is irv-ml1 over WG. Override if the fleet's # inference host moves. INFERENCE_HOST=10.100.79.3 diff --git a/stacks/asset-engine/compose.yaml b/stacks/asset-engine/compose.yaml index a12979f..d1dd9ed 100644 --- a/stacks/asset-engine/compose.yaml +++ b/stacks/asset-engine/compose.yaml @@ -15,8 +15,9 @@ # # Internal tooling — accessed directly on host:port over the LAN, does # NOT traverse Traefik. State persists under /opt/docker/conf/asset-engine/ -# {db,outputs} on the host — separate bind-mounts so outputs/ can move -# to a bigger volume later without touching DB state. +# {db,outputs,ssh} on the host — db/outputs are separate bind-mounts so +# outputs/ can move to a bigger volume later without touching DB state; +# ssh/ holds the dedicated keypair used to orchestrate irv-ml1 services. # # All tunables live in .env — edit that, not this file. @@ -36,9 +37,15 @@ services: - OIDC_ISSUER=${OIDC_ISSUER:-} - OIDC_CLIENT_ID=${OIDC_CLIENT_ID:-} - OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET:-} + # Orchestration SSH paths inside the container. + - SSH_KEY_PATH=/app/runtime/ssh/id_ed25519 + - SSH_KNOWN_HOSTS=/app/runtime/ssh/known_hosts volumes: - ${ASSET_ENGINE_DB_DIR}:/app/runtime/db - ${ASSET_ENGINE_OUTPUTS_DIR}:/app/runtime/outputs + # Dedicated SSH key for orchestrating irv-ml1 services (up/down). + # Read-only; key is generated on the host, never crosses the network. + - ${ASSET_ENGINE_SSH_DIR}:/app/runtime/ssh:ro healthcheck: test: ["CMD-SHELL", "python -c 'import urllib.request,sys; r=urllib.request.urlopen(\"http://127.0.0.1:8000/health\",timeout=3); sys.exit(0 if r.status==200 else 1)' || exit 1"] interval: 30s