ความแตกต่างระหว่างคำสั่ง 'COPY' และ 'เพิ่ม' ใน Dockerfile คืออะไร?


2196

อะไรคือความแตกต่างระหว่างคำสั่งCOPYและADDคำสั่งใน Dockerfile และเมื่อไหร่ที่ฉันจะใช้อันอื่น

COPY <src> <dest>

คำสั่ง COPY จะคัดลอกไฟล์ใหม่จาก<src>และเพิ่มไปยังระบบไฟล์ของคอนเทนเนอร์ที่พา ธ<dest>

ADD <src> <dest>

การเรียนการสอนเพิ่มจะคัดลอกไฟล์ใหม่จากและเพิ่มให้ระบบแฟ้มของคอนเทนเนอร์ที่เส้นทาง<src><dest>


11
ดูแนวทางปฏิบัติที่ดีที่สุด: docs.docker.com/engine/userguide/eng-image/ ......
EricSonaron

9
ณ เดือนมิถุนายน 2561 การอ้างอิงบอกว่าเพิ่มเข้าไปในภาพ (เช่นไฟล์คงที่) ในขณะที่ COPY เพิ่มลงในภาชนะ (เช่นอินสแตนซ์ของภาพ) แน่นอนว่านี่หมายความว่า COPY จะถูกดำเนินการทุกครั้งที่มีการเรียกใช้ Docker หรืออาจเป็นกรณีของคำศัพท์ที่ไม่สอดคล้องกันใช่หรือไม่
Chris Robinson

14
ฉันคิดว่านั่นเป็นคำศัพท์ที่ไม่สอดคล้องกัน
Daniel Stevens

6
@ChrisRobinson มันจะเป็นไปไม่ได้ที่COPYจะดำเนินการทุกครั้งที่เรียกใช้เพราะไม่จำเป็นต้องเข้าถึงบริบทดั้งเดิมเพื่อดึงเนื้อหา
Ken Williams

คำตอบ:


2166

คุณควรตรวจสอบADDและCOPYเอกสารสำหรับคำอธิบายโดยละเอียดเพิ่มเติมเกี่ยวกับพฤติกรรมของพวกเขา แต่โดยสรุปแล้วความแตกต่างที่สำคัญคือADDสามารถทำได้มากกว่าCOPY:

  • ADDอนุญาตให้<src>เป็น URL
  • อ้างถึงความคิดเห็นร้องADD เอกสารระบุว่า:

    หากเป็นไฟล์เก็บถาวร tar แบบโลคัลในรูปแบบการบีบอัดที่รู้จัก (identity, gzip, bzip2 หรือ xz) แสดงว่ามันถูกแตกเป็นไดเร็กทอรี ทรัพยากรจาก URL ระยะไกลจะไม่แตก

โปรดทราบว่าแนวทางปฏิบัติที่ดีที่สุดสำหรับการเขียน Dockerfilesแนะนำให้ใช้COPYเมื่อADDไม่จำเป็นต้องใช้เวทมนต์ มิฉะนั้นคุณ ( เนื่องจากคุณต้องค้นหาคำตอบนี้ ) มีแนวโน้มที่จะแปลกใจสักวันเมื่อคุณต้องการคัดลอกkeep_this_archive_intact.tar.gzลงในที่เก็บของคุณ แต่คุณฉีดเนื้อหาลงบนระบบแฟ้มของคุณแทน


65
แค่อยากจะชี้แจงบางสิ่งบางอย่างที่ใช้ใส่กับ URL ไปยัง .tar.gz ไม่ EXTRACT เก็บไปยังระบบแฟ้ม (ฉันสองครั้งการตรวจสอบในขณะนี้เพื่อให้แน่ใจว่าและจะได้รับการยืนยัน)
Cecile

42
นี่เป็นข้อมูลสำคัญและเป็นอาชญากรรมที่การอ้างอิงอย่างเป็นทางการของ Dockerfile ไม่ได้อธิบายความแตกต่างในลักษณะนี้
Cheeso

1
ไม่แน่ใจว่าสิ่งนี้จะแตกต่างกันสำหรับรูปภาพต่อภาพหรือไม่ ฉันใช้ภาพ busybox และเพิ่มสำหรับไฟล์ zip มันเพิ่งปรากฏในไดเรกทอรีปลายทางโดยไม่ต้องคลายซิป ฉันถือว่าการสกัดเกิดขึ้นสำหรับ tarball เท่านั้น แต่ฉันยังไม่ได้ตรวจสอบตอนนี้
Santosh Kumar Arjunan

4
@SantoshKumarArjunan: เอกสารนักเทียบท่าระบุสิ่งต่อไปนี้เกี่ยวกับการเพิ่ม ADD และการแยก tar อัตโนมัติ: 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 --from = <name | index> ซึ่งฉันไม่สามารถหาการสนับสนุนเพิ่มเติมสำหรับ ADD ได้
Brandon

474

COPY คือ

เหมือนกับ 'เพิ่ม' แต่ไม่มีการจัดการ tar และ URL ระยะไกล

อ้างอิงตรงจากรหัสที่มา


15
ฉันเห็นสิ่งนี้ถูกต้องADDหรือไม่ : สร้างไดเรกทอรีที่ไม่มีอยู่ด้วย ดังนั้นแม้ว่ามันจะหมดกำลังใจในชุดข้อความทั้งหมด แต่ก็มีข้อได้เปรียบมากกว่าCOPYเพราะคุณไม่จำเป็นต้องเรียกใช้mkdirและบันทึกการพิมพ์บางอย่าง
eli

3
COPY ทำเช่นนั้นด้วย @eli
bhordupur

คำอธิบายที่ดีที่สุดจนถึงตอนนี้ ทำไมมันไม่ได้คำตอบที่ยอมรับ?
xdevx32

141

มีเอกสารอย่างเป็นทางการเกี่ยวกับประเด็นดังกล่าว: แนวทางปฏิบัติที่ดีที่สุดสำหรับการเขียนนักเทียบท่า

เนื่องจากขนาดภาพมีความสำคัญการใช้ADDเพื่อดึงแพคเกจจาก URL ระยะไกลจึงไม่สนับสนุนอย่างยิ่ง คุณควรใช้curlหรือwgetแทน ด้วยวิธีนี้คุณสามารถลบไฟล์ที่คุณไม่ต้องการได้หลังจากที่แตกไฟล์แล้วและคุณไม่ต้องเพิ่มเลเยอร์อื่นในรูปภาพของคุณ

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

สำหรับรายการอื่น ๆ (แฟ้มไดเรกทอรี) ที่ไม่จำเป็นต้องมีADDความสามารถในการสกัดอัตโนมัติ 's tar COPYคุณควรใช้



18
นักเทียบท่าบอกว่าชอบCOPYมากกว่าเพราะมันโปร่งใสกว่า จากแนวทางปฏิบัติที่ดีที่สุดของไฟล์ Docker (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

จากนักเทียบท่าเอกสาร:

เพิ่มหรือคัดลอก

แม้ว่า ADD และ COPY จะมีฟังก์ชั่นคล้ายกัน แต่โดยทั่วไปแล้วการพูดก็ต้องการให้คัดลอก นั่นเป็นเพราะมันโปร่งใสกว่า ADD COPY รองรับเฉพาะการคัดลอกไฟล์โลคัลพื้นฐานลงในคอนเทนเนอร์ในขณะที่ ADD มีคุณสมบัติบางอย่าง (เช่นการแยก tar เฉพาะโลคัลและการสนับสนุน URL ระยะไกล) ที่ไม่ชัดเจนในทันที ดังนั้นการใช้ที่ดีที่สุดสำหรับ ADD คือการแยกไฟล์ tar อัตโนมัติลงในภาพเช่นเดียวกับใน ADD rootfs.tar.xz /

เพิ่มเติม: แนวทางปฏิบัติที่ดีที่สุดสำหรับการเขียน Dockerfiles


46

หากคุณต้องการเพิ่ม xx.tar.gz ไปยัง/usr/localin in container ให้ทำการคลายซิปแล้วลบแพ็คเกจบีบอัดที่ไม่มีประโยชน์ออก

สำหรับ 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

สำหรับเพิ่ม:

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

เพิ่มสนับสนุนการสกัด tar เฉพาะท้องถิ่น นอกจากนั้น COPY จะใช้สามเลเยอร์ แต่เพิ่มเพียงหนึ่งเลเยอร์เท่านั้น


3
เหตุผลใดที่ไม่ใช่แค่สองชั้น? 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 คัดลอกไฟล์ / ไดเรกทอรีจากโฮสต์ของคุณไปยังภาพของคุณ

ADD คัดลอกไฟล์ / ไดเรกทอรีจากโฮสต์ของคุณไปยังรูปภาพของคุณ แต่ยังสามารถดึง URL ระยะไกลแยกไฟล์ TAR ฯลฯ ...

ใช้COPYสำหรับคัดลอกไฟล์และ / หรือไดเรกทอรีไปยังบริบทการสร้าง

ใช้ADDสำหรับการดาวน์โหลดทรัพยากรระยะไกลการแตกไฟล์ TAR ฯลฯ


5
คำอธิบายที่สมบูรณ์แบบสำหรับ noob อย่างฉัน
uneq95

17

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

"แม้ว่า ADD และ COPY จะมีลักษณะการใช้งานที่คล้ายกัน แต่โดยทั่วไปแล้ว COPY ก็เป็นที่นิยมมากกว่าเพราะ ADD นั้นมีความโปร่งใสมากกว่า ADD คัดลอกรองรับเฉพาะการคัดลอกไฟล์ท้องถิ่นไปยังคอนเทนเนอร์ในขณะที่ ADD มีคุณสมบัติบางอย่าง การสนับสนุน URL ระยะไกล) ที่ไม่ชัดเจนในทันทีดังนั้นการใช้ ADD ที่ดีที่สุดคือการแยกไฟล์ tar ในเครื่องโดยอัตโนมัติลงในรูปภาพดังเช่นใน ADD rootfs.tar.xz /

หากคุณมีหลายขั้นตอน Dockerfile ที่ใช้ไฟล์ที่แตกต่างจากบริบทของคุณให้คัดลอกทีละไฟล์แทนที่จะทำทั้งหมดพร้อมกัน สิ่งนี้จะช่วยให้มั่นใจได้ว่าแคชสำหรับบิลด์ของแต่ละขั้นตอนจะไม่ถูกต้องเท่านั้น

ตัวอย่างเช่น:

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

ผลลัพธ์ในการทำให้แคชไม่ถูกต้องสำหรับขั้นตอน RUN น้อยกว่าถ้าคุณใส่ COPY / tmp / ก่อนหน้า

เนื่องจากขนาดภาพมีความสำคัญการใช้ ADD เพื่อดึงแพ็คเกจจาก URL ระยะไกลจึงไม่สนับสนุนอย่างยิ่ง คุณควรใช้ curl หรือ wget แทน วิธีนี้จะทำให้คุณสามารถลบไฟล์ที่คุณไม่ต้องการได้หลังจากที่แตกไฟล์แล้วและคุณไม่ต้องเพิ่มเลเยอร์อื่นในรูปภาพของคุณ ตัวอย่างเช่นคุณควรหลีกเลี่ยงการทำสิ่งต่าง ๆ เช่น:

 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

และทำสิ่งที่ชอบแทน:

 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

สำหรับรายการอื่น ๆ (ไฟล์ไดเรกทอรี) ที่ไม่ต้องการความสามารถในการแยกอัตโนมัติของ ADD คุณควรใช้ COPY เสมอ "


7

ที่มา: https://nickjanetakis.com/blog/docker-tip-2-the-difference-between-copy-and-add-in-a-dockerile :

COPY และ ADD เป็นทั้งคำแนะนำของ Dockerfile ที่ให้บริการตามวัตถุประสงค์ที่คล้ายคลึงกัน พวกเขาให้คุณคัดลอกไฟล์จากตำแหน่งเฉพาะลงในอิมเมจ Docker

COPY ใช้เวลาใน src และปลายทาง มันช่วยให้คุณคัดลอกไฟล์ภายในเครื่องหรือไดเรกทอรีจากโฮสต์ของคุณ (เครื่องสร้างอิมเมจ Docker) ลงในอิมเมจ Docker เท่านั้น

เพิ่มช่วยให้คุณทำเช่นนั้น แต่ก็ยังรองรับ 2 แหล่งอื่น ก่อนอื่นคุณสามารถใช้ URL แทนไฟล์ / ไดเรกทอรีในเครื่อง ประการที่สองคุณสามารถแยกไฟล์ tar จากแหล่งโดยตรงลงในปลายทาง

กรณีการใช้งานที่ถูกต้องสำหรับ ADD คือเมื่อคุณต้องการแตกไฟล์ tar ในเครื่องลงในไดเรกทอรีเฉพาะในอิมเมจ Docker ของคุณ

หากคุณกำลังคัดลอกไฟล์ในเครื่องไปยังภาพ Docker ของคุณให้ใช้ COPY เสมอเพราะชัดเจนกว่า


7

เมื่อสร้าง Dockerfile, มีสองคำสั่งที่คุณสามารถใช้เพื่อคัดลอกไฟล์ / ไดเรกทอรีเป็นมัน - และADD COPYแม้ว่าจะมีความแตกต่างกันเล็กน้อยในขอบเขตของฟังก์ชั่นของพวกเขาเป็นหลักพวกเขาปฏิบัติงานเดียวกัน

ดังนั้นทำไมเราจึงมีสองคำสั่งและเราจะรู้ได้อย่างไรว่าจะใช้หนึ่งหรืออีกอันเมื่อไหร่?

คำADDสั่งDOCKER

เริ่มต้น Let 's โดยสังเกตว่าคำสั่งเก่ากว่าADD COPYตั้งแต่เปิดตัวแพลตฟอร์ม Docker ADDคำสั่งนี้เป็นส่วนหนึ่งของรายการคำสั่ง

คำสั่งคัดลอกไฟล์ / ไดเรกทอรีไปยังระบบไฟล์ของคอนเทนเนอร์ที่ระบุ

ไวยากรณ์พื้นฐานสำหรับADDคำสั่งคือ:

ADD <src> … <dest>

ประกอบด้วยแหล่งที่คุณต้องการคัดลอก ( <src>) ตามด้วยปลายทางที่คุณต้องการเก็บไว้ ( <dest>) หากแหล่งที่มาเป็นไดเรกทอรีให้ADDคัดลอกทุกอย่างที่อยู่ภายใน (รวมถึงข้อมูลเมตาของระบบไฟล์)

ตัวอย่างเช่นหากไฟล์พร้อมใช้งานแบบโลคัลและคุณต้องการเพิ่มลงในไดเร็กทอรีของอิมเมจคุณพิมพ์:

ADD /source/file/path  /destination/path

ADDยังสามารถคัดลอกไฟล์จาก URL มันสามารถดาวน์โหลดไฟล์ภายนอกและคัดลอกไปยังปลายทางที่ต้องการ ตัวอย่างเช่น:

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

คุณสมบัติเพิ่มเติมคือมันจะคัดลอกไฟล์ที่บีบอัดโดยแยกเนื้อหาในปลายทางที่กำหนดโดยอัตโนมัติ คุณลักษณะนี้ใช้กับไฟล์ / ไดเรกทอรีที่บีบอัดที่เก็บไว้ในเครื่องเท่านั้น

ADD source.file.tar.gz /temp

โปรดจำไว้ว่าคุณไม่สามารถดาวน์โหลดและคลายบีบอัดไฟล์ / ไดเรกทอรีจาก URL ได้ คำสั่งไม่คลายแพ็กเกจภายนอกเมื่อคัดลอกไปยังระบบไฟล์โลคัล

คำCOPYสั่งDOCKER

เนื่องจากปัญหาการทำงานบางส่วนหางมีที่จะแนะนำคำสั่งเพิ่มเติมสำหรับการทำซ้ำเนื้อหา COPY-

แตกต่างจากADDคำสั่งที่เกี่ยวข้องอย่างใกล้ชิดCOPYมีเพียงหนึ่งฟังก์ชั่นที่ได้รับมอบหมาย บทบาทคือการทำซ้ำไฟล์ / ไดเรกทอรีในตำแหน่งที่ระบุในรูปแบบที่มีอยู่ ซึ่งหมายความว่าจะไม่จัดการกับการคลายบีบอัดไฟล์ แต่คัดลอกไฟล์ตามที่เป็นอยู่

คำแนะนำสามารถใช้สำหรับไฟล์ที่เก็บไว้ในเครื่องเท่านั้น ดังนั้นคุณไม่สามารถใช้กับ URL เพื่อคัดลอกไฟล์ภายนอกไปยังคอนเทนเนอร์ของคุณ

หากต้องการใช้COPYคำแนะนำให้ปฏิบัติตามรูปแบบคำสั่งพื้นฐาน:

พิมพ์ในซอร์สและตำแหน่งที่คุณต้องการให้คำสั่งแตกเนื้อหาดังนี้:

COPY <src> … <dest> 

ตัวอย่างเช่น:

COPY /source/file/path  /destination/path 

คำสั่งใดที่จะใช้ (แนวปฏิบัติที่ดีที่สุด)

เมื่อพิจารณาถึงสถานการณ์ที่COPYคำสั่งได้รับการแนะนำก็เห็นได้ชัดว่าการรักษาADDเป็นเรื่องจำเป็น นักเทียบท่าปล่อยเอกสารอย่างเป็นทางการที่สรุปแนวทางปฏิบัติที่ดีที่สุดสำหรับการเขียน Dockerfiles ซึ่งแนะนำให้ใช้กับADDคำสั่งอย่างชัดเจน

หางของบันทึกเอกสารอย่างเป็นทางการที่ควรจะเป็นไปเพื่อการเรียนการสอนในขณะที่มันมีความโปร่งใสมากกว่าCOPYADD

COPYหากคุณต้องการที่จะคัดลอกมาจากการสร้างบริบทของท้องถิ่นลงในภาชนะติดกับการใช้

ทีมนักเทียบท่ายังไม่สนับสนุนอย่างยิ่งADDในการดาวน์โหลดและคัดลอกแพ็คเกจจาก URL แต่จะปลอดภัยกว่าและมีประสิทธิภาพมากกว่าในการใช้ wget หรือ curl ภายในRUNคำสั่ง คุณหลีกเลี่ยงการสร้างเลเยอร์ภาพเพิ่มเติมและประหยัดพื้นที่


4

โน๊ตสำคัญ

ฉันต้องCOPYและเลิกจาวาแพ็คเกจในภาพนักเทียบท่า เมื่อฉันเปรียบเทียบขนาดภาพของนักเทียบท่าที่สร้างโดยใช้ ADD มันจะใหญ่กว่าขนาดที่สร้างโดยใช้ COPY 180MB tar -xzf * .tar.gz และ rm * .tar.gz

ซึ่งหมายความว่าแม้ว่า ADD จะลบไฟล์ tar แต่ก็ยังคงเก็บไว้ที่ใดที่หนึ่ง และมันทำให้ภาพใหญ่ขึ้น !!


สิ่งนี้ยังคงเป็นจริงสำหรับ Docker รุ่นล่าสุดหรือไม่
Navin

3

เนื่องจาก Docker 17.05 COPYใช้กับ--fromแฟล็กในการสร้างหลายขั้นตอนเพื่อคัดลอกสิ่งประดิษฐ์จากขั้นตอนการสร้างก่อนหน้านี้ไปยังขั้นตอนการสร้างปัจจุบัน

จากเอกสาร

COPY แบบเป็นทางเลือกยอมรับการตั้งค่าสถานะ--from=<name|index>ที่สามารถใช้เพื่อตั้งค่าตำแหน่งต้นทางไปยังสเตจสร้างก่อนหน้า (สร้างด้วย FROM .. AS) ที่จะใช้แทนบริบทของบิลด์ที่ผู้ใช้ส่ง


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

นี่เป็นอีกวิธีในการคัดลอกไฟล์ไปยังรูปภาพ ตัวเลือก -v สร้างปริมาณที่เราใช้ในระหว่างกระบวนการสร้างชั่วคราว

สิ่งนี้แตกต่างจากไดรฟ์อื่น ๆ เนื่องจากเมาท์ไดเรกทอรีโฮสต์สำหรับบิลด์เท่านั้น สามารถคัดลอกไฟล์โดยใช้คำสั่ง cp มาตรฐาน

นอกจากนี้เช่นเดียวกับ curl และ wget ก็สามารถเรียกใช้ในกองคำสั่ง (ทำงานในภาชนะเดียว) และไม่คูณขนาดภาพ เพิ่มและคัดลอกไม่สามารถวางซ้อนกันได้เพราะพวกเขาทำงานในภาชนะแบบสแตนด์อโลนและคำสั่งที่ตามมาในไฟล์เหล่านั้นที่ดำเนินการในภาชนะบรรจุเพิ่มเติมจะคูณขนาดของภาพ:

ด้วยตัวเลือกที่ตั้งจึง:

-v /opt/mysql-staging:/tvol

ต่อไปนี้จะดำเนินการในคอนเทนเนอร์เดียว:

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
คุณเป็นนักเทียบท่ารุ่นไหนที่คุณเห็นตัวเลือกนั้น? มันไม่ได้บันทึกไว้และไม่ทำงานบนไคลเอนต์ 1.12.1 ของฉัน
BMitch

2
ที่จริงแล้วฟีเจอร์นี้ยังไม่รวมอยู่ในรีลีสหลักและยังมีการพูดคุยกันมากมายเกี่ยวกับเรื่องนี้ดังนั้นเราไม่ควรคาดหวังก่อนเวลานาน ... ดูรายงานข้อผิดพลาดสำหรับข้อมูลเพิ่มเติม: github.com/ นักเทียบท่า
jwatkins

1
ใช่ไม่มีตัวเลือกดังกล่าว (ตรวจสอบในรุ่นล่าสุด 17.06) คำตอบนี้ทำให้เข้าใจผิด unknown shorthand flag: 'v' in -v
เคอร์บี้

ความคิดเห็นที่หลอกลวงอย่างแท้จริง
Guido van Steen

ปริมาณนักเทียบท่าไม่ได้ทำที่นี่ในคำตอบโปรดถ้าคุณสามารถตอบคำถามโดยตรง :) มันเป็นคำตอบ downvote ได้อย่างง่ายดาย
Majid Ali Khan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.