Sự khác biệt giữa các lệnh 'COPY' và 'ADD' trong Dockerfile là gì?


2196

Sự khác biệt giữa các lệnh COPYADDlệnh trong Dockerfile là gì và khi nào tôi sẽ sử dụng lệnh này so với lệnh khác?

COPY <src> <dest>

Lệnh COPY sẽ sao chép các tệp mới từ <src>và thêm chúng vào hệ thống tệp của bộ chứa tại đường dẫn<dest>

ADD <src> <dest>

Lệnh ADD sẽ sao chép các tệp mới từ <src>và thêm chúng vào hệ thống tệp của bộ chứa tại đường dẫn <dest>.



9
Vào tháng 6 năm 2018, tài liệu tham khảo nói rằng ADD thêm vào hình ảnh (tức là một tệp tĩnh) trong khi COPY thêm vào vùng chứa (tức là một thể hiện thời gian chạy của hình ảnh). Chắc chắn điều này ngụ ý rằng COPY được thực thi mỗi khi hình ảnh là Docker chạy, hoặc có thể đây chỉ là một trường hợp thuật ngữ không nhất quán?
Chris Robinson

14
Tôi nghĩ đó là thuật ngữ không nhất quán
Daniel Stevens

6
@ChrisRobinson, không thể COPYthực thi mỗi khi nó chạy, bởi vì nó không nhất thiết phải có quyền truy cập vào bối cảnh ban đầu để lấy nội dung.
Ken Williams

Câu trả lời:


2169

Bạn nên kiểm tra ADDCOPYtài liệu để mô tả chi tiết hơn về hành vi của họ, nhưng tóm lại, sự khác biệt chính là ADDcó thể làm được nhiều hơn COPY:

  • ADDcho phép <src>là một URL
  • Đề cập đến ý kiến ​​dưới đây, ADD tài liệu nói rằng:

    Nếu là một kho lưu trữ tar cục bộ ở định dạng nén được nhận dạng (nhận dạng, gzip, bzip2 hoặc xz) thì nó được giải nén dưới dạng thư mục. Tài nguyên từ các URL từ xa không được giải nén.

Lưu ý rằng các cách thực hành tốt nhất để viết Dockerfiles cho thấy sử dụng COPYma thuật ADDkhông bắt buộc. Mặt khác, bạn ( vì bạn phải tìm kiếm câu trả lời này ) có thể sẽ bị bất ngờ vào một ngày nào đó khi bạn có ý định sao chép keep_this_archive_intact.tar.gzvào thùng chứa của mình, nhưng thay vào đó, bạn phun nội dung lên hệ thống tệp của mình.


65
Chỉ muốn làm rõ điều gì đó: sử dụng ADD với một url đến .tar.gz KHÔNG GIỚI THIỆU kho lưu trữ vào hệ thống tập tin (Tôi đã kiểm tra lại ngay bây giờ để chắc chắn và nó đã được xác nhận)
Cecile

42
Đây là thông tin cần thiết và đó là tội ác mà tài liệu tham khảo Dockerfile chính thức không làm rõ sự khác biệt theo cách này.
Cheeso

1
Không chắc chắn, nếu điều này khác nhau cho một hình ảnh để hình ảnh. Tôi đã sử dụng hình ảnh busybox và THÊM cho một tệp zip. Nó chỉ đơn giản là xuất hiện trong thư mục đích mà không giải nén. Tôi giả sử, trích xuất chỉ xảy ra với tarball, nhưng tôi chưa kiểm tra điều đó ngay bây giờ.
Santosh Kumar Arjunan

4
@SantoshKumarArjunan: Docker docs nêu sau đây về ADD và trích xuất tar tự động: 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 cho phép --from = <name | index>, nơi tôi không thể tìm thấy sự hỗ trợ tương tự cho ADD
Brandon

474

COPY

Tương tự như 'THÊM', nhưng không có xử lý URL từ xa và tar.

Tham chiếu trực tiếp từ mã nguồn .


15
Tôi có thấy điều này chính xác không: ADDcũng tạo các thư mục không tồn tại . Vì vậy, mặc dù có phần nản lòng trong toàn bộ chủ đề này, nhưng nó có lợi thế hơn COPYvì bạn không phải chạy mkdirvà lưu một số thao tác gõ
eli

3
SAO CHÉP cũng vậy @eli
bhordupur

Giải thích tốt nhất cho đến nay. Tại sao nó không phải là câu trả lời được chấp nhận?
xdevx32

141

Có một số tài liệu chính thức về điểm đó: Thực tiễn tốt nhất để viết Dockerfiles

Bởi vì kích thước hình ảnh có vấn đề, việc sử dụng ADDđể tìm nạp các gói từ các URL từ xa được khuyến khích mạnh mẽ; bạn nên sử dụng curlhoặc wgetthay vào đó. Bằng cách đó, bạn có thể xóa các tệp bạn không còn cần sau khi chúng được giải nén và bạn sẽ không phải thêm một lớp khác trong hình ảnh của mình.

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

Đối với các mục khác (tệp, thư mục) không yêu cầu ADDkhả năng tự động trích xuất tar, bạn nên luôn luôn sử dụng COPY.



18
Docker nói thích hơn COPY, vì nó minh bạch hơn. Từ tập tin Docker Thực tiễn tốt nhất (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

Từ tài liệu Docker:

THÊM hoặc SAO CHÉP

Mặc dù ADD và COPY tương tự nhau về mặt chức năng, nói chung, COPY được ưa thích hơn. Đó là bởi vì nó minh bạch hơn THÊM. COPY chỉ hỗ trợ sao chép cơ bản các tệp cục bộ vào vùng chứa, trong khi ADD có một số tính năng (như trích xuất tar chỉ cục bộ và hỗ trợ URL từ xa) không rõ ràng ngay lập tức. Do đó, cách sử dụng tốt nhất cho ADD là tự động trích xuất tệp tar cục bộ vào hình ảnh, như trong ADD rootfs.tar.xz /.

Xem thêm: Cách thực hành tốt nhất để viết Dockerfiles


46

Nếu bạn muốn thêm xx.tar.gz /usr/localvào thùng chứa, hãy giải nén nó và sau đó xóa gói nén vô dụng.

Đối với BẢN SAO:

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

Cho thêm:

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

ADD hỗ trợ khai thác tar chỉ cục bộ. Bên cạnh đó, COPY sẽ sử dụng ba lớp, nhưng ADD chỉ sử dụng một lớp.


3
Bất kỳ lý do tại sao không chỉ là hai lớp? 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 sao chép một tập tin / thư mục từ máy chủ của bạn vào hình ảnh của bạn.

ADD sao chép một tập tin / thư mục từ máy chủ của bạn vào hình ảnh của bạn, nhưng cũng có thể tìm nạp các URL từ xa, trích xuất các tệp TAR, v.v ...

Sử dụng COPYđể chỉ sao chép các tập tin và / hoặc thư mục vào bối cảnh xây dựng.

Sử dụng ADDđể tải xuống các tài nguyên từ xa, trích xuất các tệp TAR, v.v.


5
lời giải thích hoàn hảo cho một người mới như tôi
uneq95

17

Từ tài liệu Docker: https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#add-or-copy

"Mặc dù ADD và COPY tương tự nhau về mặt chức năng, nói chung, COPY được ưa thích hơn. Điều đó là vì nó minh bạch hơn ADD. COPY chỉ hỗ trợ sao chép cơ bản các tệp cục bộ vào thùng chứa, trong khi ADD có một số tính năng (như trích xuất tar chỉ cục bộ và Hỗ trợ URL từ xa) không rõ ràng ngay lập tức. Do đó, cách sử dụng tốt nhất cho ADD là tự động trích xuất tệp tar cục bộ vào hình ảnh, như trong ADD rootfs.tar.xz /.

Nếu bạn có nhiều bước Dockerfile sử dụng các tệp khác nhau từ ngữ cảnh của bạn, hãy sao chép chúng riêng lẻ, thay vì tất cả cùng một lúc. Điều này sẽ đảm bảo rằng bộ đệm xây dựng của mỗi bước chỉ bị vô hiệu (buộc bước này phải được chạy lại) nếu các tệp được yêu cầu cụ thể thay đổi.

Ví dụ:

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

Kết quả là làm mất hiệu lực bộ đệm ít hơn cho bước RUN, so với khi bạn đặt COPY. / tmp / trước nó.

Vì kích thước hình ảnh có vấn đề, việc sử dụng THÊM để tìm nạp các gói từ các URL từ xa được khuyến khích mạnh mẽ; thay vào đó bạn nên sử dụng curl hoặc wget. Bằng cách đó, bạn có thể xóa các tệp bạn không còn cần sau khi chúng được giải nén và bạn sẽ không phải thêm một lớp khác trong hình ảnh của mình. Ví dụ: bạn nên tránh làm những việc như:

 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

Và thay vào đó, hãy làm một cái gì đó như:

 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

Đối với các mục khác (tệp, thư mục) không yêu cầu khả năng tự động trích xuất tar của ADD, bạn nên luôn luôn sử dụng COPY. "


7

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

COPY và ADD đều là các hướng dẫn Dockerfile phục vụ các mục đích tương tự. Họ cho phép bạn sao chép các tệp từ một vị trí cụ thể vào hình ảnh Docker.

COPY mất một src và đích. Nó chỉ cho phép bạn sao chép trong một tệp hoặc thư mục cục bộ từ máy chủ của bạn (máy xây dựng hình ảnh Docker) vào hình ảnh Docker.

THÊM cho phép bạn làm điều đó quá, nhưng nó cũng hỗ trợ 2 nguồn khác. Đầu tiên, bạn có thể sử dụng URL thay vì tệp / thư mục cục bộ. Thứ hai, bạn có thể trích xuất một tệp tar từ nguồn trực tiếp vào đích

Trường hợp sử dụng hợp lệ cho ADD là khi bạn muốn trích xuất tệp tar cục bộ vào một thư mục cụ thể trong hình ảnh Docker của bạn.

Nếu bạn đang sao chép các tệp cục bộ vào hình ảnh Docker của mình, hãy luôn sử dụng COPY vì nó rõ ràng hơn.


7

Khi tạo Dockerfile, có hai lệnh mà bạn có thể sử dụng để sao chép tệp / thư mục vào đó - ADDCOPY. Mặc dù có sự khác biệt nhỏ trong phạm vi chức năng của chúng, về cơ bản chúng thực hiện cùng một nhiệm vụ.

Vậy, tại sao chúng ta có hai lệnh và làm thế nào để biết khi nào nên sử dụng lệnh này hay lệnh kia?

Docker ADDCOMMAND

Hãy bắt đầu bằng cách lưu ý rằng ADDlệnh cũ hơn COPY. Kể từ khi ra mắt nền tảng Docker, ADDhướng dẫn đã là một phần trong danh sách các lệnh của nó.

Lệnh sao chép tệp / thư mục vào một hệ thống tệp của vùng chứa được chỉ định.

Cú pháp cơ bản của ADDlệnh là:

ADD <src> … <dest>

Nó bao gồm nguồn bạn muốn sao chép ( <src>) theo sau là đích bạn muốn lưu trữ ( <dest>). Nếu nguồn là một thư mục,ADD sao chép mọi thứ bên trong nó (bao gồm siêu dữ liệu hệ thống tệp).

Ví dụ: nếu tệp có sẵn cục bộ và bạn muốn thêm nó vào thư mục của một hình ảnh, bạn gõ:

ADD /source/file/path  /destination/path

ADDcũng có thể sao chép các tập tin từ một URL. Nó có thể tải xuống một tập tin bên ngoài và sao chép nó đến đích mong muốn. Ví dụ:

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

Một tính năng bổ sung là nó sao chép các tệp nén, tự động trích xuất nội dung ở đích đã cho. Tính năng này chỉ áp dụng cho các tệp / thư mục nén được lưu trữ cục bộ.

ADD source.file.tar.gz /temp

Hãy nhớ rằng bạn không thể tải xuống và trích xuất một tập tin / thư mục nén từ một URL. Lệnh không giải nén các gói bên ngoài khi sao chép chúng vào hệ thống tệp cục bộ.

DOCKER COPYCOMMAND

Do một số vấn đề về chức năng, Docker đã phải giới thiệu một lệnh bổ sung để sao chép nội dung - COPY.

Không giống như ADDlệnh liên quan chặt chẽ của nó , COPYchỉ có một chức năng được gán. Vai trò của nó là sao chép các tập tin / thư mục ở một vị trí được chỉ định theo định dạng hiện có của chúng. Điều này có nghĩa là nó không giải quyết được việc trích xuất một tệp nén mà thay vào đó là sao chép nó.

Hướng dẫn chỉ có thể được sử dụng cho các tệp được lưu trữ cục bộ. Do đó, bạn không thể sử dụng nó với các URL để sao chép các tệp bên ngoài vào thùng chứa của bạn.

Để sử dụng COPYhướng dẫn, hãy làm theo định dạng lệnh cơ bản:

Nhập nguồn và nơi bạn muốn lệnh trích xuất nội dung như sau:

COPY <src> … <dest> 

Ví dụ:

COPY /source/file/path  /destination/path 

Sử dụng lệnh nào? (Thực hành tốt nhất)

Xem xét các trường hợp trong đó COPYlệnh được đưa ra, rõ ràng là giữ ADDlà một vấn đề cần thiết. Docker đã phát hành một tài liệu chính thức phác thảo các thực tiễn tốt nhất để viết Dockerfiles, trong đó khuyên rõ ràng không nên sử dụngADD lệnh.

Tài liệu chính thức của Docker COPYluôn luôn phải là hướng dẫn sử dụng vì nó minh bạch hơn ADD.

Nếu bạn cần sao chép từ bối cảnh xây dựng cục bộ vào một thùng chứa, hãy sử dụng COPY.

Nhóm Docker cũng không khuyến khích sử dụng ADDđể tải xuống và sao chép gói từ URL. Thay vào đó, sẽ an toàn và hiệu quả hơn khi sử dụng wget hoặc curl trong một RUNlệnh. Bằng cách đó, bạn tránh tạo ra một lớp hình ảnh bổ sung và tiết kiệm không gian.


4

Lưu ý quan trọng

Tôi đã phải COPYvà gỡ bỏ gói java trong hình ảnh docker của tôi. Khi tôi so sánh kích thước hình ảnh docker được tạo bằng ADD, nó lớn hơn 180 MB so với kích thước được tạo bằng COPY, tar -xzf * .tar.gz và rm * .tar.gz

Điều này có nghĩa là mặc dù ADD loại bỏ tệp tar, nó vẫn được giữ ở đâu đó. Và nó làm cho hình ảnh lớn hơn !!


Điều này có còn đúng với phiên bản mới nhất của Docker không?
Navin

3

Vì Docker 17.05 COPYđược sử dụng với --fromcờ trong các bản dựng nhiều giai đoạn để sao chép các tạo phẩm từ các giai đoạn xây dựng trước đó sang giai đoạn xây dựng hiện tại.

từ tài liệu

Tùy chọn COPY chấp nhận một cờ --from=<name|index>có thể được sử dụng để đặt vị trí nguồn thành giai đoạn xây dựng trước đó (được tạo bằng TỪ .. NHƯ) sẽ được sử dụng thay vì bối cảnh xây dựng được gửi bởi người dùng.


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

Đây là một cách khác để sao chép các tập tin vào một hình ảnh. Tùy chọn -v tạm thời tạo một ổ đĩa mà chúng tôi đã sử dụng trong quá trình xây dựng.

Điều này khác với các khối lượng khác vì nó chỉ gắn một thư mục máy chủ cho bản dựng. Tập tin có thể được sao chép bằng lệnh cp tiêu chuẩn.

Ngoài ra, giống như curl và wget, nó có thể được chạy trong ngăn xếp lệnh (chạy trong một thùng chứa) và không nhân kích thước hình ảnh. ADD và COPY không thể xếp chồng lên nhau vì chúng chạy trong một thùng chứa độc lập và các lệnh tiếp theo trên các tệp thực thi trong các thùng chứa bổ sung sẽ nhân kích thước hình ảnh:

Với các tùy chọn được đặt như vậy:

-v /opt/mysql-staging:/tvol

Sau đây sẽ thực thi trong một container:

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
Phiên bản docker nào bạn đang ở nơi bạn thấy tùy chọn đó? Nó không được ghi lại và không hoạt động trên máy khách 1.12.1 của tôi.
BMitch

2
Trên thực tế, tính năng này vẫn chưa được đưa vào bản phát hành chính và vẫn còn nhiều cuộc thảo luận về chủ đề này, vì vậy chúng tôi không nên mong đợi nó trước một thời gian dài ... Xem báo cáo lỗi để biết thêm thông tin: github.com/ docker / docker / vấn đề / 14080 .
jwatkins

1
Vâng, không có tùy chọn như vậy (được kiểm tra trong phiên bản mới nhất 17,06). Câu trả lời này là sai lệch. unknown shorthand flag: 'v' in -v
Kirby

Nhận xét sai lệch thực sự
Guido van Steen

Khối lượng Docker không có gì để làm ở đây trong câu trả lời, xin vui lòng nếu bạn có thể, trả lời câu hỏi trực tiếp :), nó dễ dàng là câu trả lời downvote.
Majid Ali Khan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.