Qual è la differenza tra i comandi 'COPIA' e 'AGGIUNGI' in un file Docker?


2196

Qual è la differenza tra i comandi COPYe ADDin un file Docker e quando dovrei usarne uno rispetto all'altro?

COPY <src> <dest>

L'istruzione COPY copierà i nuovi file <src>e li aggiungerà al filesystem del contenitore nel percorso<dest>

ADD <src> <dest>

L'istruzione ADD copierà i nuovi file <src>e li aggiungerà al filesystem del contenitore nel percorso <dest>.



9
A giugno 2018 il riferimento dice che ADD aggiunge all'immagine (cioè un file statico) mentre COPY si aggiunge al contenitore (cioè un'istanza di runtime dell'immagine). Sicuramente questo implica che la COPIA viene eseguita ogni volta che l'immagine viene eseguita da Docker, o forse questo è semplicemente un caso di terminologia incoerente?
Chris Robinson,

14
Penso che sia una terminologia incoerente
Daniel Stevens l'

6
@ChrisRobinson, sarebbe impossibile COPYeseguirlo ogni volta che viene eseguito, perché non ha necessariamente accesso al contesto originale per afferrare il contenuto.
Ken Williams,

Risposte:


2169

È necessario controllare la documentazione ADDe COPYper una descrizione più dettagliata dei loro comportamenti, ma in poche parole, la differenza principale è che ADDpuò fare di più di COPY:

  • ADDpermette <src>di essere un URL
  • Facendo riferimento ai seguenti commenti, la ADD documentazione afferma che:

    Se si tratta di un archivio tar locale in un formato di compressione riconosciuto (identità, gzip, bzip2 o xz), viene decompresso come directory. Le risorse dagli URL remoti non vengono decompresse.

Nota che le migliori pratiche per scrivere Dockerfile suggeriscono di usare COPYdove ADDnon è richiesta la magia di . Altrimenti, tu ( dato che hai dovuto cercare questa risposta ) probabilmente ti sorprenderai un giorno quando intendi copiarlo keep_this_archive_intact.tar.gznel tuo contenitore, ma invece, spruzzi il contenuto sul tuo filesystem.


65
Volevo solo chiarire qualcosa: usare ADD con un url su un .tar.gz NON ESTRATTA l'archivio sul filesystem (ho ricontrollato in questo momento per essere sicuro ed è confermato)
Cecile

42
Queste sono informazioni essenziali ed è un crimine che il riferimento ufficiale Dockerfile non chiarisca la differenza in questo modo.
Cheeso,

1
Non sono sicuro, se questo differisce per un'immagine all'immagine. Ho usato l'immagine busybox e ADD per un file zip. È semplicemente apparso nella directory di destinazione senza decomprimere. Presumo che l'estrazione avvenga solo per il tarball, ma non l'ho verificato ora.
Santosh Kumar Arjunan,

4
@SantoshKumarArjunan: i documenti Docker indicano quanto segue su ADD e l'estrazione automatica del catrame: 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 consente --from = <name | index>, dove non riesco a trovare lo stesso supporto per ADD
Brandon

474

COPY è

Come "AGGIUNGI", ma senza la gestione tar e URL remoto.

Riferimento direttamente dal codice sorgente .


15
Lo vedo correttamente: creaADD anche directory inesistenti . Quindi, sebbene sia in qualche modo scoraggiato in tutto questo thread, ha un vantaggio rispetto al COPYfatto che non devi eseguire mkdire salvare un po 'di battitura
eli

3
Anche COPY lo fa @eli
bhordupur il

La migliore spiegazione finora. Perché non è la risposta accettata?
xdevx32

141

C'è un po 'di documentazione ufficiale su questo punto: Best Practices for Writing Dockerfiles

Poiché la dimensione dell'immagine è importante, l'utilizzo ADDper recuperare pacchetti da URL remoti è fortemente sconsigliato; dovresti usare curlo wgetinvece. In questo modo è possibile eliminare i file non più necessari dopo che sono stati estratti e non sarà necessario aggiungere un altro livello nell'immagine.

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

Per altri elementi (file, directory) che non richiedono ADDla capacità di auto-estrazione tar, è necessario utilizzare sempre COPY.



18
Docker dice di preferire COPY, perché è più trasparente. Da Docker File Best Practices (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.
schemar

115

Dai documenti Docker:

AGGIUNGI o COPIA

Sebbene ADD e COPY siano funzionalmente simili, in generale, si preferisce COPY. Questo perché è più trasparente di ADD. COPY supporta solo la copia di base di file locali nel contenitore, mentre ADD ha alcune funzionalità (come l'estrazione di tar locale e il supporto remoto dell'URL) che non sono immediatamente ovvie. Di conseguenza, l'uso migliore per ADD è l'estrazione automatica del file tar locale nell'immagine, come in ADD rootfs.tar.xz /.

Altro: best practice per scrivere Dockerfile


46

Se si desidera aggiungere un xx.tar.gz a un /usr/local contenitore in, decomprimerlo e quindi rimuovere il pacchetto compresso inutile.

Per 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

Per ADD:

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

ADD supporta l'estrazione di catrame solo locale. Oltre a ciò, COPIA utilizzerà tre livelli, ma ADD utilizza solo un livello.


3
Qualche motivo per cui non solo due strati? 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 file / directory dal tuo host alla tua immagine.

ADD copia un file / directory dal tuo host alla tua immagine, ma può anche recuperare URL remoti, estrarre file TAR, ecc ...

Uso COPY per copiare semplicemente file e / o directory nel contesto di compilazione.

Utilizzare ADDper il download di risorse remote, l'estrazione di file TAR, ecc.


5
spiegazione perfetta per un noob come me
uneq95

17

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

"Sebbene ADD e COPY siano funzionalmente simili, in generale, si preferisce COPY. Questo perché è più trasparente di ADD. COPY supporta solo la copia di base di file locali nel contenitore, mentre ADD ha alcune funzionalità (come l'estrazione di tar solo locale e supporto URL remoto) che non sono immediatamente evidenti. Di conseguenza, l'uso migliore per ADD è l'estrazione automatica del file tar locale nell'immagine, come in ADD rootfs.tar.xz /.

Se hai più passaggi Dockerfile che utilizzano file diversi dal tuo contesto, COPIAli singolarmente, piuttosto che tutti in una volta. Ciò assicurerà che la cache di compilazione di ogni passaggio venga invalidata (forzando la riesecuzione del passaggio) se i file specificatamente richiesti cambiano.

Per esempio:

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

Si ottiene un numero inferiore di invalidazioni della cache per il passaggio RUN rispetto a quando si inserisce COPY. / tmp / prima di esso.

Poiché le dimensioni dell'immagine sono importanti, l'utilizzo di ADD per recuperare i pacchetti dagli URL remoti è fortemente sconsigliato; dovresti usare invece curl o wget. In questo modo è possibile eliminare i file non più necessari dopo che sono stati estratti e non sarà necessario aggiungere un altro livello nell'immagine. Ad esempio, dovresti evitare di fare cose come:

 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

E invece, fai qualcosa del tipo:

 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

Per altri elementi (file, directory) che non richiedono la capacità di auto-estrazione tar di ADD, dovresti sempre usare COPY. "


7

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

COPIA e AGGIUNGI sono entrambe istruzioni Dockerfile che hanno scopi simili. Ti consentono di copiare file da una posizione specifica in un'immagine Docker.

COPY accetta in src e destinazione. Ti consente solo di copiare un file o una directory locale dal tuo host (la macchina che crea l'immagine Docker) nell'immagine Docker stessa.

ADD ti consente anche di farlo, ma supporta anche altre 2 fonti. Innanzitutto, è possibile utilizzare un URL anziché un file / directory locale. In secondo luogo, è possibile estrarre un file tar dall'origine direttamente nella destinazione

Un caso d'uso valido per ADD è quando si desidera estrarre un file tar locale in una directory specifica nell'immagine Docker.

Se stai copiando file locali nell'immagine Docker, usa sempre COPIA perché è più esplicito.


7

Quando si crea un file Docker, ci sono due comandi che è possibile utilizzare per copiare file / directory in esso - ADDe COPY. Sebbene vi siano lievi differenze nella portata della loro funzione, svolgono essenzialmente lo stesso compito.

Quindi, perché abbiamo due comandi e come sappiamo quando usare l'uno o l'altro?

ADDCOMANDO DOCKER

Cominciamo notando che il ADDcomando è più vecchio di COPY. Dal lancio della piattaforma Docker, le ADDistruzioni fanno parte del suo elenco di comandi.

Il comando copia file / directory in un file system del contenitore specificato.

La sintassi di base per il ADDcomando è:

ADD <src> … <dest>

Include la fonte che si desidera copiare ( <src>) seguita dalla destinazione in cui si desidera memorizzarlo ( <dest>). Se l'origine è una directory,ADD copia tutto al suo interno (inclusi i metadati del file system).

Ad esempio, se il file è disponibile localmente e si desidera aggiungerlo alla directory di un'immagine, digitare:

ADD /source/file/path  /destination/path

ADDpuò anche copiare file da un URL. Può scaricare un file esterno e copiarlo nella destinazione desiderata. Per esempio:

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

Un'ulteriore caratteristica è che copia i file compressi, estraendo automaticamente il contenuto nella destinazione specificata. Questa funzione si applica solo ai file / directory compressi memorizzati localmente.

ADD source.file.tar.gz /temp

Tieni presente che non puoi scaricare ed estrarre un file / directory compresso da un URL. Il comando non decomprime i pacchetti esterni durante la copia nel file system locale.

DOCKER COPYCOMANDO

A causa di alcuni problemi di funzionalità, Docker ha dovuto introdurre un comando aggiuntivo per la duplicazione dei contenuti - COPY.

A differenza del ADDcomando strettamente correlato , COPYha solo una funzione assegnata. Il suo ruolo è duplicare file / directory in una posizione specificata nel loro formato esistente. Ciò significa che non si occupa dell'estrazione di un file compresso, ma piuttosto lo copia così com'è.

L'istruzione può essere utilizzata solo per i file memorizzati localmente. Pertanto, non è possibile utilizzarlo con gli URL per copiare file esterni nel proprio contenitore.

Per utilizzare l' COPYistruzione, seguire il formato di comando di base:

Digita l'origine e il punto in cui desideri che il comando estragga il contenuto come segue:

COPY <src> … <dest> 

Per esempio:

COPY /source/file/path  /destination/path 

Quale comando usare? (Best Practice)

Considerando le circostanze in cui è COPYstato introdotto il comando, è evidente che mantenere ADDera una questione di necessità. Docker ha rilasciato un documento ufficiale che descrive le migliori pratiche per la scrittura di Dockerfile, che sconsiglia esplicitamente di usare il ADDcomando.

Note sulla documentazione ufficiale di Docker che COPYdovrebbero essere sempre le istruzioni di riferimento in quanto più trasparenti di ADD.

Se è necessario copiare dal contesto di compilazione locale in un contenitore, attenersi all'utilizzo COPY.

Il team Docker inoltre scoraggia fortemente l'utilizzo ADDper scaricare e copiare un pacchetto da un URL. Invece, è più sicuro ed efficiente usare wget o curl all'interno di un RUNcomando. In questo modo, si evita di creare un ulteriore livello di immagine e si risparmia spazio.


4

Nota importante

Dovevo COPY decomprimere il pacchetto Java nell'immagine della mia finestra mobile. Quando ho confrontato la dimensione dell'immagine della finestra mobile creata usando ADD era 180 MB più grande di quella creata usando COPIA, tar -xzf * .tar.gz e rm * .tar.gz

Ciò significa che sebbene ADD rimuova il file tar, viene comunque mantenuto da qualche parte. E sta ingrandendo l'immagine !!


È ancora vero per l'ultima versione di Docker?
Navin,

3

Dal momento che Docker 17.05 COPYè usato con la --frombandiera in build multi-stage per copiare gli artefatti dalle fasi di build precedenti alla fase di build corrente.

dalla documentazione

Facoltativamente, COPIA accetta un flag --from=<name|index>che può essere utilizzato per impostare la posizione di origine su una fase di compilazione precedente (creata con FROM .. AS) che verrà utilizzata al posto di un contesto di compilazione inviato dall'utente.


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

Questo è un altro modo per copiare i file in un'immagine. L'opzione -v crea temporaneamente un volume che abbiamo usato durante il processo di compilazione.

Questo è diverso rispetto ad altri volumi perché monta una directory host solo per la build. I file possono essere copiati usando un comando cp standard.

Inoltre, come curl e wget, può essere eseguito in uno stack di comandi (viene eseguito in un singolo contenitore) e non moltiplicare la dimensione dell'immagine. ADD e COPY non sono impilabili perché eseguiti in un contenitore autonomo e i successivi comandi su quei file che vengono eseguiti in contenitori aggiuntivi moltiplicheranno la dimensione dell'immagine:

Con le opzioni impostate così:

-v /opt/mysql-staging:/tvol

Quanto segue verrà eseguito in un contenitore:

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

1
Quale versione docker ti trovi dove vedi quell'opzione? Non è documentato e non funziona sul mio client 1.12.1.
BMitch,

2
In realtà, questa funzione non è stata ancora inclusa nella versione principale, e ci sono ancora molte discussioni sull'argomento, quindi non dovremmo aspettarci da molto tempo ... Vedi la segnalazione di bug per maggiori informazioni: github.com/ finestra mobile / finestra mobile / numeri / 14080 .
jwatkins,

1
Sì, non esiste tale opzione (selezionata nell'ultima versione 17.06). Questa risposta è fuorviante. unknown shorthand flag: 'v' in -v
Kirby,

Davvero un commento fuorviante
Guido van Steen,

I volumi Docker non avevano nulla da fare qui nella risposta, per favore, se possibile, rispondere alla domanda diretta :), è facilmente la risposta negativa.
Majid Ali Khan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.