Aller au contenu

Construire une chaîne

Le chemin tient en cinq étapes, avant de déployer la chaîne. Prenez le temps de valider chacune avant d'attaquer la suivante : c'est fastidieux sur le moment, mais cela vous évite de chercher une erreur dans trois couches à la fois, sans savoir si le problème vient du script, de l'image ou du CWL.

Dans la documentation AntFlow

1. Un script à interface propre

Commencez par un script qui tourne seul, hors de tout CWL. C'est votre seul terrain de débogage confortable : une fois la chaîne sur la plateforme, vous n'avez plus que des journaux.

Quatre exigences, qui découlent toutes de la façon dont le moteur appelle votre script :

  • Entrées et sorties en arguments, jamais codées en dur - le CWL ne peut piloter que ce qui est paramétrable.
  • Sorties écrites dans le répertoire courant, en chemins relatifs. Le moteur crée un répertoire de travail par étape et vient y récupérer les sorties ; un chemin absolu écrit en dehors, et le fichier est simplement perdu.
  • Un code de retour non nul en cas d'échec (sys.exit("message")). C'est le seul signal d'erreur que voit le moteur : un script qui échoue en silence avec un code 0 fait passer l'étape pour un succès, et le workflow continue sur des données absentes.
  • Aucune interaction ni affichage graphique : personne ne répondra à une invite, et il n'y a pas d'écran.

2. Conteneuriser

L'image embarque le code et ses dépendances. C'est un changement de point de vue utile : votre script n'est pas une donnée que le workflow transporte, il fait partie de l'outil, au même titre que les bibliothèques qu'il utilise.

FROM python:3.11-slim
RUN pip install --no-cache-dir rasterio boto3
WORKDIR /app
COPY mon_traitement.py /app/
ENV PATH="/app:${PATH}"

Trois précautions à la construction :

  • Taguez une version, jamais latest. Sans tag explicite, l'exécution n'est plus reproductible et la plateforme peut servir une image en cache qui n'est pas la vôtre.
  • Placez le code à un chemin absolu dans l'image (/app/…), pour que baseCommand ne dépende pas du répertoire de travail du moment.
  • N'y mettez aucun identifiant : une image se partage et se télécharge.

Avant d'écrire la moindre ligne de CWL, vérifiez que le script tourne dans le conteneur :

docker run --rm -v "$PWD:/data" -w /data <image> python3 /app/mon_traitement.py entree.tif sortie.tif

Si ça échoue à ce stade, le CWL n'y est pour rien, et il est bien plus rapide de corriger ici que dans une chaîne complète.

3. Publier l'image

La marche à suivre est dans Utiliser la registry. Retenez seulement que le nom de l'image doit reprendre le chemin du projet GitLab (registry.gitlab.com/<groupe>/<projet>:<tag>) : la registry refuse tout autre nom.

Partage du projet

Le groupe urbiverde-if-pathfinder doit être invité en Maintainer. Sans ce partage, l'image reste privée et la plateforme échoue au pull - l'erreur apparaît à l'exécution, pas à la validation du CWL.

Aperçu du service

Une image référencée dans le README.md du projet sert d'aperçu dans la plateforme : ![preview](./preview.png).

4. Écrire les CommandLineTool

Vient ensuite la description CWL proprement dite. Écrivez un tool par script : son rôle se limite à dire comment appeler le script - quels arguments, quelle image, quelles ressources, et quels fichiers récupérer ensuite.

cwlVersion: v1.2
class: CommandLineTool
label: Calcul d'indicateur        # affiché dans AntFlow

baseCommand: [python3, /app/mon_traitement.py]

requirements:
  DockerRequirement:
    dockerPull: registry.gitlab.com/<groupe>/<projet>:0.1.2
  ResourceRequirement:
    ramMin: 1024
    ramMax: 3026
    coresMin: 1
    coresMax: 2

inputs:
  entree:
    type: File
    inputBinding:
      position: 0

arguments:
  - position: 1
    valueFrom: sortie.tif

outputs:
  produit:
    type: File
    outputBinding:
      glob: sortie.tif

stdout: stdout.txt                  # journal capturé, précieux en cas d'échec

Avant de passer à la suite, relisez votre tool avec cette liste - chaque ligne correspond à une erreur courante :

  • [ ] DockerRequirement avec une image publiée et taguée
  • [ ] baseCommand en chemin absolu dans l'image
  • [ ] NetworkAccess: true si l'étape sort du conteneur (S3, API)
  • [ ] ResourceRequirement dès que l'étape charge des données en mémoire
  • [ ] glob correspondant réellement à ce que le script écrit
  • [ ] label et doc renseignés - c'est ce que lit l'utilisateur d'AntFlow

5. Assembler le workflow

Le workflow est l'enveloppe qui relie vos tools. C'est aussi là que se joue l'essentiel de l'adaptation à la plateforme : il expose des entrées qu'AntFlow sait alimenter, puis les convertit en ce dont les tools ont réellement besoin.

cwlVersion: v1.2
class: Workflow
label: Calcul d'indicateur

requirements:
  # hérité par toutes les étapes : sinon les conteneurs tournent en --net=none
  NetworkAccess:
    networkAccess: true
  InlineJavascriptRequirement: {}

inputs:
  entree_path:
    type: string                    # string, pas File : contrainte AntFlow
    label: Chemin S3 du fichier d'entrée
    default: "s3://<votre-bucket>/donnees/entree.tif"
  s3_config:
    type: string
    label: Configuration S3 au format JSON

outputs:
  produit:
    type: File
    outputSource: traitement/produit

steps:
  stage_in:                         # string -> Directory
    run: stage_in.cwl
    in:
      entree_path: entree_path
      s3_config: s3_config
    out: [donnees]

  traitement:                       # Directory -> produit
    run: mon_traitement.cwl
    in:
      entree: stage_in/donnees
    out: [produit]

Quatre règles d'assemblage à garder en tête :

  • Déclarez les entrées en string, jamais en File - Contraintes de la plateforme explique pourquoi ce point est décisif.
  • Placez les requirements communs au niveau du workflow : ils sont hérités par les étapes, inutile de les répéter dans chaque tool.
  • Renseignez default quand une valeur est raisonnable : l'utilisateur a alors un formulaire pré-rempli et exécutable tel quel.
  • label sur chaque étape : c'est ce qui s'affiche dans le graphe AntFlow.

Valider

cwltool --validate mon_workflow.cwl              # syntaxe et câblage
cwltool --outdir ./out mon_workflow.cwl job.json # exécution complète

Ne vous fiez pas à --validate seul : il vérifie la syntaxe et le câblage, mais ne détecte ni une image absente, ni un glob qui ne correspond à aucun fichier. Seule l'exécution complète le montre. Et tant qu'à faire, testez contre un MinIO local avant de viser le S3 de production.

Ce qu'un test local ne verra jamais

Reste une limite qu'il faut connaître : cwltool est plus permissif que la plateforme. Un workflow parfaitement vert sur votre poste peut échouer en production, et toujours sur les mêmes points :

Point Pourquoi ça passe en local
Fichiers intermédiaires En local ils circulent librement entre étapes ; sur la plateforme, seule une sortie déclarée traverse.
Accès à l'image Elle est en cache local, mais peut-être pas accessible à la plateforme.
Mémoire En local, toute la RAM de la machine ; sur la plateforme, plafonné et tué en silence au-delà.
Secrets cwltool:Secrets masque la valeur localement, mais c'est sur la plateforme qu'elle est alimentée depuis le compte.

Aucun de ces quatre points ne se détecte en exécutant le workflow chez vous : ils se vérifient par relecture du CWL.