Qual é a diferença entre os comandos 'COPY' e 'ADD' em um Dockerfile?

2196

Qual é a diferença entre os comandos COPYe ADDem um Dockerfile e quando eu usaria um sobre o outro?

COPY <src> <dest>

A instrução COPY copiará novos arquivos <src>e os adicionará ao sistema de arquivos do contêiner no caminho<dest>

ADD <src> <dest>

A instrução ADD copiará novos arquivos <src>e os adicionará ao sistema de arquivos do contêiner no caminho <dest>.

Steve
fonte
11
Veja as práticas recomendadas: docs.docker.com/engine/userguide/eng-image/…
EricSonaron 1/17/17
9
Como em junho de 2018, a referência diz que ADD é adicionado à imagem (por exemplo, um arquivo estático), enquanto COPY é adicionado ao contêiner (por exemplo, uma instância de tempo de execução da imagem). Certamente, isso implica que COPY é executado sempre que a imagem é executada no Docker, ou talvez este seja simplesmente um caso de terminologia inconsistente?
Chris Robinson
14
Eu acho que é a terminologia inconsistente
Daniel Stevens
6
@ Chrishrobinson, seria impossível COPYexecutar todas as vezes que é executado, porque não necessariamente tem acesso ao contexto original para capturar o conteúdo.
Ken Williams

Respostas:

2169

Você deve verificar a documentação ADDe COPYpara obter uma descrição mais detalhada de seus comportamentos, mas, em poucas palavras, a principal diferença é que isso ADDpode fazer mais do que COPY:

  • ADDpermite <src>ser um URL
  • Referindo-se aos comentários abaixo, a ADD documentação afirma que:

    Se for um arquivo tar local em um formato de compactação reconhecido (identidade, gzip, bzip2 ou xz), ele será descompactado como um diretório. Os recursos de URLs remotos não são descompactados.

Observe que as práticas recomendadas para escrever arquivos Dockerfiles sugerem usar COPYonde a mágica de ADDnão é necessária. Caso contrário, você ( desde que você procurou esta resposta ) provavelmente ficará surpreso algum dia quando pretender copiar keep_this_archive_intact.tar.gzno seu contêiner, mas, em vez disso, você pulveriza o conteúdo no seu sistema de arquivos.

icecrime
fonte
65
Só queria esclarecer uma coisa: usando ADD com uma URL para um .tar.gz não extrai o arquivo para o sistema de arquivos (eu dobro verificado agora para ter certeza e é confirmado)
Cecile
42
Esta é uma informação essencial e é um crime que a referência oficial do Dockerfile não esclareça a diferença dessa maneira.
Cheeso
1
Não tenho certeza, se isso difere de uma imagem para outra. Usei a imagem do busybox e ADD para um arquivo zip. Simplesmente apareceu no diretório de destino sem descompactar. Presumo que a extração ocorra apenas para o tarball, mas ainda não o verifiquei.
Santosh Kumar Arjunan
4
@SantoshKumarArjunan: Os documentos do Docker declaram o seguinte sobre o ADD e a extração automática de alcatrão: 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 = <nome | index>, onde não é possível encontrar o mesmo suporte para ADD
Brandon
474

COPY é

O mesmo que 'ADICIONAR', mas sem o manuseio de tar e URL remoto.

Referência diretamente do código fonte .

caike
fonte
15
Eu vejo isso corretamente: ADDtambém cria diretórios inexistentes . Assim, embora seja de alguma forma desanimado em toda esta discussão, tem uma vantagem sobre COPYporque você não tem que correr mkdire salvar a digitação
eli
3
COPY faz isso também @eli
bhordupur
Melhor explicação até agora. Por que não é a resposta aceita?
xdevx32 28/04
141

Há alguma documentação oficial sobre esse ponto: Práticas recomendadas para gravar arquivos de encaixe

Como o tamanho da imagem é importante, o uso ADDpara buscar pacotes de URLs remotas é altamente desencorajado; você deve usar curlou em wgetvez disso. Dessa forma, você pode excluir os arquivos desnecessários após a extração e não precisará adicionar outra camada à sua imagem.

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 outros itens (arquivos, diretórios) que não exigem ADDo recurso de extração automática de tar, você deve sempre usar COPY.

Victor Laskin
fonte
18
Docker diz que prefere COPY, porque é mais transparente. Das práticas recomendadas do arquivo 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.
schema 15/12
115

Dos documentos do Docker:

ADICIONAR ou COPIAR

Embora ADD e COPY sejam funcionalmente semelhantes, de um modo geral, COPY é o preferido. Isso porque é mais transparente que o ADD. O COPY suporta apenas a cópia básica de arquivos locais no contêiner, enquanto o ADD possui alguns recursos (como extração de tar somente local e suporte a URL remoto) que não são imediatamente óbvios. Conseqüentemente, o melhor uso para o ADD é a extração automática de arquivo tar local na imagem, como no ADD rootfs.tar.xz /.

Mais: Práticas recomendadas para escrever Dockerfiles

eddd
fonte
46

Se você deseja adicionar um xx.tar.gz a um /usr/local contêiner, descompacte-o e remova o pacote compactado inútil.

Para COPY:

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 adicionar:

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

ADD suporta extração de alcatrão somente local. Além disso, COPY usará três camadas, mas ADD usa apenas uma camada.

BertLi
fonte
3
Alguma razão para não apenas duas camadas? 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 um arquivo / diretório do seu host para a sua imagem.

ADD copia um arquivo / diretório do seu host para a sua imagem, mas também pode buscar URLs remotas, extrair arquivos TAR, etc ...

Usar COPY simplesmente para copiar arquivos e / ou diretórios no contexto da construção.

Use ADDpara baixar recursos remotos, extrair arquivos TAR, etc.

JSON C11
fonte
5
explicação perfeita para um noob como eu
uneq95
17

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

"Embora ADD e COPY sejam funcionalmente semelhantes, geralmente é preferido. Isso é porque é mais transparente que ADD. COPY suporta apenas a cópia básica de arquivos locais no contêiner, enquanto o ADD possui alguns recursos (como extração de alcatrão somente local e suporte a URL remoto) que não são imediatamente óbvios. Consequentemente, o melhor uso para o ADD é a extração automática de arquivos tar locais na imagem, como no ADD rootfs.tar.xz /.

Se você tiver várias etapas do Dockerfile que usam arquivos diferentes do seu contexto, copie-os individualmente, em vez de todos de uma vez. Isso garantirá que o cache de construção de cada etapa seja invalidado apenas (forçando a execução da etapa) se os arquivos especificamente necessários forem alterados.

Por exemplo:

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

Resulta em menos invalidações de cache para a etapa RUN, do que se você colocar a COPY. / tmp / antes dele.

Como o tamanho da imagem é importante, o uso do ADD para buscar pacotes de URLs remotas é altamente desencorajado; você deve usar curl ou wget. Dessa forma, você pode excluir os arquivos desnecessários após a extração e não precisará adicionar outra camada à sua imagem. Por exemplo, você deve evitar fazer coisas 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

E, em vez disso, faça 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 outros itens (arquivos, diretórios) que não exigem a capacidade de extração automática de tar do ADD, você deve sempre usar COPY. "

jhpg
fonte
7

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

COPY e ADD são instruções do Dockerfile que servem a propósitos semelhantes. Eles permitem copiar arquivos de um local específico em uma imagem do Docker.

COPY recebe um src e um destino. Ele permite copiar apenas um arquivo ou diretório local do host (a máquina que cria a imagem do Docker) para a própria imagem do Docker.

ADD também permite que você faça isso, mas também suporta outras 2 fontes. Primeiro, você pode usar uma URL em vez de um arquivo / diretório local. Em segundo lugar, você pode extrair um arquivo tar da fonte diretamente para o destino

Um caso de uso válido para ADD é quando você deseja extrair um arquivo tar local em um diretório específico na sua imagem do Docker.

Se você estiver copiando em arquivos locais para sua imagem do Docker, sempre use COPY, pois é mais explícito.

Shagun Pruthi
fonte
7

Ao criar um Dockerfile, existem dois comandos que você pode usar para copiar arquivos / diretórios nele - ADDe COPY. Embora haja pequenas diferenças no escopo de sua função, eles executam essencialmente a mesma tarefa.

Então, por que temos dois comandos e como sabemos quando usar um ou outro?

DOCKER ADDCOMMAND

Vamos começar observando que o ADDcomando é anterior a COPY. Desde o lançamento da plataforma Docker, a ADDinstrução faz parte de sua lista de comandos.

O comando copia arquivos / diretórios para um sistema de arquivos do contêiner especificado.

A sintaxe básica para o ADDcomando é:

ADD <src> … <dest>

Inclui a fonte que você deseja copiar ( <src>) seguida do destino onde deseja armazená-la ( <dest>). Se a origem for um diretório, ADDcopie tudo dentro dele (incluindo os metadados do sistema de arquivos).

Por exemplo, se o arquivo estiver disponível localmente e você desejar adicioná-lo ao diretório de uma imagem, digite:

ADD /source/file/path  /destination/path

ADDtambém pode copiar arquivos de um URL. Ele pode baixar um arquivo externo e copiá-lo para o destino desejado. Por exemplo:

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

Um recurso adicional é que ele copia arquivos compactados, extraindo automaticamente o conteúdo no destino especificado. Esse recurso se aplica apenas a arquivos / diretórios compactados armazenados localmente.

ADD source.file.tar.gz /temp

Lembre-se de que não é possível baixar e extrair um arquivo / diretório compactado de um URL. O comando não descompacta pacotes externos ao copiá-los para o sistema de arquivos local.

DOCKER COPYCOMMAND

Devido a alguns problemas de funcionalidade, o Docker teve que introduzir um comando adicional para duplicar o conteúdo - COPY.

Ao contrário de seu ADDcomando estreitamente relacionado , COPYpossui apenas uma função atribuída. Sua função é duplicar arquivos / diretórios em um local especificado em seu formato existente. Isso significa que ele não lida com a extração de um arquivo compactado, mas o copia como está.

A instrução pode ser usada apenas para arquivos armazenados localmente. Portanto, você não pode usá-lo com URLs para copiar arquivos externos para seu contêiner.

Para usar a COPYinstrução, siga o formato de comando básico:

Digite a fonte e onde deseja que o comando extraia o conteúdo da seguinte maneira:

COPY <src> … <dest> 

Por exemplo:

COPY /source/file/path  /destination/path 

Qual comando usar (prática recomendada)

Considerando as circunstâncias em que o COPYcomando foi introduzido, é evidente que manter ADDera uma questão de necessidade. O Docker lançou um documento oficial descrevendo as práticas recomendadas para a criação de arquivos Docker, que desaconselha explicitamente o uso do ADDcomando.

A documentação oficial do Docker observa que COPYsempre deve ser a instrução go-to, pois é mais transparente que ADD.

Se você precisar copiar do contexto de construção local para um contêiner, continue usando COPY.

A equipe do Docker também desencoraja fortemente o uso ADDpara baixar e copiar um pacote de um URL. Em vez disso, é mais seguro e eficiente usar o wget ou curl dentro de um RUNcomando. Ao fazer isso, você evita criar uma camada de imagem adicional e economiza espaço.

Yogi Ghorecha
fonte
4

Nota importante

Eu tive que COPYdescompactar o pacote java na minha imagem do docker. Quando comparei o tamanho da imagem do Docker criada usando ADD, ela era 180MB maior que a criada usando COPY, tar -xzf * .tar.gz e rm * .tar.gz

Isso significa que, embora o ADD remova o arquivo tar, ele ainda é mantido em algum lugar. E está aumentando a imagem !!

Avi Veltz
fonte
Isso ainda é verdade para a versão mais recente do Docker?
Navin 10/10
3

Desde o Docker 17.05 COPYé usado com o --fromsinalizador nas construções de vários estágios para copiar artefatos dos estágios de construção anteriores para o estágio de construção atual.

da documentação

Opcionalmente, COPY aceita um sinalizador --from=<name|index>que pode ser usado para definir o local de origem para um estágio de compilação anterior (criado com FROM .. AS) que será usado em vez de um contexto de compilação enviado pelo usuário.

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

Essa é outra maneira de copiar arquivos para uma imagem. A opção -v cria temporariamente um volume que usamos durante o processo de construção.

Isso é diferente dos outros volumes porque monta um diretório de host apenas para a construção. Os arquivos podem ser copiados usando um comando cp padrão.

Além disso, como curl e wget, ele pode ser executado em uma pilha de comandos (executada em um único contêiner) e não multiplicar o tamanho da imagem. ADD e COPY não são empilháveis ​​porque são executados em um contêiner autônomo e os comandos subsequentes nos arquivos executados em contêineres adicionais multiplicam o tamanho da imagem:

Com as opções definidas assim:

-v /opt/mysql-staging:/tvol

O seguinte será executado em um contêiner:

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
fonte
1
Em qual versão do docker você está onde vê essa opção? Não está documentado e não funciona no meu cliente 1.12.1.
BMitch 23/09/16
2
Na verdade, esse recurso ainda não foi incluído no release principal e ainda há muita discussão sobre o assunto, portanto não devemos esperar isso por um longo tempo ... Consulte o relatório de erros para obter mais informações: github.com/ docker / docker / Issues / 14080 .
jwatkins
1
Sim, não existe essa opção (marcada na versão mais recente 17.06). Esta resposta é enganosa. unknown shorthand flag: 'v' in -v
Kirby
Comentário enganoso, na verdade #
Guido van Steen
Os volumes do Docker não tiveram nada a ver aqui na resposta, por favor, se você puder, responda à pergunta direta :), é facilmente a resposta com voto negativo.
Majid Ali Khan