Aller au contenu
English

Construire efficacement

  • Leçon 5
  • 50 min
  • Module 2 : Construire l'image de l'application

Ce que vous saurez faire

Accélérez chaque reconstruction, n’envoyez aucun fichier secret ou volumineux à la construction et produisez la même image chaque fois. Après un changement de code, la reconstruction prend moins d’une seconde au lieu de 15. L’image est aussi 54 Mo plus petite.

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

Ce que vous devez savoir

Ce qu’il vous faut sur votre ordinateur

Testé avec Docker Desktop 4.81.0 (Docker Engine 29.6.1) sur macOS, avec une puce Apple. Les étapes pour Windows et Linux n’ont pas été testées. Les temps de construction dépendent de votre ordinateur et de votre réseau.

Amira ajoute un commentaire dans ticket_api/models.py, au-dessus de la ligne Category = Literal[...] :

ticket_api/models.py
# The categories that the classifier can return.
Category = Literal["billing", "login", "shipping", "account", "other"]

Elle reconstruit ensuite l’image avec la même commande.

Prédisez : la première construction a pris 13,4 secondes, dont 10,4 pour pip install. Lesquelles des six étapes afficheront maintenant CACHED (en cache)? Combien de temps prendra la construction?

Terminal, in ~/projects/ticket-api
docker build -t ticket-api:1.0.0 .

La sortie (abrégée) :

[+] Building 0.6s (11/11) FINISHED docker:desktop-linux
...
=> [1/6] FROM docker.io/library/python:3.14-slim@sha256:f85c5697265c178c 0.0s
...
=> => transferring context: 3.77kB 0.0s
=> CACHED [2/6] WORKDIR /app 0.0s
=> CACHED [3/6] COPY requirements-run.txt . 0.0s
=> CACHED [4/6] RUN pip install -r requirements-run.txt 0.0s
=> CACHED [5/6] COPY pyproject.toml . 0.0s
=> [6/6] COPY ticket_api ./ticket_api 0.0s
...

0,6 seconde. Les étapes 2 à 5 affichent CACHED. Seule l’étape 6, qui copie le dossier modifié, s’est exécutée de nouveau. Docker n’a installé aucun paquet.

Chaque étape d’une construction crée une couche. Docker conserve les couches créées dans son cache de construction. Avant d’exécuter une étape, il vérifie deux choses :

  1. L’instruction est-elle la même que la dernière fois?
  2. Pour COPY : les fichiers sont-ils identiques, octet par octet? Docker compare une somme de contrôle de leur contenu, pas leur date.

Si les deux sont identiques et que l’étape précédente vient aussi du cache, Docker reprend l’ancienne couche : CACHED. Dès qu’une étape diffère, le cache cesse d’aider. Cette étape s’exécute, et toutes les étapes suivantes s’exécutent aussi, car chaque couche repose sur la précédente.

Voici donc la règle pour l’ordre d’un Dockerfile : ce qui change rarement vient en premier; ce qui change souvent vient en dernier. L’image de base change quelques fois par année. La liste des paquets change quand vous ajoutez un paquet. Le code change chaque jour. C’est l’ordre du Dockerfile d’Amira.

Retirez maintenant le commentaire de models.py et reconstruisez. Prédisez d’abord : l’étape 6 s’exécute-t-elle de nouveau?

La sortie (abrégée) :

[+] Building 0.2s (11/11) FINISHED docker:desktop-linux
...
=> CACHED [5/6] COPY pyproject.toml . 0.0s
=> CACHED [6/6] COPY ticket_api ./ticket_api 0.0s

Chaque étape affiche CACHED. Les fichiers sont de nouveau identiques à ceux d’une construction précédente, et Docker possède encore cette couche.

Le même changement d'une ligne dans ticket_api/models.py, avec deux ordres du Dockerfile. Bon ordre, paquets en premier : FROM utilise la même image. WORKDIR, COPY requirements-run.txt, RUN pip install et COPY pyproject.toml sont en cache (CACHED). Seule l'étape COPY ticket_api s'exécute, en 0,0 s. La construction complète prend 0,4 s. Mauvais ordre, tous les fichiers en premier : FROM utilise la même image et WORKDIR est en cache. Puis COPY . . s'exécute en 0,9 s et RUN pip install en 11,4 s. La construction complète prend 16,7 s. Une ligne pointillée marque la première étape dont l'entrée a changé.
Une ligne de code modifiée. Dans le bon ordre, le cache conserve pip install. Dans le mauvais ordre, le changement précède pip install, donc tous les paquets sont réinstallés.
Description textuelle du diagramme

Deux colonnes montrent le même changement, une ligne dans ticket_api/models.py, construit avec deux ordres du Dockerfile.

Le bon ordre compte six étapes. [1/6] FROM python:3.14-slim utilise la même image. [2/6] WORKDIR /app, [3/6] COPY requirements-run.txt ., [4/6] RUN pip install et [5/6] COPY pyproject.toml . sont en cache. Une ligne pointillée précède [6/6] COPY ticket_api ./ticket_api, la première étape dont l’entrée a changé. Elle s’exécute en 0,0 s. La construction complète prend 0,4 s.

Le mauvais ordre compte quatre étapes. [1/4] FROM utilise la même image, et [2/4] WORKDIR /app est en cache. La ligne pointillée précède [3/4] COPY . ., qui copie tous les fichiers, y compris celui qui a changé. Cette étape s’exécute en 0,9 s. [4/4] RUN pip install vient ensuite et s’exécute donc aussi, en 11,4 s. La construction complète prend 16,7 s.

Explorer : quelles étapes s’exécutent de nouveau?

Section intitulée « Explorer : quelles étapes s’exécutent de nouveau? »

Chaque nombre dans l’explorateur est une mesure réelle sur l’ordinateur de test de cette leçon. C’est la médiane de trois constructions pour chaque changement. Vos temps seront différents, mais la répartition entre CACHED et RUN (exécution) reste la même sur tous les ordinateurs.

Explorer

Cache des couches : quelles étapes s'exécutent de nouveau après un changement?

Étapes réexécutées
1 sur 6
pip install
CACHED
Construction complète
0,4 s

Changement : une ligne ajoutée à ticket_api/models.py. Avec le bon ordre, 1 étape sur 6 est réexécutée et la construction prend 0,4 s. [6/6] COPY ticket_api ./ticket_api est la première étape dont l’entrée a changé. Elle est réexécutée, comme chaque étape qui la suit. pip install vient du cache.

  • CACHED : tiré du cache
  • RUN : réexécutée
docker build, bon ordre : 1 étape sur 6 réexécutée
ÉtapeInstructionRésultatTemps
[1/6]FROM python:3.14-slimmême image-
[2/6]WORKDIR /appCACHED-
[3/6]COPY requirements-run.txt .CACHED-
[4/6]RUN pip install -r requirements-run.txtCACHED-
[5/6]COPY pyproject.toml .CACHED-
[6/6]COPY ticket_api ./ticket_apiRUN0,0 s
Le Dockerfile d'Amira, avec les paquets en premier. Choisissez le fichier modifié. Le tableau montre chaque étape, CACHED (en cache) ou RUN (exécution), avec le temps mesuré en secondes.
Description textuelle de l’explorateur

L’explorateur montre les six étapes de construction du Dockerfile d’Amira après un changement, avec leur résultat et leur temps mesuré. L’état initial est un changement d’une ligne dans ticket_api/models.py. Seule [6/6] COPY ticket_api ./ticket_api s’exécute, et la construction prend 0,4 s.

Les autres changements : une ligne dans requirements-run.txt fait exécuter les étapes 3 à 6. pip install prend 12,8 s sur une construction de 15,8 s. Une ligne dans pyproject.toml fait exécuter les étapes 5 et 6, en 0,4 s. Une ligne dans README.md ne change rien pour Docker, car aucune étape ne copie README.md. Toutes les étapes après FROM sont en cache, pour un temps de 0,3 s. Une nouvelle image de base (FROM python:3.13-slim) fait exécuter toutes les étapes. pip install prend 13,5 s sur une construction de 16,3 s.

Beaucoup de Dockerfiles sur Internet utilisent un ordre plus court : copier le dossier complet, puis installer.

A poor order (do not use)
FROM python:3.14-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements-run.txt
EXPOSE 8000
CMD ["fastapi", "run", "--host", "0.0.0.0", "--port", "8000"]

Cela fonctionne, avec deux lignes de moins. Amira l’a essayé dans une copie du projet pour le mesurer. Passez l’explorateur au mauvais ordre, puis essayez chaque fichier de nouveau.

Explorer

Cache des couches : le bon ordre et le mauvais ordre

Étapes réexécutées
2 sur 4
pip install
réexécuté, 11,4 s
Construction complète
16,7 s

Changement : une ligne ajoutée à ticket_api/models.py. Avec le mauvais ordre, 2 étapes sur 4 sont réexécutées et la construction prend 16,7 s. [3/4] COPY . . est la première étape dont l’entrée a changé. Elle est réexécutée, comme chaque étape qui la suit. pip install est réexécuté : 11,4 s sur 16,7 s.

  • CACHED : tiré du cache
  • RUN : réexécutée
docker build, mauvais ordre : 2 étapes sur 4 réexécutées
ÉtapeInstructionRésultatTemps
[1/4]FROM python:3.14-slimmême image-
[2/4]WORKDIR /appCACHED-
[3/4]COPY . .RUN0,9 s
[4/4]RUN pip install -r requirements-run.txtRUN11,4 s
Les mêmes changements, avec une deuxième commande : le bon ordre (paquets en premier) ou le mauvais ordre (COPY . . en premier).
Description textuelle de l’explorateur

L’explorateur commence dans le mauvais ordre, avec le changement d’une ligne dans ticket_api/models.py. [3/4] COPY . . s’exécute (0,9 s), tout comme [4/4] RUN pip install (11,4 s). La construction prend 16,7 s, contre 0,4 s dans le bon ordre.

Dans le mauvais ordre, chaque changement relance pip install. La construction complète prend 16,7 s pour models.py et 16,0 s pour requirements-run.txt. Elle prend 20,0 s pour pyproject.toml, 21,2 s pour README.md et 29,0 s pour l’image de base. COPY . . copie tous les fichiers du dossier. Ainsi, même un changement dans README.md, que l’application n’utilise pas, réinstalle les 50 paquets. Dans le bon ordre, seul un changement dans requirements-run.txt ou dans l’image de base relance pip install.

Le mauvais ordre coûte environ 16 secondes par changement de code. Une équipe qui construit 50 fois par jour attend plus de 13 minutes chaque jour. Chaque construction télécharge aussi les mêmes paquets de nouveau.

Le . à la fin de docker build -t ticket-api:1.0.0 . est le contexte de construction. C’est le dossier dont Docker peut utiliser les fichiers dans COPY. Avant la construction, la commande docker envoie les fichiers du contexte au constructeur, la partie de Docker qui exécute les étapes.

Regardez la ligne transferring context (transfert du contexte) dans la sortie de construction. Amira l’a mesurée dans de nouvelles copies du projet contenant .venv, un dossier .git et un fichier .env avec une clé. La plupart des projets ont ces éléments :

Dockerfile .dockerignore transferring context
Mauvais ordre, COPY . . aucun 84.87MB (4,1 s)
Bon ordre, trois lignes COPY aucun 47.05kB
L’un ou l’autre la liste d’autorisation ci-dessous 16.86kB

Le constructeur demande seulement les fichiers nécessaires aux lignes COPY. Avec COPY . ., cela comprend tous les fichiers : l’environnement virtuel, l’historique Git et .env. Tout entre ensuite dans l’image. Amira a vérifié l’image construite dans le mauvais ordre :

Terminal
docker run --rm ticket-api-poor ls -a /app

La sortie :

.
..
.env
.git
.gitignore
.pytest_cache
.venv
Dockerfile
README.md
browser-test
contract
postman
pyproject.toml
requests
requirements-lock.txt
requirements-run.txt
requirements.txt
tests
ticket_api

La clé dans .env est maintenant dans l’image. Toute personne qui obtient l’image peut la lire. Cette image faisait aussi 492 Mo, contre 363 Mo pour le bon ordre.

Le bon ordre a envoyé 47,05 ko, même si le Dockerfile d’Amira n’a aucune ligne COPY . .. Le dossier ticket_api contient des dossiers __pycache__ provenant des tests du cours sur les API. Ils sont entrés dans l’image. Et un jour, quelqu’un pourrait ajouter COPY . . au Dockerfile.

Un fichier .dockerignore empêche cela. Il énumère les fichiers que la construction ne doit jamais voir. Créez-le dans le dossier du projet :

.dockerignore
# Send only what the image needs. Everything else stays out of the build,
# including .env, secrets/, .venv and .git.
*
!requirements-run.txt
!pyproject.toml
!ticket_api/
**/__pycache__/

C’est une liste d’autorisation. La ligne * ignore tout. Chaque ligne avec ! autorise de nouveau un élément. La dernière ligne exclut de nouveau les dossiers __pycache__. L’autre méthode est une liste d’exclusion (.env, .venv, .git, …). Vous devez la modifier pour chaque nouveau fichier secret, et personne n’y pense. Une liste d’autorisation ne peut rien oublier : un nouveau fichier reste exclu jusqu’à ce que vous l’autorisiez.

Le dossier du projet ~/projects/ticket-api en deux groupes. Restent sur votre ordinateur : .venv, .git, .env avec la clé d'API, .pytest_cache, tests, postman, requests, contract, browser-test, README.md, requirements.txt, requirements-lock.txt et les dossiers __pycache__. Ils n'atteignent jamais le constructeur. Envoyés à Docker : requirements-run.txt, pyproject.toml et ticket_api. Ils passent la liste d'autorisation .dockerignore et deviennent le contexte de construction de 16,86 ko. Ce sont les seuls fichiers que COPY peut utiliser dans docker build.
La liste d'autorisation envoie trois éléments au constructeur. Tout le reste, y compris .env et .venv, ne peut pas atteindre l'image.
Description textuelle du diagramme

À gauche, le dossier du projet est divisé en deux groupes. Le groupe « Restent sur votre ordinateur » contient .venv/ (la majeure partie des 84,87 Mo), .git/ et .env avec la clé d’API. Il contient aussi .pytest_cache/, tests/, postman/, requests/, contract/, browser-test/, README.md, requirements.txt, requirements-lock.txt et les dossiers __pycache__/. Une ligne pointillée indique qu’ils n’atteignent jamais le constructeur et ne peuvent donc pas être copiés dans l’image. Le groupe « Envoyés à Docker » contient requirements-run.txt, pyproject.toml et ticket_api/. Une flèche les fait passer par .dockerignore, avec ses règles *, !requirements-run.txt, !pyproject.toml, !ticket_api/ et **/__pycache__/. Ces règles ignorent tout, puis autorisent trois éléments. Ils deviennent le contexte de construction, de 16,86 ko, et docker build peut copier seulement ces fichiers.

Fixer une version signifie choisir une version exacte. Ainsi, une construction le mois prochain donne la même image qu’aujourd’hui. requirements-run.txt fixe déjà la version de chaque paquet. L’image de base n’est pas encore fixée : python:3.14-slim est une étiquette qui change. Aujourd’hui, elle correspond à Python 3.14.8 sur Debian 13. Après la prochaine version de Python, la même étiquette donnera une autre image.

L’image Python possède des étiquettes plus précises. python:3.14.8-slim-trixie indique la version de Python (3.14.8), la variante (slim) et la version de Debian (13, appelée trixie). Utilisez-la dans le Dockerfile :

Dockerfile
FROM python:3.14-slim
FROM python:3.14.8-slim-trixie

Même une étiquette exacte peut changer. Les responsables de l’image peuvent publier une nouvelle construction sous la même étiquette, par exemple avec un correctif de sécurité. La façon la plus stricte de fixer l’image est son empreinte : une somme de contrôle de son contenu. Affichez-la :

Terminal
docker image inspect python:3.14.8-slim-trixie --format '{{index .RepoDigests 0}}'

La sortie :

python@sha256:f85c5697265c178cc6887276c55fe16cf3d14ca35c3df6a5eab3b360534a55d2

Vous pouvez écrire FROM python:3.14.8-slim-trixie@sha256:f85c… avec l’empreinte complète. La construction utilise alors toujours exactement ces octets. Le coût : l’image ne reçoit aucun correctif de sécurité tant que vous ne changez pas l’empreinte vous-même. Ce cours fixe l’étiquette exacte. Vous vérifiez s’il existe une image plus récente quand vous travaillez sur le projet. Une équipe ayant un outil qui met automatiquement les empreintes à jour peut fixer l’empreinte.

Aujourd’hui, python:3.14-slim et python:3.14.8-slim-trixie ont la même empreinte. La sortie de construction ci-dessus affichait sha256:f85c5697… pour les deux. L’étiquette est seulement un nom; l’empreinte représente le contenu.

ENV définit une variable d’environnement dans l’image. La construction et chaque conteneur l’utilisent. Ajoutez ces lignes après FROM :

Dockerfile
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
PIP_ROOT_USER_ACTION=ignore
Variable Son effet Pourquoi
PYTHONDONTWRITEBYTECODE=1 Python n’écrit pas de fichiers .pyc. Le conteneur n’en a pas besoin. Dans la prochaine leçon, l’application n’aura pas le droit d’écrire dans /app.
PYTHONUNBUFFERED=1 Python écrit chaque ligne de journal immédiatement. docker logs affiche une ligne au moment de l’événement, pas plus tard.
PIP_NO_CACHE_DIR=1 pip ne conserve pas de copie de chaque téléchargement. La copie resterait dans la couche, et personne ne l’utiliserait.
PIP_DISABLE_PIP_VERSION_CHECK=1 pip ne cherche pas de version plus récente de pip. La construction est plus rapide, sans message à ce sujet.
PIP_ROOT_USER_ACTION=ignore pip n’avertit pas qu’il s’exécute comme root. La construction s’est exécutée comme root et a affiché WARNING: Running pip as the 'root' user can result in broken permissions… (avertissement : exécuter pip comme root peut causer des problèmes de permissions). Dans une image, c’est normal.

Le \ à la fin d’une ligne continue l’instruction sur la ligne suivante. Ensemble, l’étiquette fixée, les lignes ENV et .dockerignore changent l’image :

Première image (leçon 1) Maintenant
docker image ls : espace disque utilisé / taille du contenu 363MB / 86.8MB 309MB / 65.3MB
Couche RUN pip install (docker history) 117MB 84.1MB
Couche COPY ticket_api 102kB 49.2kB

La couche pip est 33 Mo plus petite, car elle ne contient pas de cache pip. La couche du code fait la moitié de sa taille, car elle ne contient pas de __pycache__. La taille du contenu est celle des couches compressées qu’un envoi ou une récupération transfère sur le réseau. L’espace disque utilisé est leur taille décompressée sur votre ordinateur.

L’image de base représente la majeure partie de votre image. Vous obtenez tous ses programmes et tous ses problèmes de sécurité. Amira a comparé trois variantes de Python 3.14.8 (linux/arm64, avec docker image ls --tree) :

Image de base Espace disque utilisé Taille du contenu Contient un compilateur C (gcc) et curl
python:3.14.8-trixie 1.62GB 405MB Oui
python:3.14.8-slim-trixie 204MB 43.8MB Non
python:3.14.8-alpine 85.9MB 21.1MB Non

L’image complète contient des outils de construction pour les paquets qui doivent être compilés. Les paquets d’Amira n’en ont pas besoin. La variante slim est donc huit fois plus petite, sans rien manquer.

Alpine est encore plus petite, mais utilise une bibliothèque C différente, musl, au lieu de glibc. pip peut alors utiliser seulement des wheels (paquets prêts à installer) construits pour musl, avec musllinux dans leur nom de fichier. Amira a essayé pip install -r requirements-run.txt sur python:3.14.8-alpine. Les huit paquets contenant du code compilé, comme pydantic_core et uvloop, avaient un wheel musllinux, et l’installation a fonctionné. Un paquet sans ce type de wheel doit être compilé, et l’image Alpine n’a pas de compilateur. Vérifiez chaque paquet avant de choisir Alpine, puis vérifiez de nouveau quand vous en ajoutez un. Le cours utilise slim.

Choisissez une image de base fiable. python est une Docker Official Image (image officielle Docker) : Docker la révise, et elle reçoit des mises à jour de sécurité. Sa page sur Docker Hub, hub.docker.com/_/python, énumère toutes les étiquettes. Une image provenant d’un compte inconnu peut contenir n’importe quoi.

Exercice guidé : une construction rapide, petite et à version fixe

Section intitulée « Exercice guidé : une construction rapide, petite et à version fixe »
  1. Créez .dockerignore dans le dossier du projet, comme dans Le contexte de construction et .dockerignore.

  2. Dans le Dockerfile, remplacez la première ligne par FROM python:3.14.8-slim-trixie.

  3. Ajoutez les lignes ENV après FROM, comme dans Les lignes ENV et une image plus petite. Votre Dockerfile ressemble maintenant à ceci :

    Dockerfile
    FROM python:3.14.8-slim-trixie
    ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PIP_NO_CACHE_DIR=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=1 \
    PIP_ROOT_USER_ACTION=ignore
    WORKDIR /app
    COPY requirements-run.txt .
    RUN pip install -r requirements-run.txt
    COPY pyproject.toml .
    COPY ticket_api ./ticket_api
    EXPOSE 8000
    CMD ["fastapi", "run", "--host", "0.0.0.0", "--port", "8000"]
  4. Prédisez les étapes qui s’exécuteront, puis construisez l’image avec docker build -t ticket-api:1.0.0 ..

  5. Vérifiez la ligne transferring context (transfert du contexte). Elle indique quelques kilooctets.

  6. Exécutez docker image ls ticket-api. L’image fait environ 309 Mo.

  7. Exécutez docker run --rm ticket-api:1.0.0 ls -a /app. La liste contient seulement pyproject.toml, requirements-run.txt et ticket_api.

  8. Démarrez le conteneur et appelez /health, comme dans L’essentiel du Dockerfile : exécuter l’image. La réponse est {"status":"ok"}.

Afficher la sortie de construction attendue à l’étape 4

Toutes les étapes s’exécutent. Les lignes ENV viennent juste après FROM. Chaque étape qui les suit a donc une nouvelle instruction avant elle. Voici les lignes des étapes, avec un outil de construction dont le cache est vide :

=> [1/6] FROM docker.io/library/python:3.14.8-slim-trixie@sha256:f85c569 5.5s
...
=> [2/6] WORKDIR /app 0.2s
=> [3/6] COPY requirements-run.txt . 0.0s
=> [4/6] RUN pip install -r requirements-run.txt 19.7s
=> [5/6] COPY pyproject.toml . 0.1s
=> [6/6] COPY ticket_api ./ticket_api 0.1s

Les lignes ENV n’ont pas d’étape distincte : comme EXPOSE, elles écrivent seulement des paramètres. Vos durées peuvent être différentes. Si cet ordinateur a déjà construit les mêmes étapes, certaines lignes peuvent indiquer CACHED (en cache). Étape 6 :

IMAGE ID DISK USAGE CONTENT SIZE EXTRA
ticket-api:1.0.0 ee0aa1f19820 309MB 65.3MB

Étape 7 :

.
..
pyproject.toml
requirements-run.txt
ticket_api

À vous de jouer : prédire un changement dans pyproject.toml

Section intitulée « À vous de jouer : prédire un changement dans pyproject.toml »

Ajoutez une ligne de commentaire à la fin de pyproject.toml, par exemple # Built with Docker. Avant la construction, notez les étapes qui indiqueront CACHED et celles qui s’exécuteront. Ensuite, construisez l’image, vérifiez le résultat et supprimez le commentaire.

Afficher la réponse

Les étapes 2 à 4 indiquent CACHED, donc pip install ne s’exécute pas. L’étape 5, COPY pyproject.toml ., s’exécute parce que le fichier a changé. L’étape 6 s’exécute parce qu’elle vient après l’étape 5 :

[+] Building 0.3s (11/11) FINISHED docker:desktop-linux
=> [1/6] FROM docker.io/library/python:3.14.8-slim-trixie@sha256:f85c569 0.0s
=> CACHED [2/6] WORKDIR /app 0.0s
=> CACHED [3/6] COPY requirements-run.txt . 0.0s
=> CACHED [4/6] RUN pip install -r requirements-run.txt 0.0s
=> [5/6] COPY pyproject.toml . 0.0s
=> [6/6] COPY ticket_api ./ticket_api 0.0s

ticket_api n’a pas changé, mais sa couche repose sur la nouvelle couche de l’étape 5. Il faut donc la créer à nouveau. Après la suppression du commentaire, la construction suivante indique CACHED partout.

Erreur courante

COPY échoue avec le message « not found », mais le fichier est là

Symptôme : après un changement dans .dockerignore, la construction s’arrête :

#9 [5/6] COPY pyproject.toml .
#9 ERROR: failed to calculate checksum of ref 65tu4hq3l2veiuoltpznypryw::4xw03kvqm5pe2q3u3gfngbhsy: "/pyproject.toml": not found
...
ERROR: failed to build: failed to solve: failed to compute cache key: failed to calculate checksum of ref 65tu4hq3l2veiuoltpznypryw::4xw03kvqm5pe2q3u3gfngbhsy: "/pyproject.toml": not found

ls montre que pyproject.toml se trouve dans le dossier du projet.

Cause : le fichier est sur votre ordinateur, mais pas dans le contexte de construction. Ici, la ligne !pyproject.toml manquait dans la liste d’autorisation. Ainsi, * a ignoré le fichier, et COPY ne peut pas le voir. Le message indique « not found » (introuvable) parce que, pour l’outil de construction, le fichier n’existe pas.

Solution : ajoutez le fichier à la liste d’autorisation avec une ligne !, puis relancez la construction. Quand vous ajoutez un fichier nécessaire à l’image, ajoutez-le à COPY et à .dockerignore.

Pour un vrai service d’IA : cette erreur montre que la liste d’autorisation fait son travail. Si elle omet un fichier de modèle nécessaire à l’image, la construction échoue avec une erreur claire. C’est mieux qu’un secret qui entre dans l’image sans avertissement. Préférez une erreur de construction claire à une fuite silencieuse.

Vérifiez votre compréhension

Pourquoi le Dockerfile d'Amira copie-t-il requirements-run.txt et exécute-t-il pip install avant de copier ticket_api?

Afficher la réponse

Le code change souvent et la liste des paquets change rarement. Docker réutilise les étapes en cache seulement jusqu’à la première étape dont l’entrée a changé. Cette étape et toutes les suivantes s’exécutent à nouveau. Avec les paquets en premier, un changement de code exécute seulement COPY ticket_api (0,4 s ici). Le résultat de pip install vient alors du cache. Avec le code en premier, chaque changement de code réinstalle les 50 paquets (environ 16 s ici).

Vérifiez votre compréhension

Le fichier .dockerignore de Sam liste les éléments à exclure : .venv, .git et .env. La semaine prochaine, l'équipe ajoute un fichier secrets/db_password.txt. Que se passe-t-il avec le fichier de Sam et avec la liste d'autorisation?

Afficher la réponse

Dans la liste d’exclusion de Sam, secrets/db_password.txt ne figure pas. Il entre donc dans le contexte de construction. Si le Dockerfile contient COPY . ., le mot de passe entre dans l’image. Avec la liste d’autorisation, * ignore tous les fichiers, y compris les nouveaux. Seuls requirements-run.txt, pyproject.toml et ticket_api/ peuvent atteindre la construction. Le nouveau fichier reste donc exclu sans aucun changement à .dockerignore.

Vérifiez votre compréhension

Quelle différence y a-t-il entre fixer python:3.14.8-slim-trixie et fixer son empreinte? Donnez un avantage de chaque option.

Afficher la réponse

L’étiquette exacte désigne une version de Python, une variante et une version de Debian. Mais ses responsables peuvent publier une nouvelle construction sous la même étiquette, par exemple avec un correctif de sécurité. Avantage : vous obtenez ces correctifs à la prochaine construction. L’empreinte est une somme de contrôle du contenu exact, donc l’image ne peut jamais changer. Avantage : chaque construction utilise les mêmes octets. En contrepartie, vous devez mettre à jour l’empreinte vous-même pour obtenir les correctifs.

Récapitulatif

  • Le cache des couches réutilise chaque étape jusqu’à la première étape dont l’entrée a changé. Cette étape et toutes les suivantes s’exécutent à nouveau.
  • Placez d’abord ce qui change rarement : l’image de base, la liste des paquets, pip install, puis le code. Un changement de code permet alors une reconstruction en moins d’une seconde.
  • Une liste d’autorisation dans .dockerignore envoie seulement trois éléments à la construction. .env, .venv et .git ne peuvent pas atteindre l’image.
  • Fixez l’image de base à une étiquette exacte (python:3.14.8-slim-trixie) et les paquets à des versions exactes. Une empreinte offre la fixation la plus stricte.
  • Une Docker Official Image de variante slim est petite et fiable. Les lignes ENV et .dockerignore ont réduit l’image à 309 Mo au lieu de 363 Mo.

Ensuite, vous ferez fonctionner l’application avec un compte utilisateur ordinaire. Vous prouverez aussi qu’un secret dans une couche de construction reste dans l’image après sa suppression.

Leçon suivante : Sécurité à l'exécution