Docker - bagaimana cara menyalin file dari image ke host?

117

Pertanyaan saya terkait dengan pertanyaan tentang menyalin file dari container ke host; Saya memiliki Dockerfile yang mengambil dependensi, mengompilasi artefak build dari sumber, dan menjalankan file yang dapat dieksekusi. Saya juga ingin menyalin artefak build (dalam kasus saya ini .zipdiproduksi oleh sbt distin '../ target / `, tetapi menurut saya pertanyaan ini juga berlaku untuk toples, binari, dll.

docker cpbekerja pada kontainer, bukan gambar; apakah saya perlu memulai penampung hanya untuk mendapatkan file darinya? Dalam skrip, saya mencoba menjalankan /bin/bashmode interaktif di latar belakang, menyalin file keluar, dan kemudian mematikan penampungnya, tetapi ini tampaknya kludgey. Apakah ada cara yang lebih baik?

Di sisi lain, saya ingin menghindari pembongkaran .tarfile setelah menjalankan docker save $IMAGENAMEhanya untuk mengeluarkan satu file (tapi sepertinya itu opsi yang paling sederhana, jika paling lambat, saat ini).

Saya akan menggunakan volume buruh pelabuhan, misalnya:

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

tetapi saya menjalankan boot2dockerOSX dan saya tidak tahu cara menulis langsung ke sistem file host mac saya (volume baca-tulis meningkat di dalam VM boot2docker saya, yang berarti saya tidak dapat dengan mudah membagikan skrip untuk diekstrak blah.zipdari gambar dengan orang lain.

Menandai
sumber

Jawaban:

172

Untuk menyalin file dari gambar, buat penampung sementara, salin file darinya, lalu hapus:

id=$(docker create image-name)
docker cp $id:path - > local-tar-file
docker rm -v $id
Igor Bukanov
sumber
Versi buruh pelabuhan apa yang createperintahnya ditambahkan / dihapus (tidak ada di 1.01)
ThorSummoner
2
@ThorSummoner docker creatediperkenalkan di buruh pelabuhan 1.3, blog.docker.com/2014/10/…
Igor Bukanov
1
Saya tidak tahu mengapa ini tidak dipilih sebagai jawaban yang benar.
CentAu
1
Jawaban yang pasti benar !!! Tidak bergantung pada apa pun di dalam wadah ... Untuk gambar goresan Golang, ini adalah satu-satunya cara yang mungkin!
Marcello de Sales
2
ada alasan untuk menyalin ke stdout dan kemudian mengarahkannya ke file lokal? ketika saya melakukan ini, itu membuang banyak karakter kontrol sebelum dan sesudah konten file. menjalankannya secara langsung sebagaimana docker cp $id:path > local-tar-filebekerja dengan sempurna.
Yonatan
62

Sayangnya sepertinya tidak ada cara untuk menyalin file langsung dari image Docker. Anda perlu membuat penampung terlebih dahulu, lalu menyalin file dari penampung.

Namun, jika gambar Anda berisi catperintah (dan akan dilakukan dalam banyak kasus), Anda dapat melakukannya dengan satu perintah:

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

Jika gambar Anda tidak berisi cat, cukup buat wadah dan gunakan docker cpperintah seperti yang disarankan dalam jawaban Igor.

fons
sumber
1
Solusi yang fantastis. Tidak dapat mengakses penampung saya karena penampung mogok sesaat setelah diluncurkan, tetapi perlu mengambil file di dalamnya. Ini bekerja dengan sempurna.
Mirodinho
23

Opsi yang jauh lebih cepat adalah menyalin file dari penampung yang sedang berjalan ke volume yang terpasang:

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

0m0.446s nyata

** VS **

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

0m9.014s nyata

Mikko
sumber
Ini mungkin lebih berkaitan dengan sistem file yang mendasari melakukan salinan file yang lambat / dangkal (pikirkan salin-saat-tulis) di contoh pertama, vs sebenarnya menyalin byte file di contoh kedua. Tes yang berguna adalah untuk melihat apakah cat a >bvs cp a bmemiliki waktu yang sama seperti yang ditunjukkan di sini. Selain itu, jika jalur sumber dan jalur tujuan berada pada sistem file yang berbeda, kedua contoh tersebut akan mengarah ke salinan byte-untuk-byte penuh.
KevinOrr
14

Komentar orang tua sudah menunjukkan cara menggunakan kucing . Anda juga bisa menggunakan tar dengan cara yang sama:

docker run yourimage tar -c -C /my/directory subfolder | tar x
wedesoft
sumber
1
Jawaban ini adalah menyalin direktori, bukan file seperti yang ditanyakan oleh pertanyaan asli. Namun, +1 karena ini juga berfungsi dengan file dan dilengkapi dengan fitur tambahan: izin dan pelestarian pemilik. Bagus!
caligari
5
Sebenarnya, saya menggunakandocker run --rm --entrypoint tar _image_ cC _img_directory_ . | tar xvC _host_directory_
caligari
6
docker cp $(docker create registry.example.com/ansible-base:latest):/home/ansible/.ssh/id_rsa ./hacked_ssh_key

ingin menyediakan solusi satu baris

edit: container bahkan tidak harus dijalankan dalam solusi ini

Elytscha Smith
sumber
1

Jawaban (singkat) lain untuk masalah ini:

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

Saya menggunakan boot2docker di MacOS. Saya dapat meyakinkan Anda bahwa skrip berdasarkan "docker cp" bersifat portabel. Karena setiap perintah direlay di dalam boot2docker tetapi aliran biner diteruskan kembali ke klien baris perintah buruh pelabuhan yang berjalan di mac Anda. Jadi operasi tulis dari klien buruh pelabuhan dijalankan di dalam server dan ditulis kembali ke contoh klien pelaksana!

Saya berbagi skrip cadangan untuk volume buruh pelabuhan dengan wadah buruh pelabuhan apa pun yang saya sediakan dan skrip cadangan saya diuji di linux dan MacOS dengan boot2docker. Cadangan dapat dengan mudah dipertukarkan antar platform. Pada dasarnya saya menjalankan perintah berikut di dalam skrip saya:

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

Menjalankan container busybox baru dan memasang volume container jenkins saya dengan nama jenkins_jenkins_1. Seluruh volume ditulis ke file backups / JenkinsBackup-2015-07-09-14-26-15.tar

Saya telah memindahkan arsip antara penampung linux dan penampung mac saya tanpa penyesuaian apa pun pada skrip cadangan atau pemulihan. Jika ini yang Anda inginkan, Anda dapat menemukan seluruh skrip tutorial di sini: blacklabelops / jenkins

blacklabelops
sumber
0

Anda dapat mengikat jalur lokal di host ke jalur di penampung, lalu cpfile yang diinginkan ke jalur tersebut di akhir skrip Anda.

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

Maka tidak perlu menyalin setelahnya.

ryanjdillon.dll
sumber