Singkatnya: Tidak, VOLUME
instruksi Anda tidak benar.
Dockerfile's VOLUME
menentukan satu atau lebih volume yang diberikan jalur sisi wadah. Tapi itu tidak memungkinkan penulis gambar untuk menentukan jalur host. Di sisi host, volume dibuat dengan nama seperti ID yang sangat panjang di dalam akar Docker. Di mesin saya ini /var/lib/docker/volumes
.
Catatan: Karena nama yang di-autogenerasi sangat panjang dan tidak masuk akal dari sudut pandang manusia, volume ini sering disebut sebagai "tanpa nama" atau "anonim".
Contoh Anda yang menggunakan '.' karakter bahkan tidak akan berjalan di mesin saya, tidak masalah jika saya membuat titik argumen pertama atau kedua. Saya mendapatkan pesan kesalahan ini:
buruh pelabuhan: Respons kesalahan dari daemon: kesalahan runtime oci: container_linux.go: 265: memulai proses wadah disebabkan "process_linux.go: 368: init kontainer disebabkan \" open / dev / ptmx: tidak ada file atau direktori seperti itu \ "".
Saya tahu bahwa apa yang telah dikatakan sampai saat ini mungkin tidak terlalu berharga bagi seseorang yang mencoba memahami VOLUME
dan -v
dan itu tentu saja tidak memberikan solusi untuk apa yang Anda coba capai. Jadi, mudah-mudahan, contoh-contoh berikut akan menjelaskan lebih lanjut tentang masalah ini.
Minitutorial: Menentukan volume
Diberikan Dockerfile ini:
FROM openjdk:8u131-jdk-alpine
VOLUME vol1 vol2
(Untuk hasil minitutorial ini, tidak ada bedanya jika kita menentukan vol1 vol2
atau/vol1 /vol2
- jangan tanya kenapa)
Bangun itu:
docker build -t my-openjdk
Lari:
docker run --rm -it my-openjdk
Di dalam wadah, jalankan ls
di baris perintah dan Anda akan melihat dua direktori ada; /vol1
dan/vol2
.
Menjalankan wadah juga menciptakan dua direktori, atau "volume", di sisi host.
Sambil menjalankan wadah, jalankan docker volume ls
di mesin host dan Anda akan melihat sesuatu seperti ini (saya telah mengganti bagian tengah nama dengan tiga titik untuk singkatnya):
DRIVER VOLUME NAME
local c984...e4fc
local f670...49f0
Kembali ke dalam wadah , jalankan touch /vol1/weird-ass-file
(buat file kosong di lokasi tersebut).
File ini sekarang tersedia di mesin host, di salah satu volume lol yang tidak disebutkan namanya. Butuh saya dua kali mencoba karena saya pertama kali mencoba volume yang tercantum pertama, tetapi akhirnya saya menemukan file saya di volume yang tercantum kedua, menggunakan perintah ini pada mesin host:
sudo ls /var/lib/docker/volumes/f670...49f0/_data
Demikian pula, Anda dapat mencoba menghapus file ini pada host dan itu akan dihapus dalam wadah juga.
Catatan: _data
Folder ini juga disebut sebagai "titik mount".
Keluar dari wadah dan daftarkan volume pada host. Mereka sudah pergi. Kami menggunakan --rm
bendera saat menjalankan wadah dan opsi ini secara efektif menghapus tidak hanya wadah saat keluar, tetapi juga volume.
Jalankan wadah baru, tetapi tentukan volume menggunakan -v
:
docker run --rm -it -v /vol3 my-openjdk
Ini menambahkan volume ketiga dan seluruh sistem akhirnya memiliki tiga volume yang tidak disebutkan namanya. Perintahnya akan crash jika kita tentukan saja -v vol3
. Argumen harus menjadi jalur absolut di dalam wadah. Di sisi host, volume ketiga yang baru bersifat anonim dan berada bersama dengan dua volume lainnya di /var/lib/docker/volumes/
.
Telah dinyatakan sebelumnya bahwa Dockerfile
tidak dapat memetakan ke jalur host yang semacam menimbulkan masalah bagi kami ketika mencoba untuk membawa file dari host ke wadah selama runtime. -v
Sintaks yang berbeda memecahkan masalah ini.
Bayangkan saya memiliki subfolder di direktori proyek ./src
saya yang ingin saya sinkronkan ke /src
dalam wadah. Perintah ini melakukan trik:
docker run -it -v $(pwd)/src:/src my-openjdk
Kedua sisi :
karakter mengharapkan jalur absolut. Sisi kiri menjadi jalur absolut pada mesin host, sisi kanan menjadi jalur absolut di dalam wadah. pwd
adalah perintah yang "mencetak direktori saat ini / bekerja". Memasukkan perintah $()
mengambil perintah dalam tanda kurung, menjalankannya dalam subkulit dan mengembalikan jalur absolut ke direktori proyek kami.
Menyatukan semuanya, asumsikan ada ./src/Hello.java
di folder proyek kami di mesin host dengan konten berikut:
public class Hello {
public static void main(String... ignored) {
System.out.println("Hello, World!");
}
}
Kami membangun Dockerfile ini:
FROM openjdk:8u131-jdk-alpine
WORKDIR /src
ENTRYPOINT javac Hello.java && java Hello
Kami menjalankan perintah ini:
docker run -v $(pwd)/src:/src my-openjdk
Ini mencetak "Halo, Dunia!".
Bagian terbaiknya adalah kita benar-benar bebas untuk memodifikasi file .java dengan pesan baru untuk output lain pada proses kedua - tanpa harus membangun kembali gambar =)
Komentar akhir
Saya cukup baru untuk Docker, dan "tutorial" yang disebutkan di atas mencerminkan informasi yang saya kumpulkan dari hackathon baris perintah 3 hari. Saya hampir malu saya belum dapat memberikan tautan ke dokumentasi yang jelas seperti bahasa Inggris yang mendukung pernyataan saya, tetapi saya jujur berpikir ini disebabkan oleh kurangnya dokumentasi dan bukan upaya pribadi. Saya tahu contoh berfungsi seperti yang diiklankan menggunakan pengaturan saya saat ini yaitu "Windows 10 -> Vagrant 2.0.0 -> Docker 17.09.0-ce".
Tutorial tidak menyelesaikan masalah "bagaimana kita menentukan jalur wadah di Dockerfile dan biarkan perintah jalankan hanya menentukan jalur host". Mungkin ada cara, saya belum menemukannya.
Akhirnya, saya punya firasat bahwa menentukan VOLUME
di Dockerfile bukan hanya tidak biasa, tetapi mungkin merupakan praktik terbaik untuk tidak pernah menggunakan VOLUME
. Karena dua alasan. Alasan pertama yang telah kami identifikasi: Kami tidak dapat menentukan jalur host - yang merupakan hal yang baik karena Dockerfiles harus sangat agnostik dengan spesifikasi mesin host. Tapi alasan kedua adalah orang mungkin lupa menggunakan --rm
opsi saat menjalankan wadah. Orang mungkin ingat untuk menghapus wadah tetapi lupa untuk menghapus volume. Plus, bahkan dengan ingatan manusia terbaik, mungkin merupakan tugas yang menakutkan untuk mencari tahu mana dari semua volume anonim yang aman untuk dihapus.
docker volume prune
dapat digunakan untuk membersihkan volume sisa yang tidak terpasang ke wadah yang sedang berjalan. Bukan untuk mengatakan bahwa itu akan mudah untuk distingiush yang berpotensi penting oleh id saja .../
,vol1
relatif terhadap/
, yang memutuskan untuk/vol1
. Jika Anda menggunakanWORKDIR
untuk menentukan direktori yang berfungsi selain/
,vol1
dan/vol1
tidak lagi akan menunjuk ke direktori yang sama.Menentukan
VOLUME
baris dalam Dockerfile mengkonfigurasi sedikit metadata pada gambar Anda, tetapi bagaimana metadata itu digunakan adalah penting.Pertama, apa yang dilakukan dua baris ini:
The
WORKDIR
garis ada menciptakan direktori jika tidak ada, dan update beberapa metadata gambar untuk menentukan semua path relatif, bersama dengan direktori saat ini untuk perintah sepertiRUN
akan berada di lokasi tersebut. TheVOLUME
garis ada menetapkan dua volume , satu adalah path relatif.
, dan yang lainnya/usr/src/app
, baik hanya kebetulan berada direktori yang sama. Paling seringVOLUME
baris hanya berisi direktori tunggal, tetapi bisa berisi banyak seperti yang Anda lakukan, atau bisa berupa array yang diformat json.Anda tidak dapat menentukan sumber volume di Dockerfile : Sumber kebingungan yang umum ketika menentukan volume di Dockerfile mencoba mencocokkan sintaks runtime sumber dan tujuan pada waktu pembuatan gambar, ini tidak akan berfungsi . Dockerfile hanya dapat menentukan tujuan volume. Ini akan menjadi eksploitasi keamanan sepele jika seseorang dapat menentukan sumber volume karena mereka dapat memperbarui gambar umum pada hub buruh pelabuhan untuk memasang direktori root ke dalam wadah dan kemudian meluncurkan proses latar belakang di dalam wadah sebagai bagian dari titik masuk yang menambahkan login ke / etc / passwd, mengkonfigurasi systemd untuk meluncurkan penambang bitcoin pada reboot berikutnya, atau mencari filesystem untuk kartu kredit, SSN, dan kunci pribadi untuk dikirim ke situs remote.
Apa yang dilakukan garis VOLUME? Seperti disebutkan, ini menetapkan beberapa metadata gambar untuk mengatakan direktori di dalam gambar adalah volume. Bagaimana metadata ini digunakan? Setiap kali Anda membuat wadah dari gambar ini, buruh pelabuhan akan memaksa direktori itu menjadi volume. Jika Anda tidak memberikan volume dalam perintah jalankan Anda, atau menulis file, satu-satunya pilihan untuk buruh pelabuhan adalah membuat volume anonim. Ini adalah volume bernama lokal dengan id unik panjang untuk nama dan tidak ada indikasi lain mengapa itu dibuat atau data apa yang dikandungnya (volume anonim adalah data yang hilang). Jika Anda mengganti volume, menunjuk ke volume bernama atau host, data Anda akan pergi ke sana.
VOLUME memecahkan beberapa hal: Anda tidak dapat menonaktifkan volume yang pernah didefinisikan dalam Dockerfile. Dan yang lebih penting,
RUN
perintah di buruh pelabuhan diimplementasikan dengan wadah sementara. Kontainer sementara itu akan mendapatkan volume anonim sementara. Volume anonim itu akan diinisialisasi dengan konten gambar Anda. Setiap tulisan di dalam wadah dariRUN
perintah Anda akan dibuat ke volume itu. KetikaRUN
perintah selesai, perubahan pada gambar disimpan, dan perubahan volume anonim dibuang. Karena itu, saya sangat menyarankan untuk tidak mendefinisikanVOLUME
di dalam Dockerfile. Ini menghasilkan perilaku tak terduga untuk pengguna hilir gambar Anda yang ingin memperluas gambar dengan data awal di lokasi volume.Bagaimana Anda menentukan volume? Untuk menentukan di mana Anda ingin memasukkan volume dengan gambar Anda, berikan a
docker-compose.yml
. Pengguna dapat memodifikasi itu untuk menyesuaikan lokasi volume dengan lingkungan lokal mereka, dan itu menangkap pengaturan runtime lain seperti port penerbitan dan jaringan.Seseorang harus mendokumentasikan ini! Mereka punya. Docker menyertakan peringatan tentang penggunaan VOLUME dalam dokumentasi mereka di Dockerfile bersama dengan saran untuk menentukan sumber saat runtime:
sumber
The
VOLUME
perintah dalamDockerfile
cukup legit, benar-benar konvensional, baik-baik saja untuk digunakan dan tidak usang dalam pula. Hanya perlu memahaminya.Kami menggunakannya untuk menunjuk ke direktori mana pun yang akan ditulis oleh aplikasi dalam wadah. Kami tidak menggunakan
VOLUME
hanya karena kami ingin berbagi antara host dan wadah seperti file konfigurasi.Perintah hanya membutuhkan satu param; jalur ke folder, relatif
WORKDIR
jika diatur, dari dalam wadah. Kemudian buruh pelabuhan akan membuat volume dalam grafiknya (/ var / lib / docker) dan memasangnya ke folder dalam wadah. Sekarang wadah akan memiliki tempat untuk menulis dengan kinerja tinggi. TanpaVOLUME
perintah, kecepatan tulis ke folder yang ditentukan akan sangat lambat karena sekarang wadah menggunakancopy on write
strategi itu dalam wadah itu sendiri. Thecopy on write
strategi adalah alasan utama mengapa volume ada.Jika Anda me-mount folder yang ditentukan oleh
VOLUME
perintah, perintah tidak pernah dijalankan karenaVOLUME
hanya dieksekusi ketika wadah mulai, jenis sukaENV
.Pada dasarnya dengan
VOLUME
perintah Anda mendapatkan kinerja tanpa memasang volume apa pun secara eksternal. Data akan menghemat lintas wadah juga tanpa adanya pemasangan eksternal. Kemudian ketika siap, cukup pasang sesuatu di atasnya.Beberapa contoh kasus penggunaan yang bagus:
- log
- temp folder
Beberapa kasus penggunaan buruk:
- file statis
- konfigurasi
- kode
sumber
VOLUME
direktori untuk konfigurasi. Namun begitu Anda benar-benar me-mount konfigurasi Anda harus me-mount direktori itu dan oleh karena ituVOLUME
perintah tidak berjalan. Oleh karena itu tidak ada gunanya menggunakanVOLUME
perintah pada direktori yang ditentukan untuk konfigurasi. Juga menginisialisasi grafik volume dengan file hanya baca statis statis adalah pembunuhan berat. Jadi saya mendukung apa yang saya katakan, tidak perluVOLUME
perintah pada konfigurasi.Untuk lebih memahami
volume
instruksi di dockerfile, mari kita pelajari penggunaan volume tipikal dalam implementasi file docker resmi mysql.Referensi: https://github.com/docker-library/mysql/blob/3362baccb4352bcf0022014f67c1ec7e6808b8c5/8.0/Dockerfile
Ini
/var/lib/mysql
adalah lokasi default MySQL yang menyimpan file data.Ketika Anda menjalankan wadah uji hanya untuk tujuan pengujian, Anda mungkin tidak menentukan titik pemasangannya, mis
maka instance container mysql akan menggunakan path mount default yang ditentukan oleh
volume
instruksi di dockerfile. volume dibuat dengan nama seperti ID yang sangat panjang di dalam akar Docker, ini disebut volume "tidak bernama" atau "anonim". Dalam folder sistem host / var / lib / docker / volume yang mendasarinya.Ini sangat nyaman untuk keperluan pengujian cepat tanpa perlu menentukan titik pemasangan, tetapi masih bisa mendapatkan kinerja terbaik dengan menggunakan Volume untuk penyimpanan data, bukan lapisan kontainer.
Untuk penggunaan formal, Anda harus menentukan jalur pemasangan dengan menggunakan volume yang dinamai atau bind mount, mis
Perintah me-mount direktori / my / own / datadir dari sistem host yang mendasarinya sebagai / var / lib / mysql di dalam container. Direktori data / my / own / datadir tidak akan dihapus secara otomatis, walaupun container dihapus.
Penggunaan gambar resmi mysql (Silakan periksa bagian "Di mana Menyimpan Data"):
Referensi: https://hub.docker.com/_/mysql/
sumber
-v
menggunakannya tanpa mengatur volume di DockerfileSaya tidak menganggap penggunaan VOLUME bagus dalam hal apa pun, kecuali jika Anda membuat gambar untuk diri sendiri dan tidak ada orang lain yang akan menggunakannya.
Saya terkena dampak negatif karena VOLUME terpapar dalam gambar dasar yang saya perpanjang dan hanya muncul untuk mengetahui tentang masalah setelah gambar sudah berjalan, seperti wordpress yang menyatakan
/var/www/html
folder sebagai VOLUME , dan ini berarti bahwa ada file yang ditambahkan atau diubah selama tahap pembuatan tidak dipertimbangkan, dan perubahan langsung tetap ada, bahkan jika Anda tidak tahu. Ada solusi buruk untuk menentukan direktori web di tempat lain, tetapi ini hanyalah solusi buruk untuk yang harus lebih sederhana: cukup hapus arahan VOLUME.Anda dapat mencapai maksud volume dengan mudah menggunakan
-v
opsi ini, ini tidak hanya memperjelas volume wadah (tanpa harus melihat Dockerfile dan induk Dockerfiles), tetapi ini juga memberikan konsumen pilihan untuk gunakan volume atau tidak.Ini pada dasarnya buruk untuk menggunakan VOLUMES karena alasan berikut, seperti yang dikatakan oleh jawaban ini :
Memiliki opsi untuk tidak mendeklarasikan volume akan membantu, tetapi hanya jika Anda tahu volume yang ditentukan dalam dockerfile yang menghasilkan gambar (dan parent dockerfiles!). Lebih jauh, VOLUME dapat ditambahkan dalam versi Dockerfile yang lebih baru dan memecahkan banyak hal secara tidak terduga untuk konsumen gambar.
Penjelasan bagus lainnya ( tentang gambar oracle yang memiliki VOLUME , yang telah dihapus ): https://github.com/oracle/docker-images/issues/640#issuecomment-412647328
Lebih banyak kasus di mana VOLUME memecahkan barang untuk orang:
Sebuah permintaan tarik untuk menambahkan opsi untuk me-reset sifat gambar orangtua (termasuk VOLUME), ditutup dan sedang dibahas di sini (dan Anda dapat melihat beberapa kasus dari orang terpengaruh karena volume didefinisikan dalam dockerfiles), yang memiliki komentar dengan baik a penjelasan terhadap VOLUME:
Saya juga menganggap EXPOSE buruk, tetapi memiliki sedikit efek samping. Satu-satunya hal baik yang dapat saya lihat tentang VOLUME dan EXPOSE adalah tentang dokumentasi, dan saya akan menganggap mereka baik jika mereka hanya melayani untuk itu (tanpa efek samping).
TL; DR
Saya menganggap bahwa penggunaan VOLUME terbaik harus ditinggalkan.
sumber