VSS Deploy
Objectif
Déployer n'importe quel profil VSS (base, search, lvs, warehouse, alerts, edge) en utilisant un workflow centré sur compose : construire des surcharges d'env, générer le compose résolu (dry-run), vérifier, puis déployer. Ce SKILL.md couvre les préoccupations transversales (routage de profil, prérequis, NGC, configuration GPU, et le flux deploy/teardown). Les listes de services spécifiques au profil, le dimensionnement, les recettes env, les endpoints et le debugging se trouvent dans des docs de référence par profil — charger celle qui correspond à l'intention de l'utilisateur.
Script helper : run_script("scripts/normalize_resolved_yml.py", "<resolved.yml>") normalise un dump dry-run docker compose config pour une vérification diff-friendly à l'étape 3c. Tous les autres travaux de déploiement passent par compose / dev-profile.sh.
Scripts disponibles
| Script | Objectif | Arguments |
|---|---|---|
scripts/normalize_resolved_yml.py |
Supprimer les entrées optionnelles depends_on pour les services filtrés de resolved.yml avant le déploiement. |
Chemin vers resolved.yml |
Routage de profil
Faire correspondre la demande de l'utilisateur à un profil, puis charger la référence de ce profil pour le dimensionnement, les services, les recettes env et le debugging.
| L'utilisateur dit | Profil | Référence |
|---|---|---|
| "deploy vss" / "deploy base" | base |
references/base.md |
| "deploy alerts" / "alert verification" / "real-time alerts" / "deploy for incident report" | alerts |
references/alerts.md |
| "deploy lvs" / "video summarization" | lvs |
references/lvs-profile.md |
| "deploy search" / "video search" | search |
references/search.md |
| "deploy warehouse" / "warehouse blueprint" / "vss warehouse" | warehouse |
references/warehouse.md |
| "debug warehouse" / "warehouse not working" / "warehouse FPS low" / "warehouse BEV out of sync" | warehouse (debug) |
references/warehouse-debug.md |
Routage matériel Edge (DGX Spark, AGX/IGX Thor) : voir references/edge.md. DGX Spark utilise le LLM local standalone Spark Nano 9B sur le port 30081 ; AGX/IGX Thor utilise le fallback vLLM standalone Edge 4B.
Chaque référence de profil possède sa table de dimensionnement. Ne pas choisir une forme de déploiement depuis ce fichier — ouvrir la référence de profil et vérifier le nombre minimum de GPU pour le matériel de l'hôte par rapport à la matrice (mode × plateforme) là-bas.
Instructions
Le flux de déploiement est toujours : copier .env vers generated.env, appliquer les surcharges, dry-run compose vers resolved.yml, vérifier, normaliser, déployer, puis attendre la disponibilité.
# 1. cp dev-profile-<profile>/.env dev-profile-<profile>/generated.env (clean copy)
# 2. Apply env overrides to generated.env (source .env stays untouched)
# 3. docker compose --env-file generated.env config > resolved.yml (dry-run)
# 4. Review resolved.yml
# 5. docker compose --env-file generated.env -f resolved.yml up -d
Le .env source est traité comme valeurs par défaut en lecture seule engagées dans le repo. La copie de travail par déploiement de la skill est generated.env — le même pattern que dev-profile.sh utilise en interne. Cela maintient le .env enregistré propre à travers les itérations.
Prérequis
- Chemin du repo — trouver
video-search-and-summarization/sur le disque. VérifierTOOLS.mdsi disponible. - NGC CLI & clé API — voir
references/ngc.md. Confirmer que$NGC_CLI_API_KEYest défini. - Prérequis système (pilote GPU, Docker, NVIDIA Container Toolkit, sysctls kernel) — vérifications complètes dans
references/prerequisites.md. La matrice matériel/pilote canonique est la page des prérequis VSS.
Vérification de pré-vol
Exécuter avant chaque déploiement. La liste complète des vérifications système et les étapes de correction se trouvent
dans references/prerequisites.md.
Pour DGX Spark / IGX Thor / AGX Thor, exécuter également la vérification du cache-cleaner dans
references/edge.md.
Détecter le mode sudo d'abord. Plusieurs remédiations de pré-vol et l'installateur du cache-cleaner d'edge appellent sudo. Si l'hôte nécessite un mot de passe sudo, ces étapes seront silencieusement no-op sous sudo -n et laisseront le déploiement dans un état semi-préparé.
if sudo -n true 2>/dev/null; then
echo "passwordless sudo — pre-flight will auto-install missing pieces"
else
echo "sudo requires password — pre-flight will NOT auto-install; hand commands to the user"
fi
Quand sudo a besoin d'un mot de passe, la skill ne doit pas exécuter elle-même les installateurs privilégiés. Présenter le bloc de commandes copier-coller depuis
references/prerequisites.md à l'utilisateur avec un handoff "exécuter ceci une fois et confirmer", puis reprendre après la réponse de l'utilisateur.
Test de fumée minimum (doit réussir) :
nvidia-smi --query-gpu=index,name --format=csv,noheader
docker info 2>/dev/null | grep -qi runtimes \
&& docker run --rm --gpus all ubuntu:22.04 nvidia-smi >/dev/null 2>&1 \
&& echo "nvidia runtime OK"
Si le test de fumée échoue, ne pas continuer ; ouvrir
references/prerequisites.md
pour l'arbre de correction.
Sélection de modèle
$LLM_REMOTE_URL/$VLM_REMOTE_URLsi l'utilisateur demande une configuration distante$NGC_CLI_API_KEY(NIMs locaux) ou$NVIDIA_API_KEY(distant)
Si aucune combinaison sur cet hôte ne satisfait aux exigences de dimensionnement du profil, arrêter et signaler le blocage — ne pas choisir silencieusement une autre forme.
Le mode partagé Edge est spécifique à la plateforme. Sur DGX Spark, exécuter
nvcr.io/nim/nvidia/nvidia-nemotron-nano-9b-v2-dgx-spark:1.0.0-varianten tant que NIM local standalone sur le port30081et pointer l'agent vers lui avecLLM_MODE=remote. Sur AGX/IGX Thor, continuer à utiliser le fallback vLLM standalone Edge 4B avecHF_TOKEN. Les recettes complètes sont dansreferences/edge.md.
Flux de déploiement
Toujours suivre cette séquence. Ne jamais ignorer le dry-run.
Étape 0 — Arrêter tout déploiement existant + effacer les volumes de données obsolètes
Si un déploiement existe déjà, l'arrêter ET effacer les volumes de données obsolètes avant de redéployer.
La procédure complète se trouve dans references/teardown.md.
Étape 0a — Barrière de credentials (exécuter avant toute mutation env)
Valider chaque credential que le profil choisi nécessite avant que l'étape 1c copie .env vers generated.env. Un 401 ici est un échec de 30 secondes ; le même 401 à l'intérieur d'un démarrage à froid NIM est un échec de 10–20 min. Exécuter le flux de découverte et de sonde dans references/credentials.md, puis mapper le résultat par rapport au mode choisi : les credentials requis manquants ou invalides sont des blocages, les credentials optionnels ne le sont pas.
Étape 1 — Collecter le contexte
Avant de construire les surcharges env, confirmer :
| Valeur | Comment déterminer |
|---|---|
| Profil | Faire correspondre l'intention de l'utilisateur à la table de routage ci-dessus. Par défaut : base |
| Chemin du repo | Trouver video-search-and-summarization/ sur le disque |
| Matériel | nvidia-smi --query-gpu=name,memory.total --format=csv,noheader |
| Placement LLM/VLM | Faire référence croisée des GPUs disponibles par rapport à la table Nombre minimum de GPU du profil choisi |
| Clés API | NGC_CLI_API_KEY pour les NIMs locaux, NVIDIA_API_KEY pour les distants |
HOST_IP |
hostname -I \| awk '{print $1}' — l'IP interne primaire de l'hôte |
EXTERNAL_IP |
Hôte/IP accessible par navigateur. Sur Brev, utiliser le domaine secure-link (voir references/brev.md). |
HAPROXY_PORT |
Port d'ingress accessible par navigateur. Par défaut 7777 ; s'assurer qu'il est libre. |
Avant docker compose up, vérifier que EXTERNAL_IP, HAPROXY_PORT, VSS_PUBLIC_HOST, et VSS_PUBLIC_PORT sont peuplés avec des valeurs accessibles par navigateur. Sinon, la stack peut sembler saine tandis que les liens UI/API/VST retournent 404 ou bouclent à travers Cloudflare Access.
Étape 1b — Préparer le répertoire de données
La disposition (chemins d'assets, propriété, points de montage, sous-répertoires spécifiques au profil) est documentée dans references/data-directory.md. Lire ce fichier avant de déployer pour la première fois sur un hôte ou lors du changement de profils.
INTERDIT :
chown -R ubuntu:ubuntu $VSS_DATA_DIR(ou tout chown récursif).C'est un « bon ménage » pour un instinct d'administrateur shell mais c'est la commande qui casse le déploiement de cette stack. Vous observerez un déploiement « sain » (conteneurs Up, endpoints 200) tandis que le pipeline vidéo est silencieusement cassé. Utiliser
chmod -R 777sur les sous-répertoires spécifiques documentés dansdata-directory.md— rien d'autre.
Étape 1c — Initialiser generated.env
La copie de travail par déploiement de la skill. Toujours commencer par une copie fraîche du .env source — ne jamais muter la source.
PROFILE=base
ENV_SRC=$REPO/deploy/docker/developer-profiles/dev-profile-$PROFILE/.env
ENV_GEN=$REPO/deploy/docker/developer-profiles/dev-profile-$PROFILE/generated.env
cp "$ENV_SRC" "$ENV_GEN"
Toutes les écritures ultérieures (Brev EXTERNAL_IP, le dict env_overrides de l'étape 2) vont vers $ENV_GEN. $ENV_SRC est en lecture seule à partir de maintenant.
Étape 1d — Si déploiement sur Brev, définir EXTERNAL_IP vers le domaine secure-link
Lire BREV_ENV_ID depuis /etc/environment et écrire EXTERNAL_IP dans generated.env (NON .env). Le comportement secure-link complet et le dépannage se trouvent dans references/brev.md.
brev_env_id=$(awk -F= '/^BREV_ENV_ID=/ {gsub(/"/, "", $2); print $2; exit}' /etc/environment)
sed -i "s|^EXTERNAL_IP=.*|EXTERNAL_IP=7777-${brev_env_id}.brevlab.com|" "$ENV_GEN"
Étape 2 — Construire env_overrides
Produire un dict env_overrides à partir de la demande utilisateur et du contexte collecté : choisir LLM/VLM distant/local, définir les credentials, pointer sur les endpoints, définir les drapeaux spécifiques à la plateforme. Le mapping complet (chaque clé de surcharge, quand elle s'applique, les défauts, les différences spécifiques au profil) se trouve dans references/env-overrides.md. Chaque référence de profil a des exemples travaillés pour les scénarios courants de ce profil.
Étape 3 — Appliquer les surcharges + dry-run
Fichier env de travail : <repo>/deploy/docker/developer-profiles/dev-profile-<profile>/generated.env (créé à l'étape 1c).
Deux fichiers env, rôles distincts.
.env— valeurs par défaut en lecture seule, engagées. Ne pas le muter depuis la skill.generated.env— la copie de travail par déploiement de la skill. Toutes les surcharges (le dict de l'étape 2, plus l'EXTERNAL_IPBrev de l'étape 1d) arrivent ici.--env-filepointe toujours sur ce fichier. Les vérificateurs post-déploiement doivent aussi lire depuisgenerated.envpour les valeurs réellement déployées — voir Déboguer un déploiement.
generated.envcorrespond à la convention quedev-profile.shutilise en interne — c'est un scratchpad par invocation régénéré parcp .env generated.envà chaque exécution.
# (L'étape 1c a déjà exécuté : cp $ENV_SRC $ENV_GEN)
# Apply the env_overrides dict from Step 2 to generated.env
# (read lines, update matching keys, append new keys, write)
# Example:
# sed -i "s|^LLM_MODE=.*|LLM_MODE=remote|" "$ENV_GEN"
# sed -i "s|^LLM_BASE_URL=.*|LLM_BASE_URL=http://localhost:30081|" "$ENV_GEN"
# Resolve compose
cd $REPO/deploy/docker
docker compose --env-file $ENV_GEN config > resolved.yml
Le YAML résolu est sauvegardé vers <repo>/deploy/docker/resolved.yml.
Étape 3b — Vérifier que resolved.yml n'a pas de tokens ${...} non-expandus
Les tokens ${VAR} non-expandus dans resolved.yml signifient que compose n'a pas vu ces valeurs env. La procédure diagnostique et les coupables courants se trouvent dans references/troubleshooting.md.
Étape 3c — Supprimer les depends_on optionnels pendants de resolved.yml
DOIT s'exécuter après l'étape 3, avant l'étape 5. Ignorer ceci abandonne le déploiement :
Normaliser - supprimer les dépendances optionnelles pour les services filtrés de resolved.yml
# From the repo root
uv run skills/vss-deploy-profile/scripts/normalize_resolved_yml.py "$REPO/deploy/docker/resolved.yml"
Si uv n'est pas sur l'hôte, l'installer une fois avec curl -LsSf https://astral.sh/uv/install.sh | sh (aucune root nécessaire).
Re-valider avant up -d :
docker compose -f "$REPO/deploy/docker/resolved.yml" config --quiet && echo "resolved.yml OK"
Si la validation échoue toujours après que le normaliseur s'exécute, capturer l'erreur et inspecter — c'est un bug différent (une dépendance qui n'est pas optionnelle, ou une autre violation de schéma), pas le cas dangling-depends_on.
Étape 4 — Vérifier
Montrer à l'utilisateur un résumé de ce qui sera déployé :
- Nom du profil et matériel
- Modèles LLM/VLM et mode (local/remote/local_shared)
- Services qui vont démarrer
- Attribution du périphérique GPU
- Endpoints clés (port UI, port agent)
Demander : "Ça a l'air bon — déployer maintenant ?" et attendre la confirmation avant l'étape 5.
Exception — mode autonome. Si la demande de l'utilisateur vous demande déjà d'exécuter de façon autonome (p.ex. "deploy X autonomously", "run without confirmation", "non-interactive"), ignorer le prompt de confirmation et procéder directement à l'étape 5. Ce chemin existe pour que les évals automatisés / invocations CI n'attendent pas une réponse humaine qu'ils n'obtiendront jamais. Dans tous les autres cas, un humain doit approuver.
Étape 5 — Déployer
cd $REPO/deploy/docker
docker compose --env-file $ENV_GEN -f resolved.yml up -d
--env-fileest obligatoire. Sans le mêmegenerated.envutilisé à l'étape 3,COMPOSE_PROFILESpeut être non-défini etup -dpeut quitter 0 avec zéro services sélectionnés.
Ne pas utiliser
--force-recreatesur les nouvelles tentatives. Cela détruit les conteneurs NIM déjà chauds, forçant un autre torch.compile + capture CUDA-graph de 3–5 min par NIM. Si leup -dprécédent a partiellement échoué, corriger la cause racine (généralement les perms ou une typo env) et simplement re-lancerup -d— Docker ne re-créera que les conteneurs dont la config a changé ou qui sont down.
docker compose up -d crée uniquement les conteneurs ; il n'attend pas que les services internes finissent de se réchauffer. Ne jamais déclarer le succès du déploiement jusqu'à ce que les barrières de disponibilité passent.
Étape 5b — Attendre jusqu'à ce que la stack soit réellement saine
Barrière 0 — le nombre de conteneurs doit être > 0. Refuser de continuer au-delà de up -d jusqu'à ce que compose ait lancé les services attendus :
expected=$(docker compose --env-file $ENV_GEN -f resolved.yml config --services | wc -l)
actual=$(docker compose -f resolved.yml ps -q | wc -l)
[ "$actual" -gt 0 ] && [ "$actual" -ge "$expected" ] \
|| { echo "FAIL: expected $expected services, got $actual — re-check Step 5 --env-file"; exit 1; }
Les déploiements à froid peuvent prendre 10–20 min. La procédure complète de disponibilité se trouve dans references/readiness.md, et chaque référence de profil liste les endpoints requis. Ne jamais déclarer le déploiement fait après up -d ; uniquement après que chaque endpoint documenté réussisse.
Arrêter
cd $REPO/deploy/docker
docker compose -f resolved.yml down
Pour passer de profil ou récupérer d'un déploiement partiel, suivre la procédure complète dans references/teardown.md.
Déboguer un déploiement
Utiliser ce workflow quand l'utilisateur demande de « déboguer le déploiement », « vérifier que ça fonctionne », « pourquoi l'agent ne répond pas », ou similaire. L'objectif est de confirmer le chemin complet ingestion-vidéo-vers-réponse-agent, pas simplement que les conteneurs sont « Up ».
Chaque référence de profil a une section Debugging listant les commandes exactes et la table des modes d'échec pour ce profil.
Vérifications rapides (tous les profils)
# 1. All expected containers Up
docker ps --format 'table {{.Names}}\t{{.Status}}'
# 2. Agent API + UI responding
curl -sf http://localhost:8000/docs >/dev/null && echo "agent OK"
curl -sf http://localhost:3000/ >/dev/null && echo "ui OK"
# 3. VLM NIM responding (base/lvs profiles)
curl -sf http://localhost:30082/v1/models | python3 -m json.tool
# 4. LLM NIM responding
curl -sf http://localhost:30081/v1/models | python3 -m json.tool
Vérification de santé vidéo bout en bout
Après que les vérifications rapides ci-dessus passent, piloter une requête réelle à travers l'agent — p.ex. lui demander via l'API REST ou l'UI de décrire une vidéo que vous avez uploadée vers VST. Si l'agent retourne une réponse non-vide, le chemin upload → ingest → inference → reply est sain. S'il échoue, docker logs vss-agent montre quelle étape a déclenché.
Exemples
- Profil base, modèles distants : router vers
base, copierdev-profile-base/.envversgenerated.env, définirLLM_MODE=remote/VLM_MODE=remote, dry-run, normaliser, déployer, puis vérifier/docset l'UI. - Profil search sur RTX : router vers
search, suivrereferences/search.mdpour le dimensionnement et les endpoints, ensemencer les vidéos, puis exécuter les vérifications de disponibilité du profil search. - Cible Edge : router via
references/edge.md, puis utiliser le même fluxgenerated.env→ dry-run → normalize → deploy.
Limitations
- Cette skill déploie uniquement les profils VSS basés sur compose ; le déploiement microservice standalone appartient à la skill
vss-deploy-*correspondante. - Le dimensionnement matériel, le placement de modèle, et la disponibilité spécifique au profil sont possédés par les références de profil ; ne pas les déduire de la mémoire.
- La correction matérielle privilégiée nécessite l'approbation utilisateur quand passwordless sudo n'est pas disponible.
Dépannage
Commencer par references/agent-failure-modes.md pour les échecs transversaux comme les timeouts de démarrage à froid NIM, OOM, réponses 5xx d'endpoint distant, NGC_CLI_API_KEY / HF_TOKEN manquants, valeurs non-expandues dans resolved.yml etc.