Docker - ฉันจะคัดลอกไฟล์จากรูปภาพไปยังโฮสต์ได้อย่างไร


120

คำถามของฉันเกี่ยวข้องกับคำถามเกี่ยวกับการคัดลอกไฟล์จากคอนเทนเนอร์ไปยังโฮสต์ ฉันมี Dockerfile ที่ดึงข้อมูลอ้างอิงรวบรวมสิ่งประดิษฐ์สร้างจากแหล่งที่มาและเรียกใช้ไฟล์ปฏิบัติการ ฉันต้องการคัดลอกบิวด์อาร์ติแฟกต์.zipด้วย(ในกรณีของฉันมันสร้างโดยsbt distใน "../ target /" แต่ฉันคิดว่าคำถามนี้ยังใช้ได้กับไหไบนารี ฯลฯ

docker cpทำงานบนคอนเทนเนอร์ไม่ใช่รูปภาพ ฉันจำเป็นต้องเริ่มคอนเทนเนอร์เพื่อดึงไฟล์ออกมาหรือไม่ ในสคริปต์ฉันลองทำงาน/bin/bashในโหมดโต้ตอบในพื้นหลังคัดลอกไฟล์ออกจากนั้นจึงฆ่าคอนเทนเนอร์ แต่ดูเหมือนว่าจะไม่ดี มีวิธีที่ดีกว่า?

ในทางกลับกันฉันต้องการหลีกเลี่ยงการคลาย.tarไฟล์หลังจากเรียกใช้docker save $IMAGENAMEเพื่อดึงไฟล์ออกมาหนึ่งไฟล์ (แต่ดูเหมือนว่าจะเป็นตัวเลือกที่ง่ายที่สุดถ้าช้าที่สุดในตอนนี้)

ฉันจะใช้วอลุ่มนักเทียบท่าเช่น:

docker run -v hostdir:out $IMAGENAME /bin/cp/../blah.zip /out

แต่ฉันทำงานboot2dockerใน OSX และฉันไม่รู้วิธีเขียนลงในระบบไฟล์โฮสต์ mac ของฉันโดยตรง (ไดรฟ์ข้อมูลแบบอ่าน - เขียนกำลังติดตั้งอยู่ใน boot2docker VM ของฉันซึ่งหมายความว่าฉันไม่สามารถแชร์สคริปต์เพื่อดึงข้อมูลblah.zipจากรูปภาพได้อย่างง่ายดายคนอื่น ๆ ความคิด?

คำตอบ:


172

ในการคัดลอกไฟล์จากรูปภาพให้สร้างคอนเทนเนอร์ชั่วคราวคัดลอกไฟล์จากนั้นจึงลบออก:

id=$(docker create image-name)
docker cp $id:path - > local-tar-file
docker rm -v $id

createคำสั่งเพิ่ม / ลบนักเทียบท่ารุ่นใด(ไม่มีอยู่ใน 1.01)
ThorSummoner

2
@ThorSummoner docker createเปิดตัวในdocker
Igor Bukanov

1
ฉันไม่รู้ว่าทำไมถึงไม่เลือกเป็นคำตอบที่ถูกต้อง
CentAu

1
ตอบถูกแน่นอน !!! ไม่ต้องพึ่งพาสิ่งใด ๆ ภายในตู้คอนเทนเนอร์ ... สำหรับภาพรอยขีดข่วน Golang นี่เป็นวิธีเดียวที่เป็นไปได้!
Marcello de Sales

2
เหตุผลใดที่จะคัดลอกไปที่ stdout แล้วนำไปยังไฟล์ในเครื่อง? เมื่อฉันทำสิ่งนี้มันทิ้งอักขระควบคุมจำนวนมากก่อนและหลังเนื้อหาของไฟล์ ใช้งานได้โดยตรงเมื่อdocker cp $id:path > local-tar-fileทำงานได้อย่างสมบูรณ์
Yonatan

63

น่าเสียดายที่ดูเหมือนจะไม่มีวิธีคัดลอกไฟล์โดยตรงจากอิมเมจ Docker คุณต้องสร้างคอนเทนเนอร์ก่อนแล้วจึงคัดลอกไฟล์จากคอนเทนเนอร์

อย่างไรก็ตามหากรูปภาพของคุณมีcatคำสั่ง (และจะทำในหลาย ๆ กรณี) คุณสามารถทำได้ด้วยคำสั่งเดียว:

docker run --rm --entrypoint cat yourimage  /path/to/file > path/to/destination

หากไม่มีรูปภาพของคุณcatให้สร้างคอนเทนเนอร์และใช้docker cpคำสั่งตามที่แนะนำในคำตอบของ Igor


1
ทางออกที่ยอดเยี่ยม ไม่สามารถเข้าถึงคอนเทนเนอร์ของฉันได้เนื่องจากเกิดข้อผิดพลาดในวินาทีหลังจากเปิดตัว แต่จำเป็นต้องคว้าไฟล์ที่อยู่ในนั้น สิ่งนี้ทำงานได้อย่างสมบูรณ์แบบ
Mirodinho

23

ตัวเลือกที่เร็วกว่ามากคือการคัดลอกไฟล์จากการรันคอนเทนเนอร์ไปยังไดรฟ์ข้อมูลที่ติดตั้ง:

docker run -v $PWD:/opt/mount --rm --entrypoint cp image:version /data/libraries.tgz /opt/mount/libraries.tgz

0m0.446s จริง

** VS **

docker run --rm --entrypoint cat image:version /data/libraries.tgz > libraries.tgz

0m9.014s จริง


สิ่งนี้อาจเกี่ยวข้องกับระบบไฟล์พื้นฐานที่ทำสำเนาไฟล์แบบขี้เกียจ / ตื้น (คิดว่า copy-on-write) ในตัวอย่างแรกเทียบกับการคัดลอกไบต์ของไฟล์ในตัวอย่างที่สอง การทดสอบที่มีประโยชน์คือเพื่อดูว่าcat a >bvs cp a bมีการกำหนดเวลาที่คล้ายกันดังที่แสดงไว้ที่นี่หรือไม่ นอกจากนี้หากเส้นทางต้นทางและเส้นทางปลายทางอยู่บนระบบไฟล์ที่แตกต่างกันตัวอย่างทั้งสองจะนำไปสู่สำเนาแบบไบต์ต่อไบต์แบบเต็ม
KevinOrr

14

ความคิดเห็นของผู้ปกครองได้แสดงวิธีใช้catแล้ว คุณยังสามารถใช้น้ำมันดินในลักษณะที่คล้ายกัน:

docker run yourimage tar -c -C /my/directory subfolder | tar x

1
คำตอบนี้คือการคัดลอกไดเรกทอรีแทนไฟล์ตามที่คำถามเดิมถาม อย่างไรก็ตาม +1 เนื่องจากใช้งานได้กับไฟล์และมาพร้อมกับคุณสมบัติพิเศษ: การอนุญาตและการเก็บรักษาเจ้าของ เยี่ยมมาก!
caligari

5
ที่จริงฉันใช้docker run --rm --entrypoint tar _image_ cC _img_directory_ . | tar xvC _host_directory_
caligari

7
docker cp $(docker create registry.example.com/ansible-base:latest):/home/ansible/.ssh/id_rsa ./hacked_ssh_key

ต้องการจัดหาโซลูชันหนึ่งบรรทัดโดยใช้ฟังก์ชันนักเทียบท่าที่แท้จริง (ไม่จำเป็นต้องทุบตี)

แก้ไข: ไม่จำเป็นต้องเรียกใช้คอนเทนเนอร์ในโซลูชันนี้


1

คำตอบ (สั้น ๆ ) อื่นสำหรับปัญหานี้:

docker run -v $PWD:/opt/mount --rm -ti image:version bash -c "cp /source/file /opt/mount/"

อัปเดต - ตามที่ระบุไว้โดย@Elytscha Smith สิ่งนี้ใช้ได้เฉพาะเมื่อภาพของคุณมี bash ในตัว


1
* คำตอบสั้น ๆ อีกข้อสำหรับภาพที่มีอัลไพน์ที่ใช้การทุบตีไม่ได้เป็นไปตามค่าเริ่มต้นและภาพที่สร้างขึ้นจากศูนย์ก็ไม่ได้เช่นกัน
Elytscha Smith

0

ฉันใช้ boot2docker บน MacOS ฉันมั่นใจได้ว่าสคริปต์ที่ใช้ "docker cp" เป็นแบบพกพา เนื่องจากคำสั่งใด ๆ ถูกถ่ายทอดภายใน boot2docker แต่จากนั้นสตรีมไบนารีจะถูกส่งกลับไปยังไคลเอนต์บรรทัดคำสั่งนักเทียบท่าที่ทำงานบนเครื่อง Mac ของคุณ ดังนั้นการดำเนินการเขียนจากไคลเอนต์นักเทียบท่าจะถูกดำเนินการภายในเซิร์ฟเวอร์และเขียนกลับไปที่อินสแตนซ์ไคลเอ็นต์ที่เรียกใช้งาน!

ฉันกำลังแชร์สคริปต์สำรองสำหรับไดรฟ์ข้อมูลนักเทียบท่ากับคอนเทนเนอร์นักเทียบท่าที่ฉันมีให้และสคริปต์สำรองของฉันได้รับการทดสอบทั้งบน linux และ MacOS ด้วย boot2docker การสำรองข้อมูลสามารถแลกเปลี่ยนระหว่างแพลตฟอร์มได้อย่างง่ายดาย โดยทั่วไปฉันกำลังเรียกใช้คำสั่งต่อไปนี้ภายในสคริปต์ของฉัน:

docker run --name=bckp_for_volume --rm --volumes-from jenkins_jenkins_1 -v /Users/github/jenkins/backups:/backup busybox tar cf /backup/JenkinsBackup-2015-07-09-14-26-15.tar /jenkins

รันคอนเทนเนอร์ busybox ใหม่และติดตั้งไดรฟ์ข้อมูลของคอนเทนเนอร์ jenkins ของฉันด้วยชื่อ jenkins_jenkins_1 ไดรฟ์ข้อมูลทั้งหมดเขียนไปยังไฟล์สำรอง / JenkinsBackup-2015-07-09-14-26-15.tar

ฉันได้ย้ายที่เก็บถาวรระหว่างคอนเทนเนอร์ลินุกซ์และคอนเทนเนอร์ Mac ของฉันแล้วโดยไม่มีการปรับเปลี่ยนสคริปต์สำรองหรือกู้คืน หากนี่คือสิ่งที่คุณต้องการคุณสามารถดูบทช่วยสอนทั้งหมดได้ที่นี่: blacklabelops / jenkins


0

คุณสามารถผูกโลคัลพา ธ บนโฮสต์กับพา ธ บนคอนเทนเนอร์จากนั้นcpไฟล์ที่ต้องการไปยังพา ธ นั้นที่ส่วนท้ายของสคริปต์ของคุณ

$ docker run -d \
  -it \
  --name devtest \
  --mount type=bind,source="$(pwd)"/target,target=/app \
  nginx:latest

จากนั้นไม่จำเป็นต้องคัดลอกในภายหลัง

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