Jaka jest różnica między poleceniami „KOPIUJ” i „DODAJ” w Dockerfile?


2195

Jaka jest różnica między poleceniami COPYi ADDw pliku Docker i kiedy miałbym używać jednego nad drugim?

COPY <src> <dest>

Instrukcja COPY skopiuje nowe pliki <src>i doda je do systemu plików kontenera pod ścieżką<dest>

ADD <src> <dest>

Instrukcja ADD skopiuje nowe pliki <src>i doda je do systemu plików kontenera pod ścieżką <dest>.



9
Według stanu na czerwiec 2018 r. Odniesienie mówi, że ADD dodaje do obrazu (tj. Plik statyczny), podczas gdy COPY dodaje do kontenera (tj. Wystąpienie środowiska wykonawczego obrazu). Z pewnością oznacza to, że funkcja COPY jest wykonywana za każdym razem, gdy obraz jest uruchamiany w Docker, a może jest to po prostu niespójna terminologia?
Chris Robinson

14
Myślę, że to niespójna terminologia
Daniel Stevens,

6
@ChrisRobinson, byłoby niemożliwe COPYdo wykonania przy każdym uruchomieniu, ponieważ niekoniecznie ma dostęp do oryginalnego kontekstu, aby pobrać zawartość.
Ken Williams

Odpowiedzi:


2165

Powinieneś sprawdzić dokumentację ADDi COPYuzyskać bardziej szczegółowy opis ich zachowań, ale w skrócie, główną różnicą jest to, że ADDmożna zrobić więcej niż COPY:

  • ADDpozwala <src>być adresem URL
  • Odnosząc się do poniższych komentarzy, ADD dokumentacja stwierdza, że:

    Jeśli jest to lokalne archiwum tar w rozpoznanym formacie kompresji (tożsamość, gzip, bzip2 lub xz), wówczas jest rozpakowywane jako katalog. Zasoby ze zdalnych adresów URL nie są dekompresowane.

Zauważ, że najlepsze praktyki pisania Dockerfiles sugerują używanie COPYtam, gdzie magia ADDnie jest wymagana. W przeciwnym razie możesz ( ponieważ musiałeś poszukać tej odpowiedzi ) pewnego dnia zdziwić się, gdy będziesz chciał skopiować keep_this_archive_intact.tar.gzdo swojego kontenera, ale zamiast tego rozpylisz zawartość na swój system plików.


65
Chciałem tylko coś wyjaśnić: użycie ADD z adresem URL do pliku .tar.gz NIE WYCIĄGUJE archiwum do systemu plików (sprawdziłem teraz dwukrotnie, aby się upewnić i zostało to potwierdzone)
Cecile,

42
Jest to niezbędna informacja i przestępstwem jest to, że oficjalne odniesienie do pliku Dockerfile nie wyjaśnia w ten sposób różnicy.
Cheeso

1
Nie jestem pewien, czy różni się to dla obrazu do obrazu. Użyłem obrazu busybox i DODAJ do pliku zip. Po prostu pojawił się w katalogu docelowym bez rozpakowywania. Zakładam, że ekstrakcja odbywa się tylko dla archiwum, ale teraz tego nie sprawdziłem.
Santosh Kumar Arjunan

4
@SantoshKumarArjunan: Dokumenty Dockera mówią o ADD i automatycznym wyodrębnianiu smoły: 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 pozwala --from = <name | index>, gdzie nie mogę znaleźć takiego samego wsparcia dla ADD
Brandon

474

COPY jest

Taki sam jak „DODAJ”, ale bez obsługi tar i zdalnej obsługi adresów URL.

Odwołanie prosto z kodu źródłowego .


15
Czy widzę to poprawnie: tworzyADD także nieistniejące katalogi . Tak więc, mimo że jest w jakiś sposób zniechęca całego tego wątku, ma przewagę nad COPYponieważ nie trzeba uruchamiać mkdiri zaoszczędzić trochę pisanie
Eli

3
COPY też to robi @eli
bhordupur

Najlepsze wyjaśnienie do tej pory. Dlaczego nie jest to akceptowana odpowiedź?
xdevx32

141

Istnieje na ten temat oficjalna dokumentacja: Najlepsze praktyki pisania plików Docker

Ponieważ rozmiar obrazu ma znaczenie, ADDzdecydowanie zaleca się używanie do pobierania pakietów ze zdalnych adresów URL; powinieneś użyć curllub wgetzamiast tego. W ten sposób możesz usunąć niepotrzebne pliki po ich wyodrębnieniu i nie będziesz musiał dodawać kolejnej warstwy na obrazie.

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

W przypadku innych elementów (plików, katalogów), które nie wymagają ADDfunkcji automatycznego wyodrębniania tar, należy zawsze używać COPY.



18
Docker mówi, że woli COPY, ponieważ jest bardziej przejrzysty. Z pliku Docker Best Practices (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.
schemat

115

Z dokumentów Docker:

DODAJ lub KOPIUJ

Chociaż funkcje DODAJ i KOPIUJ są funkcjonalnie podobne, ogólnie mówiąc, preferowana jest KOPIA. To dlatego, że jest bardziej przejrzysty niż ADD. Funkcja COPY obsługuje tylko podstawowe kopiowanie plików lokalnych do kontenera, podczas gdy ADD ma pewne funkcje (takie jak lokalna ekstrakcja tar i obsługa zdalnego adresu URL), które nie są od razu oczywiste. W związku z tym najlepszym zastosowaniem ADD jest automatyczna ekstrakcja lokalnego pliku tar do obrazu, tak jak w ADD rootfs.tar.xz /.

Więcej: Najlepsze praktyki pisania Dockerfiles


46

Jeśli chcesz dodać plik xx.tar.gz do /usr/localkontenera, rozpakuj go, a następnie usuń niepotrzebny skompresowany pakiet.

Do kopiowania:

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

Do dodania:

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

ADD obsługuje tylko lokalną ekstrakcję smoły. Poza tym COPY będzie używać trzech warstw, ale ADD używa tylko jednej warstwy.


3
Jest jakiś powód, dla którego nie tylko dwie warstwy? 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 kopiuje plik / katalog z twojego hosta na twój obraz.

ADD kopiuje plik / katalog z twojego hosta na obraz, ale może również pobierać zdalne adresy URL, wyodrębniać pliki TAR itp.

Służy COPYdo prostego kopiowania plików i / lub katalogów w kontekście kompilacji.

Służy ADDdo pobierania zdalnych zasobów, wypakowywania plików TAR itp.


4
doskonałe wytłumaczenie dla nooba takiego jak ja
uneq95

17

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

„Chociaż ADD i COPY są funkcjonalnie podobne, ogólnie rzecz biorąc, preferuje się COPY. Jest tak, ponieważ jest bardziej przejrzysty niż ADD. COPY obsługuje tylko podstawowe kopiowanie plików lokalnych do kontenera, podczas gdy ADD ma pewne funkcje (takie jak lokalne wyodrębnianie tar i zdalna obsługa adresów URL), które nie są od razu oczywiste. Dlatego najlepszym rozwiązaniem dla ADD jest lokalna ekstrakcja pliku tar do obrazu, tak jak w ADD rootfs.tar.xz /.

Jeśli masz wiele kroków Dockerfile, które używają innych plików z twojego kontekstu, KOPIUJ je indywidualnie, a nie wszystkie naraz. Zapewni to, że pamięć podręczna kompilacji każdego kroku zostanie unieważniona (wymuszając ponowne uruchomienie kroku), jeśli zmienią się specjalnie wymagane pliki.

Na przykład:

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

Powoduje mniej unieważnień pamięci podręcznej dla kroku RUN, niż jeśli umieścisz KOPIUJ. / tmp / przed nim.

Ponieważ rozmiar obrazu ma znaczenie, użycie ADD do pobierania pakietów ze zdalnych adresów URL jest zdecydowanie odradzane; zamiast tego powinieneś użyć curl lub wget. W ten sposób możesz usunąć niepotrzebne pliki po ich wyodrębnieniu i nie będziesz musiał dodawać kolejnej warstwy na obrazie. Na przykład powinieneś unikać robienia takich rzeczy jak:

 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

Zamiast tego zrób coś takiego:

 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

W przypadku innych elementów (plików, katalogów), które nie wymagają funkcji automatycznego wyodrębniania tar ADD, należy zawsze używać funkcji KOPIUJ ”.


7

Źródło: https://nickjanetakis.com/blog/docker-tip-2-the-difference-between-copy-and-add-in-a-dockerile :

KOPIUJ i DODAJ to instrukcje Dockerfile, które służą do podobnych celów. Pozwalają kopiować pliki z określonej lokalizacji do obrazu Docker.

Funkcja COPY przyjmuje kod źródłowy i docelowy. Pozwala tylko skopiować lokalny plik lub katalog z hosta (maszyny budującej obraz Docker) do samego obrazu Docker.

ADD pozwala ci to zrobić, ale obsługuje również 2 inne źródła. Po pierwsze, możesz użyć adresu URL zamiast lokalnego pliku / katalogu. Po drugie, możesz wyodrębnić plik tar ze źródła bezpośrednio do miejsca docelowego

Prawidłowym przypadkiem użycia dla ADD jest, gdy chcesz wyodrębnić lokalny plik tar do określonego katalogu w obrazie Docker.

Jeśli kopiujesz w plikach lokalnych do obrazu Docker, zawsze używaj KOPIUJ, ponieważ jest to bardziej wyraźne.


7

Podczas tworzenia pliku Docker istnieją dwa polecenia, których można użyć do skopiowania do niego plików / katalogów - ADDi COPY. Chociaż istnieją niewielkie różnice w zakresie ich funkcji, zasadniczo wykonują to samo zadanie.

Dlaczego więc mamy dwa polecenia i skąd wiemy, kiedy użyć jednego lub drugiego?

DOKER ADDPOLECENIE

Zacznijmy od zauważenia, że ADDpolecenie jest starsze niż COPY. Od momentu uruchomienia platformy Docker,ADD instrukcja jest częścią listy poleceń.

Polecenie kopiuje pliki / katalogi do systemu plików określonego kontenera.

Podstawowa składnia ADDpolecenia to:

ADD <src> … <dest>

Zawiera źródło, które chcesz skopiować ( <src>), a następnie miejsce docelowe, w którym chcesz je zapisać ( <dest>). Jeśli źródłem jest katalog,ADD skopiuj wszystko z niego (łącznie z metadanymi systemu plików).

Na przykład, jeśli plik jest dostępny lokalnie i chcesz go dodać do katalogu obrazu, wpisz:

ADD /source/file/path  /destination/path

ADDmoże również kopiować pliki z adresu URL. Może pobrać plik zewnętrzny i skopiować go do żądanego miejsca docelowego. Na przykład:

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

Dodatkową funkcją jest to, że kopiuje skompresowane pliki, automatycznie wyodrębniając zawartość w danym miejscu docelowym. Ta funkcja dotyczy tylko lokalnie przechowywanych skompresowanych plików / katalogów.

ADD source.file.tar.gz /temp

Pamiętaj, że nie można pobrać i wyodrębnić skompresowanego pliku / katalogu z adresu URL. Polecenie nie rozpakowuje pakietów zewnętrznych podczas kopiowania ich do lokalnego systemu plików.

DOKER COPYPOLECENIE

Z powodu pewnych problemów z funkcjonalnością Docker musiał wprowadzić dodatkowe polecenie do powielania treści - COPY.

W przeciwieństwie do ściśle powiązanego ADDpolecenia, COPYma tylko jedną przypisaną funkcję. Jego rolą jest duplikowanie plików / katalogów w określonej lokalizacji w ich istniejącym formacie. Oznacza to, że nie zajmuje się wypakowywaniem skompresowanego pliku, a raczej kopiuje go takim, jakim jest.

Z instrukcji można korzystać tylko w przypadku plików przechowywanych lokalnie. Dlatego nie można go używać z adresami URL do kopiowania plików zewnętrznych do kontenera.

Aby skorzystać z COPYinstrukcji, postępuj zgodnie z podstawowym formatem poleceń:

Wpisz źródło i miejsce, w którym polecenie ma wyodrębnić zawartość w następujący sposób:

COPY <src> … <dest> 

Na przykład:

COPY /source/file/path  /destination/path 

Którego polecenia użyć? (Najlepsza praktyka)

Biorąc pod uwagę okoliczności, w których COPYpolecenie zostało wprowadzone, oczywiste jest, że dotrzymywanie go ADDbyło koniecznością. Docker opublikował oficjalny dokument opisujący najlepsze praktyki pisania Dockerfiles, który wyraźnie odradza korzystanie zADD polecenia.

Oficjalna dokumentacja Dockera wskazuje, że COPYpowinna ona zawsze być instrukcją, ponieważ jest bardziej przejrzysta niż ADD.

Jeśli chcesz skopiować z lokalnego kontekstu kompilacji do kontenera, trzymaj się COPY.

Zespół dokerów zdecydowanie odradza również ADDpobieranie i kopiowanie pakietu z adresu URL. Zamiast tego bezpieczniej i wydajniej jest używać wget lub curl w RUNpoleceniu. W ten sposób unikasz tworzenia dodatkowej warstwy obrazu i oszczędzasz miejsce.


4

Ważna uwaga

Musiałem COPYrozpakować pakiet Java na obrazie dokera. Kiedy porównałem rozmiar obrazu dokera utworzonego za pomocą ADD, był o 180 MB większy niż ten utworzony za pomocą COPY, tar -xzf * .tar.gz i rm * .tar.gz

Oznacza to, że chociaż ADD usuwa plik tar, nadal jest gdzieś przechowywany. I dzięki temu obraz jest większy !!


Czy nadal dotyczy to najnowszej wersji Dockera?
Navin,

3

Ponieważ Docker 17.05 COPYjest używany z --fromflagą w kompilacjach wieloetapowych do kopiowania artefaktów z poprzednich etapów kompilacji do bieżącego etapu kompilacji.

z dokumentacji

Opcjonalnie COPY akceptuje flagę, --from=<name|index>której można użyć, aby ustawić lokalizację źródłową na poprzedni etap kompilacji (utworzony za pomocą FROM .. AS), który będzie używany zamiast kontekstu kompilacji wysłanego przez użytkownika.


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

To kolejny sposób kopiowania plików do obrazu. Opcja -v tymczasowo tworzy wolumin, którego użyliśmy podczas procesu kompilacji.

Różni się to od innych woluminów, ponieważ montuje katalog hosta tylko dla kompilacji. Pliki można skopiować za pomocą standardowej komendy cp.

Podobnie jak curl i wget, można go uruchomić na stosie poleceń (działa w jednym kontenerze) i nie pomnożyć rozmiaru obrazu. ADD i COPY nie można ustawiać jeden na drugim, ponieważ działają w autonomicznym kontenerze, a kolejne polecenia na plikach wykonywanych w dodatkowych kontenerach zwiększają rozmiar obrazu:

Po ustawieniu opcji w ten sposób:

-v /opt/mysql-staging:/tvol

W jednym kontenerze zostaną wykonane następujące czynności:

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
W jakiej wersji dokera widzisz tę opcję? Nie jest to udokumentowane i nie działa na moim kliencie 1.12.1.
BMitch

2
W rzeczywistości ta funkcja nie została jeszcze uwzględniona w głównym wydaniu i wciąż jest wiele dyskusji na ten temat, więc nie powinniśmy się jej spodziewać przez długi czas ... Zobacz raport o błędach, aby uzyskać więcej informacji: github.com/ doker / doker / problemy / 14080 .
jwatkins,

1
Tak, nie ma takiej opcji (zaznaczone w najnowszej wersji 17.06). Ta odpowiedź jest myląca. unknown shorthand flag: 'v' in -v
Kirby

Rzeczywiście wprowadzający w błąd komentarz
Guido van Steen

Woluminy dokerów nie miały tu nic do roboty, proszę, jeśli możesz, odpowiedz na bezpośrednie pytanie :), jest to odpowiedź negatywna.
Majid Ali Khan
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.