Aller au contenu principal

Module 4 — Environnements et images conteneurisées

Les données sont prêtes. Reste à décrire l'univers dans lequel elles seront traitées : version de Python, bibliothèques, éventuel binaire système. Azure ML matérialise cette description sous forme d'environment — un objet versionné qui produit, à l'usage, une image de conteneur stockée dans l'Azure Container Registry (ACR) du workspace. C'est cette image qui tourne sur les grappes du module 2, à l'identique en dev et en production.

Deux familles à ne pas confondre

Azure ML expose deux catégories d'environnements :

  • Environnements organisés (curated) : maintenus par Microsoft, préconstruits, préfixe AzureML-. Exemples utiles : AzureML-sklearn-1.5, AzureML-tensorflow-2.16-cuda12, AzureML-pytorch-2.4-cuda12. Ils tirent instantanément et couvrent la plupart des besoins standard.
  • Environnements personnalisés (custom) : construits à partir d'un fichier conda.yml, d'un Dockerfile, ou d'une combinaison des deux. À utiliser dès qu'une bibliothèque, une version ou un binaire système sort du standard.

Pour le fil rouge, un environnement organisé AzureML-sklearn-1.5 suffirait au modèle de base. Mais nous voulons xgboost en version précise et mlflow avec pyfunc, ce qui pousse à un environnement personnalisé.

Le fichier conda.yml : lisible et suffisant dans 80 % des cas

name: env-prev-demande
channels:
- conda-forge
dependencies:
- python=3.11
- pip=24.2
- pip:
- scikit-learn==1.5.2
- xgboost==2.1.1
- pandas==2.2.3
- pyarrow==17.0.0
- mlflow==2.16.2
- azureml-mlflow==1.57.0

Deux règles à graver :

  • Toutes les versions sont épinglées avec ==. Un xgboost sans version installe la dernière compatible, différente demain, et la reproductibilité s'évapore.
  • La bibliothèque azureml-mlflow doit apparaître dès qu'on veut que les journaux MLflow remontent au workspace. Sans elle, le suivi tourne mais n'atterrit nulle part.

L'enregistrement est atomique :

az ml environment create --name env-prev-demande --version 1 \
--conda-file conda.yml \
--image mcr.microsoft.com/azureml/openmpi5.0-ubuntu22.04:latest

L'image de base est une image Ubuntu fournie par Microsoft, avec les pilotes CUDA le cas échéant. Le fichier conda.yml s'y superpose.

Passer au Dockerfile : quand et pourquoi

Un fichier conda.yml ne peut pas installer un binaire système comme libgeos-dev. Le passage au Dockerfile s'impose dès que le projet a une dépendance native :

FROM mcr.microsoft.com/azureml/openmpi5.0-ubuntu22.04:latest

RUN apt-get update && apt-get install -y --no-install-recommends \
libgeos-dev libspatialindex-dev \
&& rm -rf /var/lib/apt/lists/*

COPY conda.yml /tmp/conda.yml
RUN conda env update --name base --file /tmp/conda.yml \
&& conda clean -afy
az ml environment create --name env-prev-demande --version 2 \
--build-context ./env/ --dockerfile-path Dockerfile

Azure ML construit l'image dans le cloud (build context) puis la publie dans l'ACR du workspace. La première construction prend 6 à 12 minutes ; les suivantes, si le Dockerfile ne change pas de ligne, bénéficient du cache de couches et prennent quelques secondes.

Versionnage strict : jamais de mutation

Un environnement enregistré est immuable. Modifier une dépendance impose une nouvelle version.

az ml environment create --name env-prev-demande --version 3 \
--conda-file conda.yml

Cette contrainte est structurante. Elle protège la reproductibilité des tâches passées : rejouer la tâche du 12 janvier avec env-prev-demande:1 produira exactement la même image, même si xgboost 2.1.1 a été depuis retiré de PyPI. C'est ce qui distingue Azure ML d'un pip install pris à la volée dans un notebook.

L'environnement non versionné, faux ami

Certains guides suggèrent d'utiliser --set-default-version ou de référencer azureml:env-prev-demande@latest dans les tâches. Cela fonctionne — jusqu'au jour où quelqu'un pousse une version 4 et où la production casse silencieusement à la prochaine exécution planifiée. La règle est : dans une définition de tâche de production, toujours référencer azureml:env-prev-demande:3, avec le numéro explicite. L'alias latest n'est qu'un outil de développement.

Construction et cache : quelques gestes qui accélèrent

  • Ordonner le Dockerfile du moins volatil au plus volatil : couches système d'abord, conda.yml ensuite, code applicatif jamais dans l'image d'environnement (le code voyage avec la tâche)
  • Verrouiller également les versions apt dans les cas critiques (libgeos-dev=3.12.1-3build1) pour les projets qui ont vécu la mise à jour surprise d'une dépendance native
  • Purger l'espace disque de conda dans une seule couche (conda clean -afy en fin de RUN) pour ne pas gonfler l'image
  • Éviter les images de base publiques non-Microsoft : elles ne sont pas garanties de contenir les paquets attendus par les points de terminaison en ligne du module 8

En résumé

  • Curated pour un besoin standard, custom dès qu'une version précise ou un binaire système est en jeu
  • Épingler toutes les dépendances Python et inclure azureml-mlflow pour que le suivi remonte
  • Un Dockerfile avec cache de couches pour les dépendances système ; le code applicatif reste hors image
  • Toujours référencer un numéro de version explicite en production, jamais latest ou @latest

Le module suivant lance la première tâche d'entraînement dans cet environnement et fait remonter les journaux via MLflow.