Comment accélérer les builds Docker et optimiser la mise en cache avec « COPY –link »
COPY --link
est une nouvelle fonctionnalité de BuildKit qui pourrait considérablement accélérer la création de vos images Docker. Il fonctionne en copiant des fichiers dans des calques d’image indépendants qui ne dépendent pas de la présence de leurs prédécesseurs. Vous pouvez ajouter du nouveau contenu aux images sans même que l’image de base n’existe sur votre système.
Cette fonctionnalité a été ajoutée dans le cadre de Buildx v0.8 en mars 2022. Elle est incluse dans la version 20.10.14 de la CLI Docker, vous devriez donc déjà y avoir accès si vous exécutez la dernière version.
Dans cet article, nous allons montrer ce que --link
fait et expliquer comment cela fonctionne. Nous examinerons également certaines des situations dans lesquelles il ne devrait pas être utilisé.
Sommaire
Qu’est-ce que « -lien » ?
--link
est un nouvel argument facultatif pour le Dockerfile existant COPY
instruction. Il modifie le fonctionnement des copies en créant un nouveau calque d’instantané à chaque fois que vous l’utilisez.
Habituel COPY
Les instructions ajoutent des fichiers à la couche qui les précède dans le Dockerfile. Le contenu de cette couche doit exister sur votre disque pour que le nouveau contenu puisse être fusionné :
FROM alpine COPY my-file /my-file COPY another-file /another-file
Le Dockerfile ci-dessus copie my-file
dans le calque produit par la commande précédente. Après le FROM
instruction, l’image se compose du contenu d’Alpine :
bin/ dev/ etc/ ...
La première COPY
l’instruction produit une image qui comprend tout d’Alpine, ainsi que le my-file
dossier:
my-file bin/ dev/ etc/ ...
Et le deuxième COPY
l’instruction ajoute another-file
au dessus de cette image :
another-file my-file bin/ dev/ etc/ ...
La couche produite par chaque instruction comprend tout ce qui l’a précédée, ainsi que tout ce qui a été ajouté récemment. À la fin de la construction, Docker utilise un processus différent pour déterminer les modifications au sein de chaque couche. Le blob d’image final contient uniquement les fichiers qui ont été ajoutés à chaque étape d’instantané, mais cela n’est pas reflété dans le processus d’assemblage lors de la construction.
Présentation de « -lien »
« -link » modifie COPY
pour créer un nouveau système de fichiers autonome à chaque utilisation. Au lieu de copier les nouveaux fichiers au-dessus du calque précédent, ils sont envoyés à un emplacement complètement différent pour devenir un calque indépendant. Les calques sont ensuite liés entre eux pour produire l’image finale.
Changeons l’exemple Dockerfile à utiliser --link
:
FROM alpine COPY --link my-file /my-file COPY --link another-file /another-file
Le résultat de la FROM
l’instruction est inchangée – elle donne la couche Alpine, avec tout le contenu de cette image :
bin/ dev/ etc/ ...
La première COPY
l’instruction a un effet sensiblement différent. Cette fois, une autre couche indépendante est créée. C’est un nouveau système de fichiers contenant uniquement my-file
:
my-file
Puis le deuxième COPY
l’instruction crée un autre nouvel instantané avec seulement another-file
:
another-file
Une fois la construction terminée, Docker stocke ces instantanés indépendants en tant que nouvelles archives de couches (tarballs). Les archives tar sont reliées à la chaîne de couches précédentes, constituant l’image finale. Il s’agit des trois instantanés fusionnés, ce qui donne un système de fichiers qui correspond à celui d’origine lors de la création des conteneurs :
my-file another-file bin/ dev/ etc/ ...
Cette image du projet BuildKit illustre les différences entre les deux approches.
Ajout de « COPY –link » à vos builds
COPY --link
n’est disponible que lorsque vous utilisez BuildKit pour créer vos images. Soit exécuter votre build avec docker buildx --create
Ou utiliser docker build
avec le DOCKER_BUILDKIT=1
ensemble de variables d’environnement.
Vous devez également vous inscrire à la syntaxe Dockerfile v1.4 en utilisant un commentaire en haut de votre fichier :
# syntax=docker/dockerfile:1.4 FROM alpine:latest COPY --link my-file /my-file COPY --link another-file /another-file
Vous pouvez désormais créer votre image avec la prise en charge des copies liées :
DOCKER_BUILDKIT=1 docker build -t my-image:latest .
Images construites à partir de Dockerfiles à l’aide COPY --link
peut être utilisé comme n’importe quel autre. Vous pouvez démarrer un conteneur avec docker run
et poussez-les directement vers les registres. La --link
L’indicateur n’affecte que la manière dont le contenu est ajouté aux calques d’image lors de la construction.
Pourquoi les copies liées sont importantes
En utilisant le --link
flag autorise la réutilisation des caches de construction même lorsque le contenu que vous COPY
dans les changements. De plus, les builds peuvent se terminer sans même que leur image de base n’existe sur votre machine.
Revenant à l’exemple ci-dessus, standard COPY
comportement exige la alpine
image doit exister sur votre hôte Docker avant que le nouveau contenu puisse être ajouté. L’image sera téléchargée automatiquement lors de la construction si vous ne l’avez pas déjà extraite.
Avec les copies liées, Docker n’a pas besoin de alpine
contenu de l’image. Il tire le alpine
manifeste, crée de nouvelles couches indépendantes pour les fichiers copiés, puis crée un manifeste révisé qui relie les couches à celles fournies par alpine
. Le contenu de la alpine
image – ses blobs de couches – ne sera téléchargée que si vous démarrez un conteneur à partir de votre nouvelle image ou si vous l’exportez dans une archive tar. Lorsque vous poussez l’image vers un registre, ce registre stocke ses nouvelles couches et acquiert à distance le alpine
ceux.
Cette fonctionnalité facilite également les rebases d’images efficaces. Peut-être distribuez-vous actuellement une image Docker à l’aide de la dernière version d’Ubuntu 20.04 LTS :
FROM golang AS build ... RUN go build -o /app . FROM ubuntu:20.04 COPY --link --from=build /app /bin/app ENTRYPOINT ["/bin/app"]
Vous pouvez créer l’image avec la mise en cache activée à l’aide de BuildKit --cache-to
drapeau. La inline
cache stocke les données du cache de build dans l’image de sortie, où elles peuvent être réutilisées dans les builds suivants :
docker buildx build --cache-to type=inline -t example-image:20.04 .
Supposons maintenant que vous souhaitiez fournir une image basée sur le prochain LTS après sa sortie, Ubuntu 22.04 :
FROM golang AS build ... RUN go build -o /app . FROM ubuntu:22.04 COPY --link --from=build /app /bin/app ENTRYPOINT ["/bin/app"]
Reconstruisez l’image à l’aide des données de cache intégrées dans la version d’origine :
docker buildx build --cache-from example-image:20.04 -t example-image:22.04 .
La construction se terminera presque instantanément. À l’aide des données mises en cache de l’image existante, Docker peut vérifier les fichiers nécessaires à la création /app
n’ont pas changé. Cela signifie que le cache de la couche indépendante créée par le COPY
l’instruction reste valable. Comme cette couche ne dépend d’aucune autre, la ubuntu:22.04
l’image ne sera pas tirée non plus. Docker relie simplement la couche d’instantané contenant /bin/app
dans un nouveau manifeste au sein du ubuntu:22.04
chaîne de couches. La couche d’instantané est effectivement « rebasée » sur une nouvelle image parente, sans qu’aucune opération de système de fichiers ne se produise.
Le modèle optimise également les builds en plusieurs étapes où des changements peuvent se produire entre n’importe laquelle des étapes :
FROM golang AS build RUN go build -o /app . FROM config-builder AS config RUN generate-config --out /config.yaml FROM ubuntu:latest COPY --link --from=config /config.yaml build.conf COPY --link --from=build /app /bin/app
Sans pour autant --link
toute modification de la valeur générée config.yaml
causes ubuntu:latest
à extraire et le fichier à copier. Le binaire doit ensuite être recompilé car son cache est invalidé par les modifications du système de fichiers. Avec les copies liées, une modification de config.yaml
permet à la construction de continuer sans tirer ubuntu:latest
ou recompiler le binaire. La couche d’instantané avec build.conf
inside est simplement remplacé par une nouvelle version indépendante de toutes les autres couches.
Quand ne pas l’utiliser
Il existe certaines situations où le --link
flag ne fonctionnera pas correctement. Comme il copie les fichiers dans un nouveau calque, au lieu de les ajouter au-dessus du précédent, vous ne pouvez pas utiliser de références ambiguës comme chemin de destination :
COPY --link my-file /data
Avec un habitué COPY
instruction, my-file
sera copié dans /data/my-file
si /data
existe déjà en tant que répertoire dans l’image. Avec --link
le système de fichiers de la couche cible sera toujours vide, donc my-file
est écrit à /data
.
La même considération s’applique à la résolution des liens symboliques. Standard COPY
résout automatiquement les chemins de destination qui sont des liens symboliques dans l’image. Lorsque vous utilisez --link
ce comportement n’est pas pris en charge car le lien symbolique n’existera pas dans la couche indépendante de la copie.
Il est recommandé de commencer à utiliser --link
partout où ces limitations ne s’appliquent pas. L’adoption de cette fonctionnalité accélérera vos builds et rendra la mise en cache plus puissante. Si vous ne pouvez pas supprimer immédiatement les chemins de destination ambigus ou liés symboliquement, vous pouvez continuer à utiliser les COPY
instruction. C’est à cause de ces modifications rétrocompatibles que --link
est un indicateur facultatif, au lieu de la nouvelle valeur par défaut.
Sommaire
BuildKit COPY --link
est une nouvelle fonctionnalité Dockerfile qui peut rendre les builds plus rapides et plus efficaces. Les images utilisant des copies liées n’ont pas besoin d’extraire les calques précédents pour que les fichiers puissent y être copiés. Docker crée une nouvelle couche indépendante pour chaque COPY
à la place, puis relie ces couches dans la chaîne.
Vous pouvez commencer à utiliser des copies liées dès maintenant si vous créez des images avec BuildKit et la dernière version de Buildx ou Docker CLI. L’adoption de « –link » est une nouvelle étape de construction Docker des meilleures pratiques, à condition que vous ne soyez pas affecté par les modifications de la résolution du chemin de destination qu’elle nécessite.