¿Cuál es la diferencia entre los comandos 'COPIAR' y 'AGREGAR' en un Dockerfile?

2196

¿Cuál es la diferencia entre los comandos COPYy ADDen un Dockerfile y cuándo usaría uno sobre el otro?

COPY <src> <dest>

La instrucción COPY copiará nuevos archivos <src>y los agregará al sistema de archivos del contenedor en la ruta<dest>

ADD <src> <dest>

La instrucción ADD copiará nuevos archivos <src>y los agregará al sistema de archivos del contenedor en la ruta <dest>.

Steve
fuente
11
Consulte las mejores prácticas: docs.docker.com/engine/userguide/eng-image/…
EricSonaron
99
En junio de 2018, la referencia dice que ADD agrega a la imagen (es decir, un archivo estático) mientras que COPY agrega al contenedor (es decir, una instancia de tiempo de ejecución de la imagen). ¿Seguramente esto implica que COPY se ejecuta cada vez que se ejecuta Docker en la imagen, o tal vez esto es simplemente un caso de terminología inconsistente?
Chris Robinson
14
Creo que es una terminología inconsistente
Daniel Stevens
66
@ChrisRobinson, sería imposible COPYque se ejecute cada vez que se ejecuta, porque no necesariamente tiene acceso al contexto original para obtener el contenido.
Ken Williams

Respuestas:

2169

Usted debe comprobar el ADDy COPYdocumentación para una descripción más detallada de sus comportamientos, pero en pocas palabras, la diferencia principal es que ADDse puede hacer algo más que COPY:

  • ADDpermite <src>ser una URL
  • Con referencia a los comentarios a continuación, la ADD documentación establece que:

    Si es un archivo tar local en un formato de compresión reconocido (identidad, gzip, bzip2 o xz), se desempaqueta como un directorio. Los recursos de las URL remotas no se descomprimen.

Tenga en cuenta que las mejores prácticas para escribir Dockerfiles sugieren usar COPYdonde ADDno se requiere la magia de . De lo contrario, usted ( ya que tuvo que buscar esta respuesta ) probablemente se sorprenda algún día cuando quiera copiar keep_this_archive_intact.tar.gzen su contenedor, pero en su lugar, rocíe el contenido en su sistema de archivos.

crimen de hielo
fuente
65
Solo quería aclarar algo: el uso de AGREGAR con una url a un .tar.gz NO EXTRACTA el archivo al sistema de archivos (lo verifiqué en este momento para estar seguro y está confirmado)
Cecile
42
Esta es información esencial y es un delito que la referencia oficial de Dockerfile no aclare la diferencia de esta manera.
Cheeso
1
No estoy seguro, si esto difiere de una imagen a otra. Utilicé la imagen busybox y AGREGAR para un archivo zip. Simplemente apareció en el directorio de destino sin descomprimir. Supongo que la extracción ocurre solo para el tarball, pero no lo he comprobado ahora.
Santosh Kumar Arjunan
44
@SantoshKumarArjunan: los documentos de Docker indican lo siguiente sobre ADD y extracción automática de alquitrán: 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 permite --from = <name | index>, donde no puedo encontrar el mismo soporte para ADD
Brandon
474

COPY es

Igual que 'AGREGAR', pero sin el manejo tar y URL remoto.

Referencia directamente desde el código fuente .

caike
fuente
15
¿Veo esto correctamente: ADDtambién crea directorios no existentes . Así, a pesar de que de alguna manera se desaconseja en todo este hilo, tiene una ventaja sobre COPY, ya que no tiene que correr mkdiry ahorrar algo de mecanografía
eli
3
COPY hace eso también @eli
bhordupur
La mejor explicación hasta ahora. ¿Por qué no es la respuesta aceptada?
xdevx32
141

Hay algo de documentación oficial sobre ese punto: Mejores prácticas para escribir archivos Docker

Debido a que el tamaño de la imagen es importante, ADDse desaconseja el uso para recuperar paquetes de URL remotas; deberías usar curlo en su wgetlugar. De esa manera, puede eliminar los archivos que ya no necesita después de que se hayan extraído y no tendrá que agregar otra capa en su imagen.

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

Para otros elementos (archivos, directorios) que no requieren ADDla capacidad de extracción automática de alquitrán, siempre debe usar COPY.

Victor Laskin
fuente
18
Docker dice que prefiera COPY, porque es más transparente. De las mejores prácticas del archivo Docker (15/12/2014): 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.
esquema
115

De los documentos de Docker:

AGREGAR o COPIAR

Aunque ADD y COPY son funcionalmente similares, en general, se prefiere COPY. Eso es porque es más transparente que AGREGAR. COPY solo admite la copia básica de archivos locales en el contenedor, mientras que ADD tiene algunas características (como extracción de alquitrán solo local y soporte remoto de URL) que no son inmediatamente obvias. En consecuencia, el mejor uso para ADD es la extracción automática de archivos tar locales en la imagen, como en ADD rootfs.tar.xz /.

Más: Mejores prácticas para escribir Dockerfiles

eddd
fuente
46

Si desea agregar un xx.tar.gz a un /usr/localcontenedor de entrada, descomprímalo y luego retire el paquete comprimido inútil.

Para COPIA:

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

Para añadir:

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

ADD admite extracción de alquitrán solo local. Además, COPY usará tres capas, pero ADD solo usa una capa.

BertLi
fuente
3
¿Alguna razón por la que no solo dos capas? 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 copia un archivo / directorio de su host a su imagen.

ADD copia un archivo / directorio de su host a su imagen, pero también puede buscar URL remotas, extraer archivos TAR, etc.

Úselo COPYsimplemente para copiar archivos y / o directorios en el contexto de compilación.

Utilícelo ADDpara descargar recursos remotos, extraer archivos TAR, etc.

JSON C11
fuente
55
explicación perfecta para un novato como yo
uneq95
17

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

"Aunque ADD y COPY son funcionalmente similares, en términos generales, se prefiere COPY. Esto se debe a que es más transparente que ADD. COPY solo admite la copia básica de archivos locales en el contenedor, mientras que ADD tiene algunas características (como extracción de alquitrán solo local y soporte remoto de URL) que no son inmediatamente obvios. En consecuencia, el mejor uso para ADD es la extracción automática de archivos tar locales en la imagen, como en ADD rootfs.tar.xz /.

Si tiene varios pasos de Dockerfile que usan diferentes archivos de su contexto, COPIELOS individualmente, en lugar de todos a la vez. Esto garantizará que la memoria caché de compilación de cada paso solo se invalide (obligando a que el paso se vuelva a ejecutar) si cambian los archivos específicamente requeridos.

Por ejemplo:

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

Resulta en menos invalidaciones de caché para el paso EJECUTAR, que si coloca COPIA. / tmp / antes de eso.

Debido a que el tamaño de la imagen es importante, se desaconseja usar ADD para recuperar paquetes de URL remotas; deberías usar curl o wget en su lugar. De esa manera, puede eliminar los archivos que ya no necesita después de que se hayan extraído y no tendrá que agregar otra capa en su imagen. Por ejemplo, debe evitar hacer cosas como:

 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

Y en cambio, haz algo como:

 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

Para otros elementos (archivos, directorios) que no requieren la capacidad de extracción automática de tar del ADD, siempre debe usar COPY ".

jhpg
fuente
7

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

COPY y ADD son instrucciones de Dockerfile que tienen propósitos similares. Le permiten copiar archivos de una ubicación específica en una imagen de Docker.

COPY toma un src y un destino. Solo le permite copiar en un archivo o directorio local desde su host (la máquina que construye la imagen Docker) en la imagen Docker.

ADD te permite hacer eso también, pero también es compatible con otras 2 fuentes. Primero, puede usar una URL en lugar de un archivo / directorio local. En segundo lugar, puede extraer un archivo tar del origen directamente en el destino

Un caso de uso válido para ADD es cuando desea extraer un archivo tar local en un directorio específico en su imagen Docker.

Si está copiando archivos locales en su imagen de Docker, use siempre COPY porque es más explícito.

Shagun Pruthi
fuente
7

Al crear un Dockerfile, hay dos comandos que puede usar para copiar archivos / directorios en él, ADDyCOPY . Aunque existen ligeras diferencias en el alcance de su función, esencialmente realizan la misma tarea.

Entonces, ¿por qué tenemos dos comandos y cómo sabemos cuándo usar uno u otro?

ESTIBADOR ADD COMANDO

Comencemos notando que el ADDcomando es anterior a COPY. Desde el lanzamiento de la plataforma Docker, elADD instrucción ha sido parte de su lista de comandos.

El comando copia archivos / directorios a un sistema de archivos del contenedor especificado.

La sintaxis básica para el ADDcomando es:

ADD <src> … <dest>

Incluye la fuente que desea copiar ( <src>) seguido del destino donde desea almacenarlo ( <dest>). Si la fuente es un directorio,ADD copia todo lo que contiene (incluidos los metadatos del sistema de archivos).

Por ejemplo, si el archivo está disponible localmente y desea agregarlo al directorio de una imagen, escriba:

ADD /source/file/path  /destination/path

ADDTambién puede copiar archivos desde una URL. Puede descargar un archivo externo y copiarlo en el destino deseado. Por ejemplo:

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

Una característica adicional es que copia archivos comprimidos, extrayendo automáticamente el contenido en el destino dado. Esta característica solo se aplica a los archivos / directorios comprimidos almacenados localmente.

ADD source.file.tar.gz /temp

Tenga en cuenta que no puede descargar y extraer un archivo / directorio comprimido de una URL. El comando no desempaqueta los paquetes externos al copiarlos en el sistema de archivos local.

ESTIBADOR COPY COMANDO

Debido a algunos problemas de funcionalidad, Docker tuvo que introducir un comando adicional para duplicar contenido COPY.

A diferencia de su ADDcomando estrechamente relacionado , COPYsolo tiene una función asignada. Su función es duplicar archivos / directorios en una ubicación específica en su formato existente. Esto significa que no se trata de extraer un archivo comprimido, sino que lo copia tal como está.

La instrucción solo se puede utilizar para archivos almacenados localmente. Por lo tanto, no puede usarlo con URL para copiar archivos externos a su contenedor.

Para usar la COPYinstrucción, siga el formato de comando básico:

Escriba la fuente y dónde desea que el comando extraiga el contenido de la siguiente manera:

COPY <src> … <dest> 

Por ejemplo:

COPY /source/file/path  /destination/path 

¿Qué comando usar? (Mejor práctica)

Teniendo en cuenta las circunstancias en que COPYse introdujo el comando, es evidente que mantenerlo ADDera una cuestión de necesidad. Docker lanzó un documento oficial que describe las mejores prácticas para escribir Dockerfiles, que explícitamente desaconseja el uso deADD comando.

La documentación oficial de Docker señala que COPYsiempre debe ser la instrucción de acceso, ya que es más transparente queADD .

Si necesita copiar del contexto de compilación local en un contenedor, siga usando COPY .

El equipo de Docker también desaconseja el uso ADDpara descargar y copiar un paquete desde una URL. En cambio, es más seguro y más eficiente usar wget o curl dentro de un RUNcomando. Al hacerlo, evita crear una capa de imagen adicional y ahorra espacio.

Yogi Ghorecha
fuente
4

Nota IMPORTANTE

Tuve que COPY descomprimir el paquete de Java en mi imagen acoplable. Cuando comparé el tamaño de la imagen acoplada creado con ADD, era 180 MB más grande que el creado con COPY, tar -xzf * .tar.gz y rm * .tar.gz

Esto significa que aunque ADD elimina el archivo tar, todavía se mantiene en algún lugar. ¡Y está haciendo la imagen más grande!

Avi Veltz
fuente
¿Sigue siendo cierto para la última versión de Docker?
Navin
3

Dado que Docker 17.05 COPYse usa con el --fromindicador en compilaciones de varias etapas para copiar artefactos de etapas de compilación anteriores a la etapa de compilación actual.

de la documentación

Opcionalmente, COPY acepta un indicador --from=<name|index>que se puede utilizar para establecer la ubicación de origen en una etapa de compilación anterior (creada con FROM .. AS) que se utilizará en lugar de un contexto de compilación enviado por el usuario.

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

Esta es otra forma de copiar archivos en una imagen. La opción -v crea temporalmente un volumen que usamos durante el proceso de compilación.

Esto es diferente a otros volúmenes porque monta un directorio de host solo para la compilación. Los archivos se pueden copiar usando un comando cp estándar.

Además, como curl y wget, se puede ejecutar en una pila de comandos (se ejecuta en un solo contenedor) y no multiplicar el tamaño de la imagen. ADD y COPY no son apilables porque se ejecutan en un contenedor independiente y los comandos posteriores en aquellos archivos que se ejecutan en contenedores adicionales multiplicarán el tamaño de la imagen:

Con las opciones configuradas así:

-v /opt/mysql-staging:/tvol

Lo siguiente se ejecutará en un contenedor:

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
fuente
1
¿En qué versión de docker estás donde ves esa opción? No está documentado y no funciona en mi cliente 1.12.1.
BMitch
2
En realidad, esta característica aún no se ha incluido en la versión principal, y todavía hay mucha discusión sobre el tema, por lo que no deberíamos esperarla antes de mucho tiempo ... Consulte el informe de errores para obtener más información: github.com/ docker / docker / issues / 14080 .
jwatkins
1
Sí, no existe tal opción (marcado en la última versión 17.06). Esta respuesta es engañosa. unknown shorthand flag: 'v' in -v
Kirby el
Comentario engañoso de hecho
Guido van Steen
Los volúmenes de Docker no tenían nada que hacer aquí en la respuesta, por favor, si puede, responda la pregunta directa :), es fácilmente la respuesta negativa.
Majid Ali Khan