Quelle est la différence entre les commandes «COPIER» et «AJOUTER» dans un Dockerfile?

2197

Quelle est la différence entre les commandes COPYet ADDdans un Dockerfile, et quand devrais-je utiliser l'une sur l'autre?

COPY <src> <dest>

L'instruction COPY copiera les nouveaux fichiers depuis <src>et les ajoutera au système de fichiers du conteneur au chemin<dest>

ADD <src> <dest>

L'instruction ADD copiera les nouveaux fichiers à partir de <src>et les ajoutera au système de fichiers du conteneur à path <dest>.

Steve
la source
11
Voir les meilleures pratiques: docs.docker.com/engine/userguide/eng-image/…
EricSonaron
9
En juin 2018, la référence indique que ADD ajoute à l'image (c'est-à-dire un fichier statique) tandis que COPY ajoute au conteneur (c'est-à-dire une instance d'exécution de l'image). Cela implique sûrement que COPY est exécuté à chaque fois que l'image est exécutée par Docker, ou peut-être s'agit-il simplement d'une terminologie incohérente?
Chris Robinson
14
Je pense que c'est une terminologie incohérente
Daniel Stevens
6
@ChrisRobinson, il serait impossible de l' COPYexécuter à chaque exécution, car il n'a pas nécessairement accès au contexte d'origine pour récupérer le contenu.
Ken Williams

Réponses:

2169

Vous devriez vérifier la documentation ADDet COPYpour une description plus détaillée de leurs comportements, mais en résumé, la principale différence est que cela ADDpeut faire plus que COPY:

  • ADDpermet <src>d'être une URL
  • Se référant aux commentaires ci-dessous, la ADD documentation indique que:

    S'il s'agit d'une archive tar locale dans un format de compression reconnu (identité, gzip, bzip2 ou xz), elle est décompressée en tant que répertoire. Les ressources des URL distantes ne sont pas décompressées.

Notez que les meilleures pratiques pour écrire des Dockerfiles suggèrent d'utiliser COPYoù la magie de ADDn'est pas requise. Sinon, vous ( puisque vous avez dû rechercher cette réponse ) serez probablement surpris un jour lorsque vous comptez copier keep_this_archive_intact.tar.gzdans votre conteneur, mais à la place, vous pulvérisez le contenu sur votre système de fichiers.

la glace
la source
65
Je voulais juste clarifier quelque chose: utiliser ADD avec une URL vers un .tar.gz N'EXTRAIT PAS l'archive vers le système de fichiers (j'ai vérifié pour le moment et c'est confirmé)
Cecile
42
Il s'agit d'informations essentielles et c'est un crime que la référence officielle Dockerfile ne clarifie pas la différence de cette façon.
Cheeso
1
Pas sûr, si cela diffère d'une image à l'autre. J'ai utilisé l'image de busybox et ADD pour un fichier zip. Il est simplement apparu dans le répertoire de destination sans décompresser. Je suppose que l'extraction ne se produit que pour l'archive tar, mais je n'ai pas vérifié cela maintenant.
Santosh Kumar Arjunan
4
@SantoshKumarArjunan: les documents Docker indiquent ce qui suit à propos de l'ADD et de l'extraction automatique de tar: If <src> is a local tar archive in a recognized compression format (identity, gzip, bzip2 or xz) then it is unpacked as a directory. Resources from remote URLs are not decompressed. Docker ADD
hmacias
1
COPY permet --from = <nom | index>, où je ne trouve pas le même support pour ADD
Brandon
474

COPY est

Identique à 'ADD', mais sans le tar et la gestion des URL distantes.

Référence directement à partir du code source .

caike
la source
15
Est-ce que je vois cela correctement: créeADD également des répertoires inexistants . Donc, bien que cela soit découragé dans tout ce fil, il a un avantage sur COPYparce que vous n'avez pas à exécuter mkdiret à enregistrer de la frappe
eli
3
COPY fait ça aussi @eli
bhordupur
Meilleure explication jusqu'à présent. Pourquoi ce n'est pas la réponse acceptée?
xdevx32
141

Il existe une documentation officielle sur ce point: Meilleures pratiques pour l'écriture de Dockerfiles

La taille de l'image étant importante, l'utilisation ADDde la récupération de packages à partir d'URL distantes est fortement déconseillée; vous devez utiliser curlou à la wgetplace. De cette façon, vous pouvez supprimer les fichiers dont vous n'avez plus besoin après leur extraction et vous n'aurez pas à ajouter un autre calque dans votre image.

RUN mkdir -p /usr/src/things \
  && curl -SL http://example.com/big.tar.gz \
    | tar -xJC /usr/src/things \
  && make -C /usr/src/things all

Pour les autres éléments (fichiers, répertoires) qui ne nécessitent pas la ADDcapacité d'extraction automatique de tar, vous devez toujours utiliser COPY.

Victor Laskin
la source
18
Docker dit préférer COPY , car il est plus transparent. Extrait des meilleures pratiques du fichier Docker (2014-12-15): Although ADD and COPY are functionally similar, generally speaking, COPY is preferred. That’s because it’s more transparent than ADD. COPY only supports the basic copying of local files into the container, while ADD has some features that are not immediately obvious.
schemar
115

Depuis les documents Docker:

AJOUTER ou COPIER

Bien que ADD et COPY soient fonctionnellement similaires, de manière générale, COPY est préféré. C'est parce qu'il est plus transparent que ADD. COPY ne prend en charge que la copie de base des fichiers locaux dans le conteneur, tandis que ADD possède certaines fonctionnalités (comme l'extraction de tar local uniquement et la prise en charge d'URL à distance) qui ne sont pas immédiatement évidentes. Par conséquent, la meilleure utilisation d'ADD est l'extraction automatique du fichier tar local dans l'image, comme dans ADD rootfs.tar.xz /.

Plus: Meilleures pratiques pour écrire des Dockerfiles

eddd
la source
46

Si vous souhaitez ajouter un xx.tar.gz à un /usr/local conteneur in, décompressez-le, puis supprimez le package compressé inutile.

Pour COPIER:

COPY resources/jdk-7u79-linux-x64.tar.gz /tmp/
RUN tar -zxvf /tmp/jdk-7u79-linux-x64.tar.gz -C /usr/local
RUN rm /tmp/jdk-7u79-linux-x64.tar.gz

Pour ajouter:

ADD resources/jdk-7u79-linux-x64.tar.gz /usr/local/

ADD prend en charge l'extraction de goudron uniquement locale. En plus, COPY utilisera trois couches, mais ADD n'utilisera qu'une seule couche.

BertLi
la source
3
Une raison pour laquelle pas seulement deux couches? RUN tar -zxvf /tmp/jdk-7u79-linux-x64.tar.gz -C /usr/local && rm /tmp/jdk-7u79-linux-x64.tar.gz
Stephen C
25

COPY copie un fichier / répertoire de votre hôte vers votre image.

ADD copie un fichier / répertoire de votre hôte vers votre image, mais peut également récupérer des URL distantes, extraire des fichiers TAR, etc ...

Utilisation COPY pour copier simplement des fichiers et / ou des répertoires dans le contexte de construction.

Utiliser ADDpour télécharger des ressources distantes, extraire des fichiers TAR, etc.

JSON C11
la source
5
explication parfaite pour un noob comme moi
uneq95
17

Depuis les documents Docker: https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#add-or-copy

"Bien que ADD et COPY soient fonctionnellement similaires, de manière générale, COPY est préféré. En effet, il est plus transparent que ADD. COPY ne prend en charge que la copie de base des fichiers locaux dans le conteneur, tandis que ADD possède certaines fonctionnalités prise en charge des URL distantes) qui ne sont pas immédiatement évidentes. Par conséquent, la meilleure utilisation d'ADD est l'extraction automatique des fichiers tar locaux dans l'image, comme dans ADD rootfs.tar.xz /.

Si vous avez plusieurs étapes Dockerfile qui utilisent des fichiers différents de votre contexte, copiez-les individuellement, plutôt que toutes en même temps. Cela garantira que le cache de génération de chaque étape n'est invalidé (forçant l'étape à être réexécutée) que si les fichiers spécifiquement requis changent.

Par exemple:

 COPY requirements.txt /tmp/
 RUN pip install --requirement /tmp/requirements.txt
 COPY . /tmp/

Il en résulte moins d'invalidités de cache pour l'étape RUN que si vous mettez la COPIE. / tmp / avant.

La taille de l'image étant importante, l'utilisation d'ADD pour récupérer des packages à partir d'URL distantes est fortement déconseillée; vous devriez plutôt utiliser curl ou wget. De cette façon, vous pouvez supprimer les fichiers dont vous n'avez plus besoin après leur extraction et vous n'aurez pas à ajouter un autre calque dans votre image. Par exemple, vous devez éviter de faire des choses comme:

 ADD http://example.com/big.tar.xz /usr/src/things/
 RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
 RUN make -C /usr/src/things all

Et au lieu de cela, faites quelque chose comme:

 RUN mkdir -p /usr/src/things \
     && curl -SL htt,p://example.com/big.tar.xz \
     | tar -xJC /usr/src/things \
     && make -C /usr/src/things all

Pour les autres éléments (fichiers, répertoires) qui ne nécessitent pas la fonction d'extraction automatique de tar d'ADD, vous devez toujours utiliser COPY. "

jhpg
la source
7

Source: https://nickjanetakis.com/blog/docker-tip-2-the-difference-between-copy-and-add-in-a-dockerile :

COPY et ADD sont des instructions Dockerfile qui servent à des fins similaires. Ils vous permettent de copier des fichiers d'un emplacement spécifique dans une image Docker.

COPY prend un src et une destination. Il vous permet uniquement de copier dans un fichier local ou un répertoire de votre hôte (la machine qui construit l'image Docker) dans l'image Docker elle-même.

ADD vous permet également de le faire, mais il prend également en charge 2 autres sources. Tout d'abord, vous pouvez utiliser une URL au lieu d'un fichier / répertoire local. Deuxièmement, vous pouvez extraire un fichier tar de la source directement dans la destination

Un cas d'utilisation valide pour ADD est lorsque vous souhaitez extraire un fichier tar local dans un répertoire spécifique de votre image Docker.

Si vous copiez des fichiers locaux sur votre image Docker, utilisez toujours COPY car c'est plus explicite.

Shagun Pruthi
la source
7

Lors de la création d'un Dockerfile, il existe deux commandes que vous pouvez utiliser pour y copier des fichiers / répertoires - ADDet COPY. Bien qu'il existe de légères différences dans l'étendue de leur fonction, ils remplissent essentiellement la même tâche.

Alors, pourquoi avons-nous deux commandes et comment savoir quand utiliser l'une ou l'autre?

DOCKER ADDCOMMAND

Commençons par noter que la ADDcommande est plus ancienne que COPY. Depuis le lancement de la plateforme Docker, l' ADDinstruction fait partie de sa liste de commandes.

La commande copie les fichiers / répertoires dans un système de fichiers du conteneur spécifié.

La syntaxe de base de la ADDcommande est:

ADD <src> … <dest>

Il comprend la source que vous souhaitez copier ( <src>) suivie de la destination où vous souhaitez le stocker ( <dest>). Si la source est un répertoire,ADD copie tout ce qu'il contient (y compris les métadonnées du système de fichiers).

Par exemple, si le fichier est disponible localement et que vous souhaitez l'ajouter au répertoire d'une image, vous tapez:

ADD /source/file/path  /destination/path

ADDpeut également copier des fichiers à partir d'une URL. Il peut télécharger un fichier externe et le copier vers la destination souhaitée. Par exemple:

ADD http://source.file/url  /destination/path

Une fonctionnalité supplémentaire est qu'il copie les fichiers compressés, extrayant automatiquement le contenu dans la destination donnée. Cette fonctionnalité s'applique uniquement aux fichiers / répertoires compressés stockés localement.

ADD source.file.tar.gz /temp

Gardez à l'esprit que vous ne pouvez pas télécharger et extraire un fichier / répertoire compressé à partir d'une URL. La commande ne décompresse pas les packages externes lors de leur copie dans le système de fichiers local.

DOCKER COPYCOMMAND

En raison de certains problèmes de fonctionnalité, Docker a dû introduire une commande supplémentaire pour la duplication de contenu - COPY.

Contrairement à sa ADDcommande étroitement liée , COPYune seule fonction est affectée. Son rôle est de dupliquer des fichiers / répertoires dans un emplacement spécifié dans leur format existant. Cela signifie qu'il ne traite pas de l'extraction d'un fichier compressé, mais le copie tel quel.

L'instruction ne peut être utilisée que pour les fichiers stockés localement. Par conséquent, vous ne pouvez pas l'utiliser avec des URL pour copier des fichiers externes dans votre conteneur.

Pour utiliser l' COPYinstruction, suivez le format de commande de base:

Tapez la source et l'endroit où vous souhaitez que la commande extrait le contenu comme suit:

COPY <src> … <dest> 

Par exemple:

COPY /source/file/path  /destination/path 

Quelle commande utiliser? (Meilleure pratique)

Compte tenu des circonstances dans lesquelles le COPYcommandement a été introduit, il est évident que le maintien ADDétait une nécessité. Docker a publié un document officiel décrivant les meilleures pratiques pour l'écriture de Dockerfiles, qui déconseille explicitement d'utiliser leADD commande.

La documentation officielle de Docker note que cela COPYdevrait toujours être l'instruction principale car elle est plus transparente que ADD.

Si vous devez copier du contexte de construction local dans un conteneur, respectez l'utilisation COPY.

L'équipe Docker déconseille également fortement ADDde télécharger et de copier un package à partir d'une URL. Au lieu de cela, il est plus sûr et plus efficace d'utiliser wget ou curl dans une RUNcommande. Ce faisant, vous évitez de créer une couche d'image supplémentaire et économisez de l'espace.

Yogi Ghorecha
la source
4

Note importante

j'ai dû COPY et décompresser le package java dans mon image docker. Lorsque j'ai comparé la taille d'image de docker créée à l'aide d'ADD, elle était de 180 Mo plus grande que celle créée à l'aide de COPY, tar -xzf * .tar.gz et rm * .tar.gz

Cela signifie que même si ADD supprime le fichier tar, il est toujours conservé quelque part. Et ça agrandit l'image !!

Avi Veltz
la source
Est-ce toujours le cas pour la dernière version de Docker?
Navin
3

Depuis Docker 17.05 COPYest utilisé avec le --fromdrapeau dans les builds multi-étapes les générations pour copier les artefacts des étapes de génération précédentes vers l'étape de génération actuelle.

de la documentation

COPY accepte éventuellement un indicateur --from=<name|index>qui peut être utilisé pour définir l'emplacement source à une étape de génération précédente (créée avec FROM .. AS) qui sera utilisée à la place d'un contexte de génération envoyé par l'utilisateur.

MCI
la source
0
docker build -t {image name} -v {host directory}:{temp build directory} .

C'est une autre façon de copier des fichiers dans une image. L'option -v crée temporairement un volume que nous avons utilisé pendant le processus de génération.

Ceci est différent des autres volumes car il monte un répertoire hôte pour la génération uniquement. Les fichiers peuvent être copiés à l'aide d'une commande cp standard.

En outre, comme curl et wget, il peut être exécuté dans une pile de commandes (s'exécute dans un seul conteneur) et ne pas multiplier la taille de l'image. ADD et COPY ne sont pas empilables car ils s'exécutent dans un conteneur autonome et les commandes suivantes sur les fichiers qui s'exécutent dans des conteneurs supplémentaires multiplieront la taille de l'image:

Avec les options définies ainsi:

-v /opt/mysql-staging:/tvol

Les éléments suivants s'exécuteront dans un seul conteneur:

RUN cp -r /tvol/mysql-5.7.15-linux-glibc2.5-x86_64 /u1 && \
    mv /u1/mysql-5.7.15-linux-glibc2.5-x86_64 /u1/mysql && \

    mkdir /u1/mysql/mysql-files && \
    mkdir /u1/mysql/innodb && \
    mkdir /u1/mysql/innodb/libdata && \
    mkdir /u1/mysql/innodb/innologs && \
    mkdir /u1/mysql/tmp && \

    chmod 750 /u1/mysql/mysql-files && \
    chown -R mysql /u1/mysql && \
    chgrp -R mysql /u1/mysql
Dennis Payne
la source
1
Sur quelle version de docker êtes-vous là où vous voyez cette option? Ce n'est pas documenté et ne fonctionne pas sur mon client 1.12.1.
BMitch
2
En fait, cette fonctionnalité n'a pas encore été incluse dans la version principale, et il y a encore beaucoup de discussions sur le sujet, donc nous ne devrions pas nous y attendre avant longtemps ... Voir le rapport de bogue pour plus d'informations: github.com/ docker / docker / issues / 14080 .
jwatkins
1
Oui, il n'y a pas une telle option (vérifié dans la dernière version 17.06). Cette réponse est trompeuse. unknown shorthand flag: 'v' in -v
Kirby
Commentaire trompeur en effet
Guido van Steen
Les volumes Docker n'avaient rien à voir ici dans la réponse, s'il vous plaît si vous le pouvez, répondez à la question directe :), c'est facilement la réponse de downvote.
Majid Ali Khan