Apa perbedaan antara perintah 'COPY' dan 'ADD' di Dockerfile?

2196

Apa perbedaan antara perintah COPYdan ADDdalam Dockerfile, dan kapan saya akan menggunakan satu di atas yang lain?

COPY <src> <dest>

Instruksi COPY akan menyalin file-file baru dari <src>dan menambahkannya ke sistem file kontainer di jalurnya<dest>

ADD <src> <dest>

Instruksi ADD akan menyalin file baru dari <src>dan menambahkannya ke sistem file kontainer di path <dest>.

Steve
sumber
11
Lihat praktik terbaik: docs.docker.com/engine/userguide/eng-image/…
EricSonaron
9
Pada Juni 2018 referensi mengatakan bahwa ADD menambah gambar (yaitu file statis) sedangkan COPY menambah wadah (yaitu contoh runtime dari gambar). Tentunya ini menyiratkan bahwa COPY dijalankan setiap kali gambar Docker dijalankan, atau mungkin ini hanya kasus terminologi yang tidak konsisten?
Chris Robinson
14
Saya pikir itu terminologi yang tidak konsisten
Daniel Stevens
6
@ ChrisRobinson, mustahil untuk COPYmengeksekusi setiap kali dijalankan, karena itu tidak selalu memiliki akses ke konteks asli untuk mengambil konten.
Ken Williams

Jawaban:

2169

Anda harus memeriksa ADDdan COPYdokumentasi untuk deskripsi yang lebih rinci tentang perilaku mereka, tetapi secara singkat, perbedaan utama adalah bahwa ADDdapat melakukan lebih dari COPY:

  • ADDmemungkinkan <src>untuk menjadi URL
  • Mengacu pada komentar di bawah, ADD dokumentasi menyatakan bahwa:

    Jika arsip tar lokal dalam format kompresi yang dikenali (identitas, gzip, bzip2, atau xz) maka arsip itu dibongkar sebagai direktori. Sumber daya dari URL jarak jauh tidak terkompresi.

Perhatikan bahwa Praktik terbaik untuk menulis Dockerfiles menyarankan penggunaan di COPYmana keajaiban ADDtidak diperlukan. Jika tidak, Anda ( karena Anda harus mencari jawaban ini ) suatu hari nanti akan terkejut ketika Anda bermaksud menyalin keep_this_archive_intact.tar.gzke dalam wadah Anda, tetapi sebaliknya, Anda menyemprotkan isinya ke sistem file Anda.

icecrime
sumber
65
Hanya ingin mengklarifikasi sesuatu: menggunakan ADD dengan url ke .tar.gz JANGAN mengekstraksi arsip ke sistem file (saya periksa dua kali sekarang untuk memastikan dan dikonfirmasi)
Cecile
42
Ini adalah informasi penting dan merupakan kejahatan yang tidak dirujuk oleh referensi resmi Dockerfile dengan cara ini.
Cheeso
1
Tidak yakin, apakah ini berbeda untuk gambar ke gambar. Saya menggunakan gambar busybox dan ADD untuk file zip. Itu hanya muncul di direktori tujuan tanpa membuka ritsleting. Saya berasumsi, ekstraksi hanya terjadi untuk tarball, tapi saya belum memeriksanya sekarang.
Santosh Kumar Arjunan
4
@SantoshKumarArjunan: Dok Docker menyatakan yang berikut tentang ADD dan ekstraksi tar otomatis: 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 memungkinkan --from = <name | index>, di mana saya tidak dapat menemukan dukungan yang sama untuk ADD
Brandon
474

COPY adalah

Sama seperti 'ADD', tetapi tanpa penanganan tar dan URL jarak jauh.

Referensi langsung dari kode sumber .

caike
sumber
15
Apakah saya melihat ini dengan benar: ADDjuga membuat direktori yang tidak ada . Jadi, meskipun entah bagaimana berkecil di seluruh thread ini, ini memiliki keuntungan lebih COPYkarena Anda tidak harus menjalankan mkdirdan menyimpan beberapa mengetik
eli
3
COPY juga melakukannya @eli
bhordupur
Penjelasan terbaik sejauh ini. Mengapa itu bukan jawaban yang diterima?
xdevx32
141

Ada beberapa dokumentasi resmi tentang hal itu: Praktik Terbaik untuk Menulis Dockerfiles

Karena ukuran gambar penting, gunakan ADDuntuk mengambil paket dari URL jarak jauh sangat tidak disarankan; Anda harus menggunakan curlatau wgetsebagai gantinya. Dengan begitu Anda dapat menghapus file yang tidak lagi Anda perlukan setelah diekstraksi dan Anda tidak perlu menambahkan layer lain di gambar Anda.

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

Untuk item lain (file, direktori) yang tidak memerlukan ADDkemampuan ekstraksi tar otomatis, Anda harus selalu menggunakan COPY.

Victor Laskin
sumber
18
Docker mengatakan lebih suka COPY, karena lebih transparan. From the Docker File 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.
schemar
115

Dari Docker docs:

Tambah atau SALINAN

Meskipun ADD dan COPY secara fungsional serupa, secara umum, COPY lebih disukai. Itu karena lebih transparan daripada ADD. COPY hanya mendukung penyalinan dasar file lokal ke dalam wadah, sementara ADD memiliki beberapa fitur (seperti ekstraksi tar khusus lokal dan dukungan URL jarak jauh) yang tidak segera terlihat. Akibatnya, penggunaan terbaik untuk ADD adalah ekstraksi file tar lokal ke dalam gambar, seperti pada ADD rootfs.tar.xz /.

Lebih lanjut: Praktik terbaik untuk menulis Dockerfiles

eddd
sumber
46

Jika Anda ingin menambahkan xx.tar.gz ke a /usr/local dalam wadah, unzip, dan kemudian hapus paket terkompresi yang tidak berguna.

Untuk 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

Untuk ADD:

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

ADD mendukung ekstraksi tar khusus lokal. Selain itu, COPY akan menggunakan tiga lapisan, tetapi ADD hanya menggunakan satu lapisan.

BertLi
sumber
3
Ada alasan mengapa tidak hanya dua lapisan? 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 menyalin file / direktori dari host Anda ke gambar Anda.

ADD menyalin file / direktori dari host Anda ke gambar Anda, tetapi juga dapat mengambil URL jarak jauh, mengekstrak file TAR, dll ...

Menggunakan COPY untuk hanya menyalin file dan / atau direktori ke dalam konteks build.

Gunakan ADDuntuk mengunduh sumber daya jarak jauh, mengekstraksi file TAR, dll.

JSON C11
sumber
5
penjelasan sempurna untuk noob seperti saya
uneq95
17

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

"Meskipun ADD dan COPY secara fungsional serupa, secara umum, COPY lebih disukai. Itu karena itu lebih transparan daripada ADD. COPY hanya mendukung penyalinan dasar file lokal ke dalam wadah, sementara ADD memiliki beberapa fitur (seperti ekstraksi tar lokal saja dan dukungan URL jarak jauh) yang tidak segera jelas. Akibatnya, penggunaan terbaik untuk ADD adalah ekstraksi file tar lokal ke dalam gambar, seperti pada ADD rootfs.tar.xz /.

Jika Anda memiliki beberapa langkah Dockerfile yang menggunakan file berbeda dari konteks Anda, SALINKAN secara individual, daripada sekaligus. Ini akan memastikan bahwa cache build setiap langkah hanya tidak valid (memaksa langkah untuk dijalankan kembali) jika file yang diperlukan secara khusus berubah.

Sebagai contoh:

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

Menghasilkan lebih sedikit cacat cache untuk langkah RUN, daripada jika Anda menggunakan COPY. / tmp / sebelumnya.

Karena ukuran gambar penting, menggunakan ADD untuk mengambil paket dari URL jarak jauh sangat tidak disarankan; Anda harus menggunakan keriting atau gantinya. Dengan begitu Anda dapat menghapus file yang tidak lagi Anda perlukan setelah diekstraksi dan Anda tidak perlu menambahkan layer lain di gambar Anda. Misalnya, Anda harus menghindari melakukan hal-hal seperti:

 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

Dan sebaliknya, lakukan sesuatu seperti:

 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

Untuk item lain (file, direktori) yang tidak memerlukan kemampuan ekstraksi tar otomatis ADD, Anda harus selalu menggunakan COPY. "

jhpg
sumber
7

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

COPY dan ADD keduanya instruksi Dockerfile yang melayani tujuan yang sama. Mereka memungkinkan Anda menyalin file dari lokasi tertentu ke gambar Docker.

COPY mengambil src dan tujuan. Itu hanya memungkinkan Anda menyalin dalam file atau direktori lokal dari host Anda (mesin membangun gambar Docker) ke dalam gambar Docker itu sendiri.

ADD memungkinkan Anda melakukannya juga, tetapi juga mendukung 2 sumber lainnya. Pertama, Anda dapat menggunakan URL alih-alih file / direktori lokal. Kedua, Anda dapat mengekstrak file tar dari sumber langsung ke tujuan

Kasing penggunaan yang valid untuk ADD adalah ketika Anda ingin mengekstrak file tar lokal ke direktori tertentu di gambar Docker Anda.

Jika Anda menyalin dalam file lokal ke gambar Docker Anda, selalu gunakan COPY karena lebih eksplisit.

Shagun Pruthi
sumber
7

Saat membuat Dockerfile, ada dua perintah yang dapat Anda gunakan untuk menyalin file / direktori ke dalamnya - ADDdan COPY. Meskipun ada sedikit perbedaan dalam lingkup fungsi mereka, mereka pada dasarnya melakukan tugas yang sama.

Jadi, mengapa kita memiliki dua perintah, dan bagaimana kita tahu kapan harus menggunakan satu atau yang lain?

ADDPERINTAH DOCKER

Mari kita mulai dengan mencatat bahwa ADDperintahnya lebih tua dari COPY. Sejak peluncuran platform Docker, ADDinstruksi telah menjadi bagian dari daftar perintahnya.

Perintah menyalin file / direktori ke sistem file dari wadah yang ditentukan.

Sintaks dasar untuk ADDperintah ini adalah:

ADD <src> … <dest>

Ini termasuk sumber yang ingin Anda salin ( <src>) diikuti oleh tujuan tempat Anda ingin menyimpannya ( <dest>). Jika sumbernya adalah direktori,ADD salin semua yang ada di dalamnya (termasuk metadata sistem file).

Misalnya, jika file tersedia secara lokal dan Anda ingin menambahkannya ke direktori gambar, Anda mengetik:

ADD /source/file/path  /destination/path

ADDjuga dapat menyalin file dari URL. Itu dapat mengunduh file eksternal dan menyalinnya ke tujuan yang diinginkan. Sebagai contoh:

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

Fitur tambahan adalah bahwa ia menyalin file terkompresi, secara otomatis mengekstraksi konten di tujuan yang diberikan. Fitur ini hanya berlaku untuk file / direktori terkompresi yang disimpan secara lokal.

ADD source.file.tar.gz /temp

Ingatlah bahwa Anda tidak dapat mengunduh dan mengekstrak file / direktori terkompresi dari URL. Perintah tidak membongkar paket eksternal ketika menyalinnya ke sistem file lokal.

BURUH PELABUHAN COPYPERINTAH

Karena beberapa masalah fungsionalitas, Docker harus memperkenalkan perintah tambahan untuk menggandakan konten - COPY.

Tidak seperti ADDperintah yang terkait erat , COPYhanya memiliki satu fungsi yang ditugaskan. Perannya adalah untuk menduplikasi file / direktori di lokasi yang ditentukan dalam format yang ada. Ini berarti bahwa itu tidak berurusan dengan mengekstraksi file terkompresi, melainkan menyalinnya apa adanya.

Instruksi hanya dapat digunakan untuk file yang disimpan secara lokal. Karenanya, Anda tidak dapat menggunakannya dengan URL untuk menyalin file eksternal ke wadah Anda.

Untuk menggunakan COPYinstruksi, ikuti format perintah dasar:

Ketik sumber dan di mana Anda ingin perintah untuk mengekstrak konten sebagai berikut:

COPY <src> … <dest> 

Sebagai contoh:

COPY /source/file/path  /destination/path 

Perintah mana yang digunakan? (Praktik Terbaik)

Mempertimbangkan keadaan di mana COPYperintah itu diperkenalkan, jelas bahwa menjaga ADDadalah masalah kebutuhan. Docker merilis dokumen resmi yang menguraikan praktik terbaik untuk menulis Dockerfiles, yang secara eksplisit menyarankan agar tidak menggunakan ADDperintah.

Dokumentasi resmi Docker mencatat bahwa COPYharus selalu menjadi instruksi masuk karena lebih transparan daripada ADD.

Jika Anda perlu menyalin dari konteks pembangunan lokal ke dalam wadah, tetap gunakan COPY.

Tim Docker juga sangat tidak menyarankan ADDuntuk mengunduh dan menyalin paket dari URL. Sebaliknya, lebih aman dan lebih efisien untuk menggunakan wget atau curl dalam sebuah RUNperintah. Dengan melakukannya, Anda menghindari membuat lapisan gambar tambahan dan menghemat ruang.

Yogi Ghorecha
sumber
4

Catatan penting

Saya harus COPYdan untar paket java di gambar buruh pelabuhan saya. Ketika saya membandingkan ukuran gambar buruh pelabuhan yang dibuat menggunakan ADD itu 180MB lebih besar dari yang dibuat menggunakan COPY, tar -xzf * .tar.gz dan rm * .tar.gz

Ini berarti bahwa meskipun ADD menghapus file tar, ia masih disimpan di suatu tempat. Dan itu membuat gambar lebih besar !!

Avi Veltz
sumber
Apakah ini masih berlaku untuk versi terbaru Docker?
Navin
3

Karena Docker 17.05 COPYdigunakan dengan --frombendera dalam pembuatan multi-tahap untuk menyalin artefak dari tahap pembuatan sebelumnya ke tahap pembuatan saat ini.

dari dokumentasi

Secara opsional COPY menerima flag --from=<name|index>yang dapat digunakan untuk mengatur lokasi sumber ke tahap build sebelumnya (dibuat dengan FROM .. AS) yang akan digunakan sebagai ganti konteks build yang dikirim oleh pengguna.

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

Ini adalah cara lain untuk menyalin file ke gambar. Opsi -v untuk sementara membuat volume yang kami gunakan selama proses build.

Ini berbeda dengan volume lainnya karena ia me-mount direktori host untuk build saja. File dapat disalin menggunakan perintah cp standar.

Juga, seperti curl dan wget, itu dapat dijalankan dalam tumpukan perintah (berjalan dalam satu wadah) dan tidak mengalikan ukuran gambar. ADD dan COPY tidak dapat ditumpuk karena mereka berjalan dalam wadah mandiri dan perintah selanjutnya pada file-file yang dieksekusi dalam wadah tambahan akan melipatgandakan ukuran gambar:

Dengan opsi yang diatur sebagai berikut:

-v /opt/mysql-staging:/tvol

Berikut ini akan dieksekusi dalam satu wadah:

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
sumber
1
Apa versi buruh pelabuhan tempat Anda melihat opsi itu? Itu tidak didokumentasikan dan tidak berfungsi pada klien 1.12.1 saya.
BMitch
2
Sebenarnya, fitur ini masih belum termasuk dalam rilis utama, dan masih ada banyak diskusi tentang masalah ini, jadi kita seharusnya tidak mengharapkannya sebelum waktu yang lama ... Lihat laporan bug untuk info lebih lanjut: github.com/ buruh pelabuhan / buruh pelabuhan / masalah / 14080 .
jwatkins
1
Ya, tidak ada opsi seperti itu (diperiksa dalam versi terbaru 17.06). Jawaban ini menyesatkan. unknown shorthand flag: 'v' in -v
Kirby
Komentar yang menyesatkan memang
Guido van Steen
Volume Docker tidak ada hubungannya di sini dalam jawaban, tolong jika Anda dapat, jawab pertanyaan langsung :), itu dengan mudahnya adalah jawaban downvote.
Majid Ali Khan