Aller au contenu
English

Cohérence des environnements

  • Leçon 1
  • 35 min
  • Module 1 : Comprendre les conteneurs
Leçon 1 sur 15 · L'essentiel de Docker et du nuage pour les développeurs en IACohérence des environnements

Ce que vous saurez faire

Comprenez pourquoi le même projet peut fonctionner sur un ordinateur et échouer sur un autre, même avec un fichier de verrouillage. Découvrez ensuite l’idée qui résout ce problème : regrouper tout l’environnement dans un paquet, une image, et l’exécuter partout.

Avant de commencerCe qu’il faut savoir et avoir sous la mainEnviron 35 minutes

Ce que vous devez savoir

Ce qu’il vous faut sur votre ordinateur

  • L’API de billets à la fin du cours Créer et déployer votre première API, dans ~/projects/ticket-api (Windows : $HOME\projects\ticket-api). Elle contient requirements-lock.txt et ticket_api/config.py. Si le projet manque ou ne fonctionne plus, copiez l’instantané end-of-m07 du cours Créer et déployer votre première API, comme dans Utiliser un instantané.
  • Vous n’avez pas besoin de Docker pour cette leçon. Vous l’installez dans Installer et vérifier : installer Docker. Ici, vous lisez les commandes d’Amira et leurs sorties réelles. La pratique guidée utilise seulement votre terminal.

Testé avec Docker Desktop 4.81.0 (Docker Engine 29.6.1) sur macOS, avec une puce Apple. Les étapes Windows et Linux ne sont pas testées.

Amira est responsable de ticket-api, l’API de billets de soutien du cours Créer et déployer votre première API. Son collègue Sam veut aussi l’exécuter. Sam a Python 3.12 sur un portable Windows. Amira a Python 3.14.6 sur un Mac avec une puce Apple. Sam clone le projet et crée un environnement virtuel. Ensuite, Sam installe les versions exactes du fichier de verrouillage, comme l’indique le README :

Sam's terminal (Windows PowerShell)
python -m pip install -r requirements-lock.txt

L’installation s’arrête à un paquet, uvloop. Sur Windows, pip ne trouve aucun paquet prêt à installer. Il essaie donc de le construire à partir du code source. La construction s’arrête avec le message d’uvloop :

The cause, from uvloop's setup.py (version 0.23.0)
RuntimeError: uvloop does not support Windows at the moment

Cette étape Windows n’est pas testée ici. La ligne ci-dessus est la vérification du code source d’uvloop qui arrête la construction. Amira peut montrer la cause sur son propre ordinateur. Elle demande à pip quels fichiers existent pour Windows et Python 3.12. Les options --platform et --python-version font chercher à pip les fichiers d’un autre ordinateur, sans rien installer. Elle exécute pip dans un conteneur, que vous découvrirez plus loin dans cette leçon :

Amira's terminal
docker run --rm python:3.14.8-slim-trixie pip download --disable-pip-version-check --no-deps --only-binary=:all: --platform win_amd64 --python-version 3.12 --dest /tmp/w uvloop==0.23.0

La sortie :

ERROR: Could not find a version that satisfies the requirement uvloop==0.23.0 (from versions: none)
ERROR: No matching distribution found for uvloop==0.23.0

La même question pour deux autres paquets du fichier de verrouillage, httptools==0.8.0 et watchfiles==1.3.0, donne un fichier Windows pour chacun (httptools-0.8.0-cp312-cp312-win_amd64.whl, watchfiles-1.3.0-cp310-abi3-win_amd64.whl). Seul uvloop n’en a aucun.

Pourquoi uvloop se trouve-t-il dans le fichier de verrouillage? fastapi[standard] installe Uvicorn, le serveur. Uvicorn demande uvloop seulement sur les systèmes autres que Windows : uvloop accélère le serveur sur Linux et macOS. Amira a créé le fichier de verrouillage avec pip freeze sur son Mac. pip freeze écrit ce qui est installé sur cet ordinateur. La liste du Mac contient donc uvloop :

Amira's terminal
grep uvloop requirements-lock.txt
Sortie
uvloop==0.23.0

Le fichier de verrouillage convient au Mac d’Amira. Il ne convient pas au portable de Sam. Personne n’a fait d’erreur : les deux ordinateurs ont des environnements différents.

Sans conteneur : le Mac d'Amira contient le code ticket_api, les paquets du fichier de verrouillage, Python 3.14.6 et macOS sur une puce Apple. L'API démarre. Le portable de Sam contient le même code, mais uvloop ne peut pas s'installer. Python 3.12 et Windows 11 sont différents, et l'installation s'arrête. Avec un conteneur : une seule image en lecture seule contient le code ticket_api, les paquets aux versions exactes, Python 3.14.8 et les fichiers Linux de Debian 13. docker run la démarre sur le Mac d'Amira et sur le portable de Sam. Elle fonctionne sur les deux.
Sans conteneur, chaque ordinateur a son propre environnement. Avec un conteneur, les deux ordinateurs exécutent la même image.
Description textuelle du diagramme

La partie gauche montre deux ordinateurs sans conteneur. Le Mac d’Amira contient quatre parties : le code ticket_api, les paquets du fichier de verrouillage, Python 3.14.6 et macOS sur une puce Apple. L’API démarre. Le portable de Sam contient le même code, mais trois parties diffèrent. uvloop ne peut pas s’installer, Python est à la version 3.12 et le système est Windows 11. L’installation s’arrête. La partie droite montre une image avec le code, les versions exactes des paquets, Python 3.14.8 et les fichiers de Debian 13, un système Linux. docker run démarre la même image sur les deux ordinateurs, et elle fonctionne sur les deux.

L’environnement d’un programme comprend tout ce qui entoure son code et change la façon dont il s’exécute. Pour l’API de billets, il comporte cinq parties :

Partie Exemple pour l’API de billets Ce que les cours Python pour l’ingénierie de l’IA en pratique et Créer et déployer votre première API ont fait
Le système d’exploitation et ses bibliothèques macOS, Windows ou un système Linux comme Debian ou Ubuntu Rien
L’interpréteur Python 3.14.6 ou Python 3.12 requires-python = ">=3.12" dans pyproject.toml : une plage, pas une seule version
Les paquets FastAPI 0.142.2, Uvicorn, uvloop L’environnement virtuel les isole. Le fichier de verrouillage fixe leurs versions.
Les paramètres API_KEY, SHOW_DOCS, CLASSIFIER_MODE Des variables d’environnement, lues dans config.py
Les fichiers Le code ticket_api. Plus tard, un fichier de modèle. Git

Le fichier de verrouillage fixait seulement une partie, les paquets, et seulement pour un type d’ordinateur. Le système d’exploitation et la version de Python différaient encore d’un ordinateur à l’autre. Un serveur ajoute un troisième environnement, généralement Linux, que ni Amira ni Sam n’utilisent.

Le problème prend de l’ampleur avec les services d’IA. Les paquets d’apprentissage automatique ont souvent une version compilée différente pour chaque système d’exploitation et chaque type de processeur. Un cours ultérieur, Déployer des modèles d’IA pour de vrais utilisateurs, place un modèle entraîné dans le même type de paquet. Chaque copie de l’environnement doit aussi contenir ce fichier de modèle, dans la bonne version exacte.

La solution consiste à regrouper l’environnement dans un paquet, pas seulement à le décrire.

  • Une image est un paquet qui contient un programme et tout ce qu’il lui faut pour s’exécuter. Elle contient les fichiers d’un petit système Linux, l’interpréteur, les paquets et le code. Personne ne peut modifier une image après sa création par Docker. Elle contient aussi quelques informations sur le démarrage du programme, comme sa commande de démarrage.
  • Un conteneur est une copie d’une image en cours d’exécution. Docker démarre le programme de l’image comme un processus. Il donne à ce processus sa propre vue des fichiers, du réseau et des autres processus. Vous pouvez démarrer plusieurs conteneurs à partir d’une image.
  • Docker est l’outil qui construit les images et exécute les conteneurs. Vous tapez des commandes docker dans le terminal. Elles vont à Docker Engine, un programme qui fait le travail.
  • Un registre est un serveur qui stocke des images pour que d’autres personnes et serveurs puissent les télécharger. Docker Hub est le registre public par défaut. Vous utilisez des images de Docker Hub dans ce module et envoyez votre propre image à un registre au module 5.

Les paramètres sont la seule partie qui reste hors de l’image. La même image s’exécute sur le Mac d’Amira avec une clé de test, et sur un serveur avec la vraie clé. Au module 3, vous donnez ses paramètres à un conteneur au démarrage.

Les fichiers sources (Dockerfile, ticket_api, requirements-run.txt) passent par docker build, au module 2, pour produire une image. Un registre, Docker Hub, contient des images construites par d'autres personnes. docker pull permet d'en obtenir une image. L'image contient des couches en lecture seule et une commande de démarrage. docker run démarre le conteneur 1 et le conteneur 2 à partir de l'image. Chaque conteneur est un processus en cours d'exécution avec sa propre couche accessible en écriture.
Une image provient de vos fichiers sources (docker build) ou d'un registre (docker pull). Chaque docker run démarre un nouveau conteneur à partir de cette image.
Description textuelle du diagramme

Une image peut venir de deux endroits. Vous la construisez à partir de fichiers sources avec docker build : un Dockerfile, le code ticket_api et la liste des paquets. Vous le faites au module 2. Ou vous la téléchargez d’un registre comme Docker Hub avec docker pull : une image construite par quelqu’un d’autre. L’image contient des couches en lecture seule et une commande de démarrage. Chaque docker run démarre un nouveau conteneur à partir de l’image. Un conteneur est un processus en cours d’exécution avec sa propre couche accessible en écriture. Le conteneur 1 et le conteneur 2 ne partagent donc pas leurs modifications.

Exemple détaillé : la même image sur chaque ordinateur

Section intitulée « Exemple détaillé : la même image sur chaque ordinateur »

Amira compare son Mac à un conteneur. D’abord, son Mac :

Amira's terminal
python3 --version
uname -sm

uname -sm affiche le nom du système d’exploitation et le type de processeur. La sortie :

Python 3.14.6
Darwin arm64

Darwin est le noyau de macOS. arm64 est le type de processeur des puces Apple. Ensuite, elle pose les mêmes questions dans un conteneur créé à partir de l’image officielle Python :

Amira's terminal
docker run --rm python:3.14.8-slim-trixie sh -c 'python --version; uname -sm; grep PRETTY_NAME /etc/os-release'

La sortie :

Python 3.14.8
Linux aarch64
PRETTY_NAME="Debian GNU/Linux 13 (trixie)"

Dans le conteneur, le système est Linux (Debian 13, appelé « trixie »), avec Python 3.14.8, sur le même Mac. aarch64 est le nom utilisé par Linux pour arm64. Sur le portable de Sam, la même commande affiche la même version de Python et la même version de Debian. Seul le nom du processeur peut différer : un portable Intel ou AMD affiche x86_64. Installer et vérifier explique cette différence.

Le nom python:3.14.8-slim-trixie comprend un nom d’image et une étiquette. python est l’image. L’étiquette après le deux-points choisit une version : Python 3.14.8, la variante légère (« slim »), sur Debian trixie.

Le cours Créer et déployer votre première API présentait les cinq tâches de toute plateforme d’hébergement. Il indiquait que Docker les décrit autrement. Voici la correspondance. Vous apprenez chaque partie dans ce cours :

Étape de la plateforme Avec Docker Où dans ce cours
Construire : installer Python et les dépendances Un Dockerfile et docker build créent une image Module 2
Démarrer : exécuter la commande de démarrage Le CMD de l’image Module 2
Écouter : envoyer des requêtes à l’application sur un port EXPOSE dans l’image et -p au démarrage du conteneur Module 3
Configurer : donner ses paramètres à l’application -e, un fichier d’environnement ou un fichier de secrets, au démarrage du conteneur Module 3
Maintenir en marche : HTTPS, redémarrages, journaux docker logs sur votre ordinateur; une plateforme de conteneurs dans le nuage Modules 3 et 5

Avec un conteneur, vous faites vous-même l’étape de construction, une seule fois, sur votre ordinateur. La plateforme exécute ensuite seulement l’image. Le résultat est le même sur votre ordinateur, sur celui de Sam et sur le serveur.

Pratique guidée : dresser la liste de votre environnement

Section intitulée « Pratique guidée : dresser la liste de votre environnement »

Cette pratique ne nécessite pas Docker. Vous notez les cinq parties de l’environnement de votre ordinateur, comme Amira.

  1. Ouvrez un terminal dans le dossier du projet ~/projects/ticket-api.

  2. Affichez la version de Python.

    Fenêtre de terminal
    python3 --version

    Résultat attendu : une ligne, comme Python 3.14.6.

  3. Affichez le système d’exploitation et le processeur.

    Fenêtre de terminal
    uname -sm

    Résultat attendu : par exemple, Darwin arm64 sur un Mac avec une puce Apple, Linux x86_64 sur la plupart des ordinateurs Linux, ou un nom Windows et AMD64 sur Windows.

  4. Cherchez uvloop dans le fichier de verrouillage.

    Fenêtre de terminal
    grep uvloop requirements-lock.txt

    Résultat attendu : uvloop==0.23.0 si le fichier a été créé sur macOS ou Linux. Aucune ligne s’il a été créé sur Windows.

  5. Ouvrez ticket_api/config.py et notez chaque paramètre lu avec os.environ.get.

  6. Notez les cinq parties dans un petit tableau : système d’exploitation, interpréteur, paquets, paramètres, fichiers.

Afficher un exemple de réponse (le Mac d’Amira)
Partie Le Mac d’Amira
Système d’exploitation macOS (Darwin), puce Apple (arm64)
Interpréteur Python 3.14.6
Paquets Les 63 lignes de requirements-lock.txt, avec uvloop==0.23.0
Paramètres ALLOWED_ORIGINS, API_KEY, CLASSIFIER_MODE, CLASSIFIER_TIMEOUT, LOG_LEVEL, SHOW_DOCS
Fichiers Le dossier ticket_api, pyproject.toml

Seuls les paquets sont fixés par un fichier du projet. Le système d’exploitation et la version de Python sont ceux de cet ordinateur.

Un nouveau collègue a un portable Linux avec un processeur Intel et Python 3.13. Utilisez votre tableau de l’exercice guidé. Quelles parties de l’environnement diffèrent de celles du Mac d’Amira? Le fichier de verrouillage peut-il en fixer certaines? Est-ce qu’uvloop s’installe? (uvloop 0.23.0 offre des paquets Linux prêts à installer pour Python 3.13 sur les processeurs Intel et AMD.)

Afficher la réponse

Trois parties diffèrent : le système d’exploitation (Linux, pas macOS), le processeur (x86_64, pas arm64) et l’interpréteur (3.13, pas 3.14.6). Le fichier de verrouillage n’en fixe aucune : il fixe seulement les versions des paquets. uvloop s’installe, car un paquet Linux existe pour Python 3.13. L’installation fonctionne donc probablement, mais cela reste un troisième environnement. Un bogue lié à la version de Python ou au système peut encore apparaître uniquement sur ce portable. Une image élimine cette question : les trois personnes exécutent Python 3.14.8 sur Debian 13.

Erreur courante

Modifier le fichier de verrouillage jusqu'à ce que l'installation fonctionne

Symptôme : Sam supprime la ligne uvloop==0.23.0 de requirements-lock.txt. L’installation fonctionne, les tests passent et Sam enregistre le fichier modifié dans un commit (une modification enregistrée). Quelques semaines plus tard, le serveur fonctionne sans uvloop, sans que personne l’ait décidé.

Cause : le fichier de verrouillage décrit maintenant le portable de Sam, pas le serveur. Uvicorn utilise uvloop quand il est installé, et la boucle d’événements standard, plus lente, quand il ne l’est pas. L’environnement du serveur a donc changé à cause du portable d’une seule personne. Un fichier de verrouillage créé sur un système d’exploitation est une liste pour ce système d’exploitation.

Solution :

  1. Ne modifiez pas un fichier de verrouillage à la main pour faire fonctionner l’installation. Rétablissez la ligne avec git restore requirements-lock.txt.
  2. Créez la liste des paquets sur le même type de système que celui qui exécute le service. Dans le module 2, vous créez requirements-run.txt dans un conteneur Linux. C’est donc la liste pour l’image Linux.
  3. Sur votre propre ordinateur, utilisez l’image pour exécuter le service. Utilisez votre environnement virtuel seulement pour écrire du code et exécuter les tests.

Pour un vrai service d’IA : des paquets comme PyTorch ont une version compilée différente pour chaque système d’exploitation, processeur et carte graphique. Une liste créée sur un portable est souvent inadéquate pour le serveur. L’image est l’endroit où la liste du serveur est exacte.

Vérifiez votre compréhension

Le fichier de verrouillage d'Amira fixe la version de chaque paquet. Quelles parties de l'environnement ne fixe-t-il pas?

Afficher la réponse

Il ne fixe ni le système d’exploitation et ses bibliothèques, ni la version de Python. Ceux-ci dépendent de ce qui est installé sur l’ordinateur. Il ne fixe pas non plus les paramètres, et il ne devrait pas le faire. Les paramètres changent volontairement entre les ordinateurs : une clé de test sur un portable, la vraie clé sur le serveur. Il fixe aussi les paquets seulement pour le type d’ordinateur qui l’a créé. La liste du Mac contient uvloop, que Windows ne peut pas installer.

Vérifiez votre compréhension

Faites une prédiction : Sam installe Docker sur le portable Windows et exécute docker run --rm python:3.14.8-slim-trixie python --version. Qu'affiche cette commande, et pourquoi n'est-ce pas Python 3.12?

Afficher la réponse

Elle affiche Python 3.14.8. La commande exécute le Python de l’image, pas celui qui est installé sur le portable de Sam. L’image contient ses propres fichiers système Linux et son propre Python 3.14.8. Chaque ordinateur qui exécute cette image utilise donc la même version.

Vérifiez votre compréhension

Quelle partie de l'environnement reste hors de l'image, et pourquoi?

Afficher la réponse

Les paramètres, comme API_KEY et SHOW_DOCS. La même image doit fonctionner sur un portable avec une clé de test. Elle doit aussi fonctionner sur un serveur avec la vraie clé et sans documentation. Si un paramètre est dans l’image, vous avez besoin d’une image différente pour chaque environnement. Et toute personne qui possède l’image peut lire un secret qu’elle contient. Le module 3 fournit les paramètres au conteneur à son démarrage.

Récapitulatif

  • Un environnement comprend cinq parties : le système d’exploitation et ses bibliothèques, l’interpréteur, les paquets, les paramètres et les fichiers.
  • Un fichier de verrouillage fixe seulement les versions des paquets, et seulement pour le type d’ordinateur où il a été créé. La liste du Mac d’Amira contient uvloop, que Windows ne peut pas installer.
  • Une image contient toutes les parties sauf les paramètres. Un conteneur est une copie d’une image en cours d’exécution. Docker construit des images et exécute des conteneurs. Un registre stocke les images.
  • Docker décrit les cinq étapes liées à la plateforme du cours Créer et déployer votre première API : construire, démarrer, écouter, configurer, maintenir en exécution.

Ensuite, vous explorez le contenu d’une image et exécutez vos premiers conteneurs. Vous voyez quelles modifications un conteneur conserve et lesquelles il perd.

Leçon suivante : Images et conteneurs en cours d'exécution