Sécurité à l'exécution
- Leçon 6
- 50 min
- Module 2 : Construire l'image de l'application
Leçon 6 sur 15 · L'essentiel de Docker et du nuage pour les développeurs en IASécurité à l'exécution
1. Comprendre les conteneurs
2. Construire l'image de l'application
3. Réseau, configuration et persistance
4. Les services de base du nuage
5. Déployer et nettoyer
Ce que vous saurez faire
Limitez ce qu’une personne malveillante peut faire si elle prend le contrôle de l’API. Assurez-vous aussi que l’image ne contient jamais de secret. Ces deux mesures coûtent peu maintenant, mais coûtent cher à corriger après la publication de l’image.
Avant de commencerCe qu’il faut savoir et avoir sous la main
Ce que vous devez savoir
- Le cache des couches et l’ordre du Dockerfile, dans Construire efficacement : le cache des couches.
.dockerignorecomme liste d’autorisation, dans Construire efficacement : le contexte de construction et .dockerignore.- Pourquoi un secret reste hors du code, dans Configuration et secrets : secrets.
docker execetdocker history, dans Images et conteneurs en cours d’exécution : exemple détaillé : un fichier dans un conteneur et Ce que contient une image.
Ce qu’il vous faut sur votre ordinateur
- Le
Dockerfileaux versions fixées, avec les lignes ENV, dans Construire efficacement : exercice guidé : une construction rapide, petite et à version fixe. .dockerignore, dans Construire efficacement : le contexte de construction et .dockerignore.- L’image
ticket-api:1.0.0construite avec ces fichiers (309 Mo), dans le même exercice guidé. - Si votre projet est manquant ou ne fonctionne plus, copiez le dernier instantané du cours sur les API,
end-of-m07. Faites ensuite les exercices guidés de L’essentiel du Dockerfile et de Construire efficacement. Utiliser un instantané donne les étapes.
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.
Qui exécute l’application?
Section intitulée « Qui exécute l’application? »Démarrez l’API en donnant un nom au conteneur, pour pouvoir l’utiliser dans d’autres commandes. -d exécute le conteneur en arrière-plan :
docker run -d --rm --name ticket-api -p 127.0.0.1:8000:8000 -e API_KEY=local-dev-key ticket-api:1.0.0Demandez au conteneur quel utilisateur l’exécute :
docker exec ticket-api idLa sortie :
uid=0(root) gid=0(root) groups=0(root)root, l’utilisateur numéro 0, qui peut tout faire. Sans ligne USER, un Dockerfile exécute l’application comme root. Amira essaie de voir ce que root peut faire. Elle crée un fichier à côté du code, puis remplace le classificateur par une seule ligne :
docker exec ticket-api touch /app/ticket_api/x.pydocker exec ticket-api sh -c 'echo "print(1)" > /app/ticket_api/classifier.py'Les deux commandes fonctionnent, sans message. Le conteneur exécute maintenant du code modifié. Arrêtez-le avant qu’il fasse autre chose :
docker stop ticket-api--rm supprime le conteneur et, avec lui, le fichier modifié. L’image n’a pas changé. Mais imaginez une personne malveillante qui trouve un bogue dans l’API et peut y exécuter des commandes. Comme root, elle peut modifier le code du service en cours d’exécution, installer des programmes et lire tous les fichiers du conteneur. L’isolation du conteneur l’empêche d’accéder à votre ordinateur. Mais root dans le conteneur porte le même numéro d’utilisateur, 0, que root sur l’hôte. Un bogue dans l’isolation peut alors lui donner les droits de root sur l’hôte.
La solution est simple : l’application n’a pas besoin d’être root. Elle doit seulement lire son code et répondre aux requêtes.
Exécuter comme utilisateur autre que root
Section intitulée « Exécuter comme utilisateur autre que root »Ajoutez deux lignes au Dockerfile. RUN useradd crée dans l’image un utilisateur normal nommé app. USER app indique que chaque étape suivante et chaque conteneur s’exécutent comme cet utilisateur :
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
RUN useradd --create-home --uid 10001 app
WORKDIR /app
COPY requirements-run.txt .RUN pip install -r requirements-run.txt
COPY pyproject.toml .COPY ticket_api ./ticket_api
USER app
EXPOSE 8000CMD ["fastapi", "run", "--host", "0.0.0.0", "--port", "8000"]| Partie | Pourquoi |
|---|---|
useradd ... app |
Un utilisateur normal, sans droits particuliers. |
--uid 10001 |
Un numéro d’utilisateur fixe. Chaque construction donne le même numéro. Un montage de fichier ou une règle de sécurité pourra donc l’utiliser plus tard. Un numéro élevé évite les conflits avec les utilisateurs d’un ordinateur Linux normal, dont les numéros commencent à 1 000. |
--create-home |
Crée /home/app. Certains outils écrivent leurs paramètres dans le dossier personnel. |
RUN useradd près du début |
L’utilisateur change très rarement. Il précède donc la liste des paquets, comme l’indique la règle du cache. |
USER app après les lignes COPY |
pip install et COPY s’exécutent encore comme root. Le code et les paquets appartiennent donc à root. Seule l’application s’exécute comme app. |
Voici le Dockerfile terminé de ce cours. Il ne change pas dans les modules suivants. Construisez l’image :
docker build -t ticket-api:1.0.0 .Les lignes des étapes, avec un outil de construction dont le cache est vide (version abrégée) :
=> [1/7] FROM docker.io/library/python:3.14.8-slim-trixie@sha256:f85c569 4.5s ... => [2/7] RUN useradd --create-home --uid 10001 app 0.4s => [3/7] WORKDIR /app 0.0s => [4/7] COPY requirements-run.txt . 0.0s => [5/7] RUN pip install -r requirements-run.txt 16.7s => [6/7] COPY pyproject.toml . 0.1s => [7/7] COPY ticket_api ./ticket_api 0.1sIl y a maintenant sept étapes. La nouvelle étape 2 précède toutes les autres. Chaque étape s’exécute donc à nouveau une fois. USER n’a pas d’étape : comme ENV, c’est un paramètre. L’image garde la même taille qu’avant, 309 Mo.
Vérifier le résultat
Section intitulée « Vérifier le résultat »Démarrez la nouvelle image avec la même commande qu’avant :
docker run -d --rm --name ticket-api -p 127.0.0.1:8000:8000 -e API_KEY=local-dev-key ticket-api:1.0.0docker exec ticket-api idLa sortie (après l’identifiant du conteneur) :
uid=10001(app) gid=10001(app) groups=10001(app)Essayez les mêmes modifications que root :
docker exec ticket-api touch /app/xdocker exec ticket-api sh -c 'echo "print(1)" > /app/ticket_api/classifier.py'La sortie :
touch: cannot touch '/app/x': Permission deniedsh: 1: cannot create /app/ticket_api/classifier.py: Permission deniedLes fichiers appartiennent à root, et les autres utilisateurs peuvent seulement les lire :
docker exec ticket-api ls -l /appLa sortie :
total 12-rw-r--r-- 1 root root 296 Oct 7 16:49 pyproject.toml-rw-r--r-- 1 root root 1092 Oct 7 16:50 requirements-run.txtdrwxr-xr-x 2 root root 4096 Oct 7 17:03 ticket_apirw-r--r-- signifie que le propriétaire (root) peut lire et écrire, mais que tous les autres peuvent seulement lire. C’est tout ce dont l’application a besoin. /health donne encore {"status":"ok"}. docker top ticket-api montre le processus avec le numéro d’utilisateur :
UID PID PPID C STIME TTY TIME CMD10001 20466 20442 25 17:10 ? 00:00:00 /usr/local/bin/python3.14 /usr/local/bin/fastapi run --host 0.0.0.0 --port 8000Description textuelle du diagramme
Le panneau de gauche montre le conteneur sans ligne USER. fastapi s’exécute comme root, uid 0. Il peut lire le code dans /app. Il peut aussi modifier le code dans /app et écrire dans /usr/local, où se trouvent Python et les paquets. Le schéma marque ces deux lignes : une personne malveillante qui prend le contrôle du processus peut les exploiter. Le panneau de droite montre le conteneur avec USER app. fastapi s’exécute comme app, uid 10001. Il peut lire le code dans /app, mais ne peut ni le modifier ni écrire dans /usr/local.
Arrêtez le conteneur : docker stop ticket-api.
Garder les identifiants secrets hors de l’image
Section intitulée « Garder les identifiants secrets hors de l’image »Une image est un fichier que vous copiez : vers un registre, chez Sam ou dans le nuage. Toute personne qui peut la télécharger peut lire chaque couche. Un secret ne doit donc jamais faire partie d’une construction. L’API de billets le fait déjà correctement : la clé entre au démarrage du conteneur, avec -e API_KEY=.... Le module 3 la fournit sous forme de fichier. L’image ne contient aucune clé.
Voici trois façons courantes d’insérer un secret dans une image par erreur :
| Erreur | Où le secret reste |
|---|---|
COPY .env . ou COPY . . avec un .env dans le dossier |
Dans la couche de ce COPY, sous forme de fichier |
ENV API_KEY=... |
Dans les paramètres de l’image. docker image inspect le montre à tout le monde. |
ARG API_KEY et --build-arg API_KEY=... |
Dans l’historique de construction des lignes RUN qui l’utilisent |
Votre liste d’autorisation bloque déjà la première erreur. Amira la teste avec un Dockerfile qui tente de copier .env :
#7 [3/4] COPY .env .#7 ERROR: failed to calculate checksum of ref 65tu4hq3l2veiuoltpznypryw::0sv39oljj5ojc6ywju1h5qxh8: "/.env": not found.env ne fait pas partie du contexte de construction. COPY ne peut donc pas le trouver. L’erreur courante ci-dessous montre ce qui arrive dans un projet sans liste d’autorisation.
Si une construction a elle-même besoin d’un identifiant secret, utilisez un secret de construction. Par exemple, un jeton (token) pour télécharger un paquet privé. RUN --mount=type=secret,id=api_key ... rend le fichier /run/secrets/api_key accessible à cette seule étape RUN. Il n’est jamais enregistré dans une couche. Vous fournissez le fichier avec docker build --secret id=api_key,src=api_key.txt .. Amira l’a testé : l’étape a lu 31 octets dans /run/secrets/api_key. Dans un conteneur créé à partir de l’image, ls /run/secrets indique No such file or directory (aucun fichier ou dossier de ce nom). L’API de billets n’a pas besoin de secret de construction.
Erreur courante
La clé reste dans l'image, même après RUN rm
Faites ce test dans un nouveau dossier, ~/projects/leak-demo, avec une fausse clé. N’utilisez jamais une vraie clé pour ce test.
Symptôme : aucun signe visible. Un collègue a écrit un Dockerfile qui copie .env, puis le supprime, « par sécurité » :
FROM python:3.14.8-slim-trixieWORKDIR /appCOPY .env .RUN rm .envLe dossier contient un fichier .env avec une seule ligne, API_KEY=demo-key-7731-not-real, et aucun .dockerignore. La construction fonctionne :
docker build -t leak-demo:1 .docker run --rm leak-demo:1 ls -a /appLa sortie (les lignes des étapes, puis ls) :
=> [1/4] FROM docker.io/library/python:3.14.8-slim-trixie@sha256:f85c569 0.0s => CACHED [2/4] WORKDIR /app 0.0s => [3/4] COPY .env . 0.0s => [4/4] RUN rm .env 0.4s.../app est vide. La clé semble avoir disparu.
Diagnostic : examinez les couches. docker history montre que la couche COPY .env . est toujours là :
docker history leak-demo:1IMAGE CREATED CREATED BY SIZE COMMENT54aae749bcd1 2 seconds ago RUN /bin/sh -c rm .env # buildkit 8.19kB buildkit.dockerfile.v0<missing> 2 seconds ago COPY .env . # buildkit 12.3kB buildkit.dockerfile.v0<missing> 19 minutes ago WORKDIR /app 8.19kB buildkit.dockerfile.v0<missing> 39 hours ago CMD ["python3"] 0B buildkit.dockerfile.v0...Les couches sont en lecture seule. RUN rm .env ne peut pas modifier la couche en dessous. Il ajoute seulement une nouvelle couche avec un marqueur, un fichier whiteout (masquage), qui cache .env dans un conteneur en cours d’exécution. Prouvez-le : enregistrez l’image dans un fichier, décompressez-le et trouvez la couche contenant app/.env :
docker image save leak-demo:1 -o leak-demo.tarmkdir layers && tar -xf leak-demo.tar -C layersfor f in layers/blobs/sha256/*; do tar -tf "$f" 2>/dev/null | grep -qx app/.env && echo "$f"; donedocker image save leak-demo:1 -o leak-demo.tarmkdir layers; tar -xf leak-demo.tar -C layersGet-ChildItem layers/blobs/sha256 | ForEach-Object { if ((tar -tf $_.FullName 2>$null) -contains 'app/.env') { $_.FullName } }docker image save leak-demo:1 -o leak-demo.tarmkdir layers && tar -xf leak-demo.tar -C layersfor f in layers/blobs/sha256/*; do tar -tf "$f" 2>/dev/null | grep -qx app/.env && echo "$f"; doneLa sortie (le fichier de l’image fait 42 Mo) :
layers/blobs/sha256/ed3d3b3e5e58ff6e9574e76ff47278683ebdfd02bf7f54b38b1953fc56b04942Lisez le fichier de cette couche. Utilisez le nom dans votre propre sortie :
tar -xOf layers/blobs/sha256/ed3d3b3e5e58ff6e9574e76ff47278683ebdfd02bf7f54b38b1953fc56b04942 app/.envAPI_KEY=demo-key-7731-not-realLa clé, au complet. layers/manifest.json liste les sept couches de l’image dans l’ordre. D’abord les quatre de l’image de base, puis WORKDIR, puis celle-ci (couche 6). La couche 7 vient de RUN rm. Elle contient seulement app/ et app/.wh..env, le fichier whiteout.
Description textuelle du diagramme
L’image est une pile de couches, la plus récente en haut. Les couches 1 à 4 viennent de FROM python:3.14.8-slim-trixie. La couche 5 vient de WORKDIR /app et contient le dossier. La couche 6 vient de COPY .env . et contient app/.env avec la clé d’API. Le schéma la met en évidence. La couche 7 vient de RUN rm .env et contient seulement un marqueur, .wh..env, qui cache .env. Une note en bas indique que, dans un conteneur, ls -a /app ne montre aucun .env. Mais dans l’image enregistrée, la couche 6 contient toujours le fichier et la clé.
ENV est encore plus facile à lire. Avec ENV API_KEY=demo-key-7731-not-real dans un Dockerfile, docker image inspect --format '{{json .Config.Env}}' l’affiche avec les autres paramètres :
["PATH=/usr/local/bin:...","PYTHON_VERSION=3.14.8","PYTHON_SHA256=c221...","API_KEY=demo-key-7731-not-real"]Cause : chaque couche d’une image reste dans l’image. Une étape ultérieure peut cacher un fichier, mais elle ne peut pas le supprimer.
Correction :
- Considérez la clé comme publique. Créez une nouvelle clé et cessez d’utiliser l’ancienne. Supprimer l’image ne suffit pas : vous ne savez pas qui l’a copiée.
- Supprimez l’image partout :
docker image rm leak-demo:1sur votre ordinateur, et dans chaque registre où vous l’avez envoyée. - Modifiez le Dockerfile pour que le secret n’entre jamais dans une construction. Aucun
COPYde fichiers secrets, aucunENVouARGcontenant un secret. Fournissez le secret au démarrage du conteneur. Utilisez un.dockerignorecomme liste d’autorisation.
Pour un vrai service d’IA : les clés d’API des fournisseurs de modèles ont une valeur monétaire pour une personne malveillante. De plus, les images vont dans des registres accessibles à de nombreuses personnes et de nombreux systèmes. Une image doit pouvoir être publiée sans risque. Gardez toutes les clés, tous les jetons et tous les mots de passe hors de l’image. Insérez-les seulement au démarrage du conteneur.
Nettoyez le test : docker image rm leak-demo:1. Supprimez ensuite le dossier ~/projects/leak-demo avec son .env, leak-demo.tar et layers.
Exercice guidé : un utilisateur autre que root
Section intitulée « Exercice guidé : un utilisateur autre que root »- Ajoutez
RUN useradd --create-home --uid 10001 appaprès les lignesENVde votreDockerfile. - Ajoutez
USER appaprèsCOPY ticket_api ./ticket_api. - Comparez votre fichier avec le Dockerfile terminé dans Exécuter comme utilisateur autre que root. Il doit être identique.
- Construisez l’image avec
docker build -t ticket-api:1.0.0 .. La construction comporte sept étapes. - Démarrez le conteneur avec
docker run -d --rm --name ticket-api -p 127.0.0.1:8000:8000 -e API_KEY=local-dev-key ticket-api:1.0.0. - Exécutez
docker exec ticket-api id. La sortie commence paruid=10001(app). - Exécutez
docker exec ticket-api touch /app/x. La sortie estPermission denied(permission refusée). - Appelez
/health. Il donne{"status":"ok"}. - Arrêtez le conteneur avec
docker stop ticket-api.
Afficher la sortie attendue des étapes 6 et 7
uid=10001(app) gid=10001(app) groups=10001(app)touch: cannot touch '/app/x': Permission deniedSi l’étape 6 indique uid=0(root), l’image n’a pas de ligne USER app, ou vous avez démarré une ancienne image. Construisez-la à nouveau et vérifiez que docker image inspect ticket-api:1.0.0 --format '{{.Config.User}}' affiche app.
À vous de jouer : où l’application peut-elle écrire?
Section intitulée « À vous de jouer : où l’application peut-elle écrire? »L’application ne peut pas écrire dans /app. Faites une prédiction : peut-elle écrire dans /tmp? Dans /home/app? Vérifiez avec docker exec ticket-api touch /tmp/x et docker exec ticket-api touch /home/app/x, puis expliquez.
Afficher la réponse
Les deux fonctionnent. /tmp est accessible à tous les utilisateurs (ls -ld /tmp affiche drwxrwxrwt). /home/app appartient à app, car useradd --create-home l’a créé pour cet utilisateur (drwx------ 2 app app). L’application peut donc encore écrire des fichiers temporaires, mais pas son propre code. Les fichiers dans /tmp et /home/app sont dans la couche accessible en écriture du conteneur. Ils disparaissent avec le conteneur. Le module 3 montre où placer les données qui doivent persister.
Exercice du module
Section intitulée « Exercice du module »L’exercice du module : construire l’image de l’API de billets et inspecter sa configuration. Ce sont les paramètres que l’image contient en plus de ses fichiers. D’abord, un petit exemple détaillé.
Exemple détaillé : un paramètre
Section intitulée « Exemple détaillé : un paramètre »docker image inspect affiche la description complète de l’image en JSON. --format sélectionne un champ avec un gabarit : {{.Config.User}} est l’utilisateur défini par USER.
docker image inspect ticket-api:1.0.0 --format '{{.Config.User}}'appVotre tâche : la configuration de l’image
Section intitulée « Votre tâche : la configuration de l’image »- Construisez l’image à partir du Dockerfile terminé, sous le nom
ticket-api:1.0.0, si ce n’est pas déjà fait. - Affichez ces champs avec
docker image inspect ticket-api:1.0.0 --format '...':{{.Config.User}},{{json .Config.Cmd}},{{json .Config.ExposedPorts}},{{.Config.WorkingDir}}et{{json .Config.Env}}. - Pour chaque champ, écrivez une ligne indiquant quelle ligne du Dockerfile l’a défini.
- Examinez
Env(variables d’environnement). Contient-il une clé ou un mot de passe? Quelles variables viennent de l’image de base? - Exécutez
docker history ticket-api:1.0.0. Nommez les couches de 0 octet et expliquez pourquoi leur taille est nulle.
Afficher le corrigé
Une seule commande pour les quatre premiers champs :
docker image inspect ticket-api:1.0.0 --format 'User={{.Config.User}} Cmd={{json .Config.Cmd}} ExposedPorts={{json .Config.ExposedPorts}} WorkingDir={{.Config.WorkingDir}}'User=app Cmd=["fastapi","run","--host","0.0.0.0","--port","8000"] ExposedPorts={"8000/tcp":{}} WorkingDir=/appdocker image inspect ticket-api:1.0.0 --format '{{json .Config.Env}}'["PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","PYTHON_VERSION=3.14.8","PYTHON_SHA256=c2215904f02b175596dc49351585104f4bc20341e1c47378b26a2c274360ce73","PYTHONDONTWRITEBYTECODE=1","PYTHONUNBUFFERED=1","PIP_NO_CACHE_DIR=1","PIP_DISABLE_PIP_VERSION_CHECK=1","PIP_ROOT_USER_ACTION=ignore"]-
User(utilisateur) vient deUSER app;Cmd(commande), deCMD [...];ExposedPorts(ports exposés), deEXPOSE 8000;WorkingDir(répertoire de travail), deWORKDIR /app. Les cinq dernières variables dansEnvviennent des lignesENV. -
Aucune clé et aucun mot de passe.
API_KEYn’y figure pas, car vous la fournissez seulement avec-eau démarrage d’un conteneur.PATH,PYTHON_VERSIONetPYTHON_SHA256viennent de l’image de base. -
docker history(premières lignes) :CMD ["fastapi" "run" "--host" "0.0.0.0" "--p… 0BEXPOSE [8000/tcp] 0BUSER app 0BCOPY ticket_api ./ticket_api # buildkit 49.2kBCOPY pyproject.toml . # buildkit 12.3kBRUN /bin/sh -c pip install -r requirements-r… 84.1MBCOPY requirements-run.txt . # buildkit 12.3kBWORKDIR /app 8.19kBRUN /bin/sh -c useradd --create-home --uid 1… 69.6kBENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFER… 0BCMD,EXPOSE,USERetENVfont 0 octet. Ils modifient seulement la configuration affichée à l’étape 2, pas les fichiers. Leurs couches sont donc vides.
Vérification du module
Section intitulée « Vérification du module »Vérifiez votre compréhension
Rappel : nommez les six instructions du premier Dockerfile de ticket-api. Pour chacune, dites si elle crée des fichiers dans une couche ou seulement un paramètre.
Afficher la réponse
Quatre instructions créent des fichiers : FROM (les couches de l’image de base), WORKDIR (le dossier), COPY (les fichiers copiés) et RUN (ce que la commande a modifié, comme les paquets installés). EXPOSE (le port documenté) et CMD (la commande de démarrage) écrivent seulement des paramètres, avec des couches de 0 octet. Dans le Dockerfile terminé, ENV et USER définissent aussi seulement des paramètres.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Vérifiez votre compréhension
Prédiction : dans le Dockerfile terminé, vous modifiez requirements-run.txt pour ajouter un paquet. Lesquelles des sept étapes s'exécutent de nouveau, et l'utilisateur app est-il recréé?
Afficher la réponse
Les étapes 1 à 3 (FROM, RUN useradd, WORKDIR) proviennent du cache. L’utilisateur app n’est donc pas recréé. L’étape 4, COPY requirements-run.txt ., s’exécute parce que le fichier a changé. Les étapes 5 à 7 (pip install, COPY pyproject.toml, COPY ticket_api) s’exécutent parce qu’elles viennent après. pip install est l’étape lente : environ 13 secondes ici.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Vérifiez votre compréhension
Vérification de réalisation : ajoutez un commentaire à ticket_api/models.py, reconstruisez ticket-api:1.0.0 et expliquez quelles couches Docker a réutilisées et pourquoi. Ensuite, retirez le commentaire.
Afficher la réponse
La sortie de la construction (abrégée) :
[+] Building 0.4s (12/12) FINISHED docker:desktop-linux ... => CACHED [2/7] RUN useradd --create-home --uid 10001 app 0.0s => CACHED [3/7] WORKDIR /app 0.0s => CACHED [4/7] COPY requirements-run.txt . 0.0s => CACHED [5/7] RUN pip install -r requirements-run.txt 0.0s => CACHED [6/7] COPY pyproject.toml . 0.0s => [7/7] COPY ticket_api ./ticket_api 0.0sDocker a réutilisé les couches des étapes 2 à 6 : leurs instructions et leurs fichiers d’entrée n’ont pas changé. Leurs couches en cache sont donc encore correctes. L’image de base de l’étape 1 est la même. Seule l’étape 7 s’est exécutée, parce que ticket_api/models.py, un fichier qu’elle copie, a changé. C’est la dernière étape, donc aucune autre ne la suit. Les paramètres (USER, EXPOSE, CMD) sont écrits de nouveau, ce qui ne prend aucun temps. La construction a pris 0,4 seconde plutôt qu’environ 16.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Récapitulatif
Dans ce module, vous avez construit l’image de l’application :
- Un Dockerfile avec
FROM,WORKDIR,COPY,RUN,EXPOSEetCMDsous forme exec, etrequirements-run.txtcréé dans un conteneur Linux. - Une construction rapide : les paquets avant le code, pour reconstruire en moins d’une seconde après une modification du code. Une liste d’autorisation
.dockerignorequi envoie trois éléments à la construction. - Une petite image de base fiable à version fixe,
python:3.14.8-slim-trixie, et des lignes ENV qui maintiennent l’image à 309 Mo. - Une image sûre : l’application s’exécute sous
app(uid 10001) et ne peut pas modifier son propre code. Aucun secret ne se trouve dans les couches. Un fichier supprimé par une étape ultérieure reste dans l’image.
Réinitialisation. Pour commencer le module 3 dans un état propre :
- Listez vos conteneurs avec
docker ps -a. Arrêtez et supprimez tout conteneurticket-api:docker rm -f ticket-api. - Supprimez les images de test :
docker image rm hello-image leak-demo:1. Si vous les avez déjà supprimées, Docker indiqueNo such image(aucune image de ce nom). - Supprimez les dossiers
~/projects/hello-imageet~/projects/leak-demo. - Exécutez
docker system dfpour voir l’espace utilisé par les images, les conteneurs et le cache de construction. N’exécutez pas de commande qui supprime tout : d’autres projets sur votre ordinateur peuvent utiliser le même Docker. - Si votre projet ne fonctionne plus, copiez l’instantané
end-of-m02et reconstruisezticket-api:1.0.0.
Ensuite, vous vous connecterez au conteneur par des ports. Vous apprendrez pourquoi 127.0.0.1 signifie autre chose dans un conteneur.
Leçon suivante : Ports et accès au service