Configuration de l'environnement d'orchestration PAIDF
Préparez un environnement Kubernetes GPU pour l'orchestration PAIDF sans supposer un fournisseur de cloud. Traitez Kubernetes — et non le vendeur d'hôte — comme le contrat d'intégration.
Limite de sécurité
Commencez par un audit en lecture seule. Avant tout prepare, installation Helm, modification de connexion Airflow ou
mutation distante, résumez les modifications exactes et obtenez l'approbation de l'utilisateur. N'imprimez jamais kubeconfig,
clés NGC, tokens Hugging Face, secrets AWS, ou corps de Secret Kubernetes.
Sélectionnez deux axes indépendants
- Sélectionnez le placement du contrôleur : utilisez un contrôleur existant, ou déployez Airflow dans le cluster Kubernetes actuel.
- Sélectionnez le placement du service de modèle séparément : utilisez des endpoints VLM/LLM/image-edit externes, ou déployez ces services dans le cluster. Ne déduisez jamais un choix de l'autre.
- Préférez les endpoints externes sur un nœud H100 à un seul GPU. Le contrôleur et le worker d'augmentation peuvent toujours s'exécuter dans le cluster de ce nœud.
- Rejetez un hôte Docker uniquement ou SSH uniquement jusqu'à ce qu'une distribution Kubernetes supportée et le
plugin de périphérique NVIDIA exposent
nvidia.com/gpu.
Lisez topologies.md avant de modifier l'infrastructure.
Auditez le cluster de calcul
Le cluster est accessible uniquement via une kubeconfig que l'utilisateur fournit. Elle contient une adresse de cluster et des credentials d'administrateur, elle ne fait donc jamais partie du repository. Résolvez-la dans cet ordre :
- Utilisez
$KUBECONFIGs'il est déjà défini dans l'environnement. - Sinon demandez le chemin à l'utilisateur et exportez-le.
echo "${KUBECONFIG:-unset}" # ask the user for a path when this is unset
export KUBECONFIG=/path/the/user/gave
Ne devinez jamais un chemin, ne supposez pas un emplacement relatif au repository, et ne basculez pas vers ~/.kube/config. Si
le chemin que l'utilisateur nomme n'existe pas, dites-le et demandez à nouveau.
Exécutez localement quand l'agent dispose déjà de la kubeconfig (remote_k8s.py audit n'a pas
de flag --kubeconfig ; passez-le via la variable d'environnement) :
python scripts/remote_k8s.py audit --service-mode external --json
Sinon, passez-le inline via --kubectl-command :
python scripts/remote_k8s.py audit \
--kubectl-command "kubectl --kubeconfig $KUBECONFIG" \
--service-mode external --json
Exécutez via SSH quand les outils Kubernetes existent uniquement sur l'hôte distant :
python scripts/remote_k8s.py audit \
--ssh-target ubuntu@host \
--kubectl-command "kubectl" \
--service-mode external --json
remote_k8s.py est fourni avec cette compétence — exécutez-le depuis le répertoire de la compétence, pas depuis le répertoire
scripts/ du repository. Utilisez --kubectl-command "k3s kubectl" le cas échéant. Ne passez pas les mots de passe SSH
ou le contenu des clés privées dans le prompt ; utilisez la configuration SSH ou un agent.
Avant une installation Helm, l'audit se termine avec un code non zéro et le blocker
NGC image-pull secret is missing. C'est l'état normal de première installation, car le graphique
crée ce secret lui-même — lisez le bloc facts et continuez. Ne le résolvez pas avec
--create-registry-secret, qui fait échouer l'installation suivante sur les métadonnées de propriété.
Interprétez la capacité de manière conservatrice :
- Augmentation d'attributs d'image : Les endpoints externes ne déploient aucun service d'inférence dans le cluster, et les tâches d'augmentation et de recherche d'attributs vérifiées utilisent des profils CPU. Le mode interne déploie des services VLM, LLM et image-edit, chacun réclamant un GPU ; exigez au moins trois GPUs allocatables pour une replica de chacun, plus un pour chaque replica supplémentaire.
- Génération de vidéos d'événements : Les endpoints externes ne déploient aucun service d'inférence dans le cluster, mais les pods de tâches de détection/suivi, captioning et auto-labeling QA visuel chacun réclament un GPU quand actifs. Le mode interne a aussi besoin d'un GPU par replica VLM et LLM plus deux par replica image-to-video — au moins quatre GPUs allocatables pour une replica de chaque service.
- Un nœud à un seul GPU (par exemple, un H100) peut utiliser des endpoints de modèle externes, selon la capacité d'auto-labeling GPU de la génération de vidéos d'événements.
Le cluster de calcul est partagé. Les exécutions de DAG d'autres utilisateurs peuvent être actives dans le même namespace.
Signalez toujours les GPUs comme libre-versus-total (vérifiez les pods en cours d'exécution pour les demandes de GPU, pas seulement
l'allocatable du nœud), et n'émettez jamais de commandes destructrices larges (delete pods --all) contre le namespace de calcul sans d'abord
vérifier la propriété du pod via les labels dag_id et run_id.
Déployez un contrôleur sur le cluster actuel
Quand l'utilisateur demande la configuration (pas audit uniquement), confirmez quelles étapes exécuter avant de faire quoi que ce soit. Présentez les commandes exactes que vous prévoyez d'exécuter et obtenez une approbation explicite :
"Je vais exécuter les commandes suivantes dans l'ordre :
make setup— valide les secrets desecrets.envet génère les valeurs Helm pour l'installationmake install sdg-controller— empaquette les dépendances d'exécution Airflow, télécharge les DAGs et plugins vers S3, et installe/met à niveau la release HelmContinuer ?"
Il y a exactement deux cibles liées à l'installation : make setup et make install sdg-controller.
Il n'y a pas de bare make install et pas de make install nfs à moins que le stockage NFS ne soit aussi nécessaire (voir
Stockage ci-dessous).
Exécutez toujours make setup en premier sur tout déploiement, installation ou redéploiement — même si une exécution précédente a déjà
généré les valeurs Helm. Les secrets tournent ; make setup est bon marché et sûr. Sautez-le uniquement au milieu d'une session quand
l'agent lui-même vient de l'exécuter moments avant.
Namespace manquant — si kubectl get ns sdg-workflow retourne NotFound, c'est une condition de première installation normale,
pas une erreur à diagnostiquer. Naviguez directement vers make install sdg-controller.
make setup
C'est une étape légère de validation des secrets, pas un bootstrap complet de l'environnement. Elle :
- Lit
secrets.envà la racine du repository (copiezsecrets.env.exampleet remplissez les valeurs avant d'exécuter) ; - Valide que
NGC_API_KEY,HF_TOKEN, et toutes les credentials S3 AWS requises sont présentes ; - Génère les valeurs Helm utilisées par l'installation et actualise
secrets.envavec les valeurs normalisées.
Variables requises dans secrets.env :
| Variable | Objectif |
|---|---|
NGC_API_KEY |
Pulls d'images NGC et accès NVCF |
HF_TOKEN |
Téléchargements de modèles HuggingFace (mode service interne) |
AWS_S3_BUCKET |
Raccourci ; remplit les paramètres des buckets DAG, entrée et sortie |
AWS_S3_REGION |
Région du bucket S3 |
AWS_S3_ACCESS_KEY_ID |
Clé d'accès S3 |
AWS_S3_SECRET_ACCESS_KEY |
Clé secrète S3 |
Ce sont les variables que make setup valide. secrets.env.example expédie le raccourci unifié
AWS_S3_* ci-dessus, qui remplit les paramètres DAG, entrée et sortie de la même manière ; définissez plutôt les
variables AWS_S3_DAG_*, AWS_S3_INPUT_*, et AWS_S3_OUTPUT_* par objectif quand celles-ci
diffèrent.
KUBECONFIG est pas l'une d'elles et n'est pas dans secrets.env.example. make setup la lit
à partir de l'environnement, demande un chemin quand elle est non définie et le terminal est interactif, et
échoue quand elle est non définie de manière non-interactive. Exportez le chemin que l'utilisateur vous a donné avant d'exécuter :
export KUBECONFIG=/path/the/user/gave
make setup écrit alors ce chemin dans secrets.env pour les make install / make sync-dag ultérieurs.
make setup ne déploie pas Kubernetes, Docker, outils CLI, ou aucun logiciel système. Assurez-vous
que kubectl, helm, uv, docker, et aws (v2) sont déjà sur PATH avant d'exécuter.
make install sdg-controller
Cette cible effectue cinq étapes : empaquette les dépendances Python d'exécution Airflow du groupe verrouillé
airflow-runtime dans pyproject.toml/uv.lock, télécharge les DAGs, plugins et dépendances vers S3, exécute
helm dependency update, désinstalle toute release Helm antérieure, puis
helm upgrade --install dans le namespace sdg-workflow avec un délai d'expiration de 10 minutes.
Avant d'exécuter, vérifiez la connectivité S3 (l'installation échoue immédiatement à l'étape 2 si S3 est inaccessible) :
source secrets.env
# Redirect output to /dev/null so head-pipe doesn't mask aws exit code
aws s3 ls "s3://$AWS_S3_DAG_BUCKET/" --region "$AWS_S3_DAG_REGION" >/dev/null 2>&1 \
&& echo "S3 OK" \
|| echo "S3 UNREACHABLE — check credentials and network before proceeding with make install sdg-controller"
Exécutez chaque étape qui touche S3 dans un shell complètement en dehors du sandbox de l'agent. Cela s'applique à
make setup, make install sdg-controller, make sync-dag, et la pré-vérification ci-dessus. L'agent
les exécute lui-même — ne les confiez pas à l'utilisateur ; automatiser ce déploiement est tout l'intérêt
de la compétence.
La signature d'échec du sandbox est DNS, pas l'egress : le namespace réseau du sandbox n'a pas
de /etc/resolv.conf, donc rien sous amazonaws.com ne se résout — y compris l'endpoint régional générique,
pas seulement le sous-domaine du bucket.
fatal error: Could not connect to the endpoint URL: "https://<bucket>.s3.<region>.amazonaws.com/..."
curl: (6) Could not resolve host: s3.<region>.amazonaws.com # curl exits 6
getent hosts s3.<region>.amazonaws.com # returns nothing
Sur cette signature, escaladez vers un shell non-sandboxé et réessayez. Ne re-diagnostiquez pas les credentials, noms de buckets, ou régions — ce n'est pas la cause. Demander une permission réseau plus large seule n'aide pas : le sandbox rapportera un accès réseau sans restriction tandis que DNS échoue toujours, car le résolveur manquant est une propriété du namespace plutôt qu'une politique d'egress.
Après que l'invocation d'installation retourne — quel que soit son code de sortie, y compris une interruption ou un abandon — vérifiez toujours par rapport à l'état du cluster, qui est la seule source de vérité :
helm --kubeconfig "$KUBECONFIG" list -n sdg-workflow
kubectl --kubeconfig "$KUBECONFIG" get pods -n sdg-workflow
kubectl --kubeconfig "$KUBECONFIG" get pvc -n sdg-workflow
kubectl --kubeconfig "$KUBECONFIG" get events -n sdg-workflow --sort-by=.lastTimestamp | tail -20
Une invocation interrompue applique fréquemment toujours chaque modification. Interprétez les résultats comme :
| Signal | Signification |
|---|---|
Helm deployed, tous les pods contrôleur Running |
Succès — continuez |
Helm failed avec context canceled, pods Running |
Interrompu à mi-attente. Réexécutez make install sdg-controller pour réconcilier vers deployed. Ne lancez pas make uninstall |
Toute PVC Pending |
Problème de capacité ou de provisonneur — vérifiez get events ; les pods seuls paraîtront sains |
Pods ImagePullBackOff |
Secret de registre manquant ou clé NGC invalide |
L'installation prend environ 2–5 minutes sur un cache chaud et plus longtemps sur une première installation. Signalez une ligne de statut au fur et à mesure que chacune des cinq étapes se complète pour que l'utilisateur n'ait jamais à demander si c'est toujours en cours.
Pré-vérification de la capacité — le graphique demande ~536Gi de PVCs par défaut, 500Gi de modelCache. Sur un
hôte à nœud unique ou petit disque, cette réclamation ne peut jamais se lier, et comme aucun pod contrôleur ne la monte,
le déploiement entier paraît toujours sain :
df -h / # free space must exceed the sum of PVC requests in deploy/values.yaml
Réduisez modelCache.size, ou définissez modelCache.enabled: false quand chaque service de modèle est
externe et rien ne télécharge les modèles dans le cluster.
Points clés à énoncer à l'utilisateur avant d'exécuter :
- Oui, il télécharge les packages Python et les fichiers DAG vers S3, donc les credentials AWS et la connectivité S3 doivent être en place.
- Oui, il détruit le déploiement en cours en premier (Helm uninstall) avant la réinstallation.
- Les DAGs et plugins sont tirés de S3 par le dag-synchronizer plutôt que montés à partir de l'arborescence de travail locale ;
exécutez
make sync-dagaprès chaque modification des fichiers DAG. - Il ne pas construire ou pousser des images Docker ; les images de container sont tirées de NGC.
Ressources non gérées préexistantes : l'étape de désinstallation préserve les PVCs. Si le namespace contient des PVCs, Secrets, ou d'autres ressources non créées par une release Helm antérieure, Helm peut refuser d'installer. Supprimez-les d'abord, en confirmant avec l'utilisateur car les PVCs peuvent contenir les poids de modèle en cache.
Stockage
Voir Storage dans topologies.md pour la requirement de StorageClass nfs,
make install nfs, et le comportement de PVC de model-cache.
Préparez les prérequis de cluster manquants
Après approbation explicite, créez uniquement les ressources demandées. remote_k8s.py prepare lit
NGC_API_KEY à partir de l'environnement — utilisez set -a pour exporter les variables de secrets.env
avant d'exécuter, sinon source seule n'exporte pas vers les processus enfants :
set -a && source secrets.env && set +a # sets KUBECONFIG when `make setup` has already run
export KUBECONFIG=/path/the/user/gave # otherwise set it explicitly, after the source above
python skills/orchestration-setup/scripts/remote_k8s.py prepare \
--create-registry-secret
Le secret est envoyé comme un manifeste via stdin ; NGC_API_KEY n'apparaît jamais dans les arguments de commande ou
la sortie.
Ne pré-créez pas ngc-docker-registry-secret quand vous avez l'intention d'exécuter make install sdg-controller. Le graphique Helm gère ce secret lui-même, et un créé manuellement n'a pas
de métadonnées de propriété Helm, donc l'installation abandonne avant de déployer quoi que ce soit :
Error: unable to continue with install: Secret "ngc-docker-registry-secret" in namespace
"sdg-workflow" exists and cannot be imported into the current release: invalid ownership
metadata; label validation error: missing key "app.kubernetes.io/managed-by"...
Utilisez --create-registry-secret uniquement pour valider les credentials NGC par rapport à un cluster qui ne sera pas
géré par Helm. Si le conflit se produit, supprimez le secret et laissez Helm le recréer :
kubectl --kubeconfig "$KUBECONFIG" delete secret ngc-docker-registry-secret -n sdg-workflow
Pour les services internes, créez la PVC model-cache uniquement après avoir sélectionné une classe de stockage valide :
python scripts/remote_k8s.py prepare \
--create-registry-secret \
--create-model-cache-pvc \
--storage-class nfs \
--pvc-access-mode ReadWriteMany
prepare n'a pas de flag --kubeconfig (pas plus que audit) ; comme audit, il s'appuie sur l'ambient
kubectl qui récupère $KUBECONFIG de l'environnement.
N'installez pas automatiquement un opérateur GPU, plugin de périphérique, ou distribution Kubernetes. Signalez-les comme des prérequis d'infrastructure, car l'installation correcte est spécifique au fournisseur et à la distro.
Connectez le contrôleur SDG
Lisez controller-connection.md. Après l'installation, vérifiez en utilisant le token Airflow obtenu dans Connectez-vous au contrôleur déployé :
# 1. kubernetes_remote connection exists.
# It is injected as an env var, not stored in the metadata database, so
# GET /api/v2/connections/kubernetes_remote returns 404 on a healthy controller.
# Check the env var instead — a 404 here is not a failure.
kubectl exec -n sdg-workflow deploy/sdg-workflow-controller-scheduler -c scheduler -- \
printenv AIRFLOW_CONN_KUBERNETES_REMOTE >/dev/null 2>&1 \
&& echo "kubernetes_remote: present" \
|| echo "kubernetes_remote: MISSING"
# 2. Required pools have slots. default_pool is Airflow's built-in pool (not chart-created);
# the rest come from deploy/values.yaml airflowPools.pools and are workflow-specific — include
# every workflow you intend to run, not just one.
POOLS_JSON=$(curl -s -H "Authorization: Bearer $TOKEN" "$AIRFLOW_URL/api/v2/pools")
python3 -c "
import sys,json
required = ('k8s_gpu_1','default_pool',
'external_image_edit_service_pool','iaa_internal_image_edit_service_pool', # image-attribute-augmentation-workflow
'external_image2video_service_pool','internal_image2video_service_pool') # event-video-generation-workflow
pools = {p['name']: p for p in json.load(sys.stdin).get('pools',[])}
for n in required:
p = pools.get(n)
print(n, '- OK slots:', p['slots'] if p else 'MISSING')
" <<< "$POOLS_JSON"
# 3. The DAG(s) you intend to run are loaded and unpaused
IAA_DAG_JSON=$(curl -s -H "Authorization: Bearer $TOKEN" \
"$AIRFLOW_URL/api/v2/dags/image_attribute_augmentation_dag_k8s")
python3 -c "import sys,json; d=json.load(sys.stdin); print('is_paused:', d.get('is_paused'), '| found:', 'dag_id' in d)" <<< "$IAA_DAG_JSON"
EVG_DAG_JSON=$(curl -s -H "Authorization: Bearer $TOKEN" \
"$AIRFLOW_URL/api/v2/dags/event_video_generation_dag_k8s")
python3 -c "import sys,json; d=json.load(sys.stdin); print('is_paused:', d.get('is_paused'), '| found:', 'dag_id' in d)" <<< "$EVG_DAG_JSON"
# 4. Multistorage config secret exists
SECRET_JSON=$(kubectl get secret -n sdg-workflow multistorageclient-configuration-secret \
-o jsonpath='{.data}' 2>/dev/null)
if [ -n "$SECRET_JSON" ]; then
python3 -c "import sys,json; print('keys:', list(json.load(sys.stdin).keys()))" <<< "$SECRET_JSON"
else
echo "multistorageclient-configuration-secret NOT FOUND"
fi
Retournez controller readiness: unverified à moins que ceux-ci aient été vérifiés. Pour un contrôleur récemment déployé,
exécutez les quatre vérifications ci-dessus avant de rapporter prêt.
Connectez-vous au contrôleur déployé
Après que make install sdg-controller réussisse, établissez l'AIRFLOW_URL. L'adresse ClusterIP est
toujours routable depuis la machine hôte (même sans port-forward) et est le choix le plus fiable
pour l'utilisation par agent :
AIRFLOW_URL="http://$(kubectl get svc -n sdg-workflow \
sdg-workflow-controller-api-server \
-o jsonpath='{.spec.clusterIP}'):8080"
echo "AIRFLOW_URL=$AIRFLOW_URL"
Puis obtenez un token JWT. Les credentials sont dans deploy/values.yaml sous
airflow.createUserJob.defaultUser (défaut admin/admin — changez avant l'utilisation en production). Notez
que le chemin est createUserJob, pas webserver, qui n'existe pas dans ce graphique :
TOKEN=$(curl -s -X POST "$AIRFLOW_URL/auth/token" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}' \
| python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
test -n "$TOKEN" && echo "auth OK" || echo "auth FAILED"
Pour aussi exposer l'UI dans un navigateur depuis une autre machine, démarrez un port-forward. Il lie
0.0.0.0:8080 sur l'hôte, donc l'UI est accessible à l'adresse de l'hôte sur le port 8080 :
make port-forward # blocks until interrupted — run it in a terminal you own
HOST_IP=$(hostname -I | awk '{print $1}')
echo "Airflow UI: http://$HOST_IP:8080"
L'adresse ClusterIP Kubernetes et l'adresse réseau propre de l'hôte sont des espaces d'adresses séparés. L'adresse ClusterIP est routable depuis l'hôte mais n'est pas routable en externe ; l'adresse d'hôte via port-forward est ce qu'un navigateur sur une autre machine doit utiliser. Résolvez les deux au runtime — ne supposez jamais ni ne codez en dur l'une ou l'autre.
make port-forward ne se termine jamais. L'agent peut la démarrer en tant que travail d'arrière-plan en utilisant le mécanisme
de travail d'arrière-plan natif du harnais (pas un raw shell &) pour vérifier la connectivité ou servir un besoin de courte durée —
cela garde le shell réactif pour les commandes de suivi. Dites à l'utilisateur qu'elle s'arrêtera quand la session de l'agent se termine,
et préférez un terminal que l'utilisateur possède pour tout ce qui doit persister au-delà de cette conversation. Avant de démarrer
un nouveau forward, vérifiez et nettoyez tout processus make port-forward / kubectl port-forward ... 8080 antérieur égaré
pour qu'ils ne rivalisent pas pour le port :
ps -ef | grep "port-forward" | grep -v grep
kill <pid> # or kill -9 if it doesn't respond
Vérifiez avec une sonde bornée par rapport aux deux adresses :
curl -s -o /dev/null -w "%{http_code}\n" --max-time 5 http://localhost:8080
curl -s -o /dev/null -w "%{http_code}\n" --max-time 5 http://<host-ip>:8080
Pour mettre à jour les DAGs ou plugins après l'installation initiale sans réinstaller (le dag-synchronizer récupère les modifications S3 dans l'intervalle configuré, défaut 30 s) :
make sync-dag
Remise à la course d'augmentation
Produisez un rapport de disponibilité contenant la topologie, le contexte Kubernetes, le nombre de GPUs prêts,
le mode de service, l'URL Airflow, les ressources manquantes, les vérifications du contrôleur, et la remédiation sûre. Avant
de continuer vers une exécution de workflow, présentez les commandes d'installation planifiées (make setup, make install sdg-controller)
et attendez une approbation explicite — même si les pods contrôleur paraissent sains. Si la demande d'origine demande aussi
d'exécuter un workflow, continuez avec la procédure de compétence propre de ce workflow (par exemple
image-attribute-augmentation-workflow ou event-video-generation-workflow) uniquement après que l'utilisateur approuve ou
rejette les étapes d'installation et que la disponibilité du calcul et du contrôleur est établie ; ne demandez pas à l'utilisateur
de nommer ou de réinvoquer une autre compétence. Ne soumettez jamais un workflow uniquement parce que
kubectl get nodes réussit.