Docker Compose: Bind Mount atau Volum Bernama?
Ketahui bila menggunakan bind mount atau volum bernama untuk konfigurasi dan data, termasuk perangkap kebenaran fail serta cara memeriksa, menyandar dan memindahkan data.
Mount bind atau volum bernama: jawapan ringkas
Volum Docker Compose terdiri daripada dua jenis. Pilihan bergantung pada pihak yang mengurus fail tersebut. Gunakan mount bind untuk fail yang anda tulis dan baca sendiri, seperti konfigurasi, templat dan tapak statik. Gunakan volum bernama untuk data yang diurus oleh aplikasi, seperti fail pangkalan data, indeks carian dan media yang dimuat naik. Mount bind menunjuk kepada laluan pada hos yang boleh anda buka dalam editor. Volum bernama ialah storan yang dicipta dan dijejaki oleh Docker untuk anda, dan anda mengaksesnya melalui Docker.
Kedua-duanya muncul di bawah kunci volumes: yang sama dalam sesuatu perkhidmatan. Sebab itu kedua-duanya sering disalah anggap sama. Perbezaannya ialah bahagian kiri tanda titik bertindih. Bahagian kiri yang bermula dengan . atau / ialah laluan hos, jadi ia merupakan mount bind. Apa-apa sahaja yang lain ialah nama, jadi ia merupakan volum bernama. Nama tersebut juga mesti diisytiharkan dalam blok volumes: peringkat atas.
Dua sintaks dalam fail compose
services:
db:
image: postgres:17
environment:
POSTGRES_PASSWORD: changeme
volumes:
- pgdata:/var/lib/postgresql/data
web:
image: nginx:1.27
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./site:/usr/share/nginx/html:ro
volumes:
pgdata:pgdata:/var/lib/postgresql/data ialah volume bernama. ./nginx.conf:/etc/nginx/nginx.conf ialah bind mount, manakala :ro memasangnya sebagai baca sahaja. Ini ialah nilai lalai yang betul untuk konfigurasi yang tidak sepatutnya ditulis semula oleh container. Jika entri volumes: peringkat atas tiada, Compose berhenti dengan service "db" refers to undefined volume pgdata.
Mulakan dan senaraikan perkara yang dicipta oleh Docker:
docker compose up -d
docker volume lsNama volume itu bukan pgdata. Namanya ialah <project>_pgdata, kerana nama projek secara lalai ialah nama direktori yang mengandungi fail compose. Direktori bernama myapp menghasilkan myapp_pgdata. Perkara ini penting kerana penamaan semula direktori akan menghasilkan volume kosong yang baharu, lalu aplikasi kelihatan seperti kehilangan datanya. Sebenarnya tidak: volume lama masih disenaraikan oleh docker volume ls. Tetapkan nama dengan name: dalam fail compose, atau tetapkan COMPOSE_PROJECT_NAME jika direktori itu mungkin dipindahkan. Tetapan seperti ini hendaklah diletakkan bersama fail persekitaran dan rahsia Compose yang lain.
Mengapa ralat kebenaran hanya berlaku pada bind mount
Inilah perbezaan praktikal yang paling ketara. Perbezaan ini berpunca daripada satu peraturan: named volume yang kosong pada penggunaan pertama diisi daripada imej, manakala bind mount tidak.
Apabila Docker memasang named volume yang kosong pada direktori yang sudah mengandungi kandungan dalam imej, Docker menyalin kandungan tersebut ke dalam volume, termasuk pemilikan dan mod yang ditetapkan oleh imej. Imej Postgres rasmi menyediakan /var/lib/postgresql/data yang dimiliki oleh pengguna postgres sendiri. Oleh itu, volume tersebut dimiliki oleh id berangka yang sama dan pangkalan data dapat dimulakan.
Bind mount berfungsi sebaliknya. Apa-apa yang terdapat pada hos akan dilihat oleh kontena, termasuk pemilikan, manakala kandungan imej pada laluan tersebut disembunyikan. Jika direktori pada hos tidak wujud, daemon Docker menciptanya dan daemon berjalan sebagai root. Oleh itu, anda mendapat direktori yang dimiliki oleh root:root. Proses kontena yang berjalan sebagai pengguna bukan root tidak dapat menulis kepadanya:
PermissionError: [Errno 13] Permission denied: '/data/app.db'Penyelesaiannya ialah menyamakan nombor tersebut. Pemilikan merentasi bind mount dibandingkan berdasarkan id pengguna berangka, bukan nama, kerana kontena mempunyai /etc/passwd sendiri. Pengguna bernama app dalam kontena tidak mempunyai makna pada hos. Uid 1000 bermaksud uid 1000 pada kedua-dua pihak.
id -u
mkdir -p ./data
docker compose exec web id
sudo chown -R 1000:1000 ./datadocker compose exec web id mencetak uid yang digunakan oleh proses kontena sebenar. Samakan direktori hos dengan nombor tersebut, atau tetapkan kontena supaya menggunakan nombor anda dengan user: "1000:1000" dalam perkhidmatan. Menetapkan user: lebih kemas untuk aplikasi yang anda tulis sendiri. Menukar pemilikan direktori hos dengan chown lebih selamat untuk imej yang tidak anda tulis, kerana sesetengah imej memulakan entrypoint sebagai root, menggugurkan keistimewaan, kemudian memerlukan pemilikan tertentu pada direktori di bawahnya.
Terdapat dua perangkap lain yang perlu diketahui. Pada Fedora, RHEL dan sistem lain yang menguatkuasakan SELinux (security-enhanced Linux), bind mount akan ditolak sehingga dilabel semula. Oleh itu, tambahkan :z untuk laluan yang dikongsi antara kontena, atau :Z untuk laluan yang hanya boleh digunakan oleh satu kontena, dan tuliskannya sebagai - ./data:/data:Z. Selain itu, bind mount bagi satu fail, bukannya direktori, akan rosak apabila editor menggantikan fail tersebut dan bukannya menulis terus ke dalamnya, kerana mount mengikut inode asal. Kontena akan terus melihat kandungan lama sehingga anda memulakannya semula. Pasang direktori induk apabila fail tersebut kerap diedit.
Prestasi: keadaan yang benar-benar menunjukkan perbezaan
Pada pelayan Linux, kedua-dua jenis melalui laluan kernel yang sama. Oleh itu, perbezaan daya pemprosesan cukup kecil sehingga anda tidak sepatutnya membuat pilihan berdasarkan faktor itu. Volum bernama yang menggunakan pemacu lalai local berada pada sistem fail yang sama seperti bahagian Docker yang lain, di bawah /var/lib/docker/volumes/. Lekapan bind pula berada di lokasi yang anda tetapkan.
Perbezaan ketara muncul pada Docker Desktop untuk macOS dan Windows, apabila bekas dijalankan dalam mesin maya. Lekapan bind di situ merentasi sistem fail hos ke dalam mesin maya melalui lapisan perkongsian fail. Beban kerja yang melakukan banyak operasi fail kecil, seperti pepohon kebergantungan Node.js atau cache rangka kerja PHP, menjadi lebih perlahan dengan ketara. Volum bernama kekal dalam mesin maya dan tidak menanggung kos tersebut. Oleh sebab itu, banyak fail compose pembangunan memasang direktori sumber menggunakan bind mount tetapi mengisytiharkan volum bernama pada node_modules.
Perbezaan sebenar yang lain ialah lokasi data disimpan. Lekapan bind pada /mnt/backup menyimpan data pada cakera tersebut. Volum bernama disimpan pada sistem fail yang mengandungi /var/lib/docker, yang biasanya merupakan cakera root pada VPS. Pangkalan data yang berkembang dalam volum bernama akan memenuhi cakera yang sama tempat log sistem anda disimpan. Semak keadaan ini sebelum menjadi insiden:
docker system df -v
df -h /var/lib/dockerdocker system df -v menyenaraikan setiap volum berserta saiznya dan menandakan volum yang tidak lagi dirujuk oleh mana-mana bekas.
Memeriksa volume bernama
Volume bernama bukan kotak hitam. Tanya Docker lokasinya:
docker volume inspect myapp_pgdataMedan Mountpoint memberikan laluan hos sebenar, biasanya /var/lib/docker/volumes/myapp_pgdata/_data. Anda boleh membacanya dengan sudo ls, dan ini berguna untuk pemeriksaan pantas. Jangan anggap laluan ini sebagai tempat untuk mengedit fail. Menulis di situ sebagai root akan menghasilkan semula masalah pemilikan yang diterangkan di atas, dan laluan itu ialah butiran pemacu local yang tidak dikongsi oleh pemacu volume lain.
Cara yang selamat untuk melihat kandungannya ialah menggunakan bekas sementara yang memasang volume tersebut:
docker run --rm -v myapp_pgdata:/vol alpine ls -la /volCara ini berfungsi untuk mana-mana pemacu, melihat keizinan yang sama seperti yang dilihat oleh bekas sebenar, dan tidak meninggalkan apa-apa kerana --rm.
Membuat sandaran bagi setiap jenis
Lekapan bind ialah direktori biasa, jadi mana-mana alat sandaran peringkat fail boleh mengendalikannya. Tujukan sandaran kepada laluan hos dan anda selesai. Volum bernama memerlukan satu langkah tambahan kerana alat itu perlu mengakses kandungannya. Lekapkan volum dan direktori hos ke dalam bekas sementara yang sama, kemudian tulis arkib:
docker run --rm \
-v myapp_pgdata:/data:ro \
-v "$PWD":/backup \
alpine tar czf /backup/pgdata.tar.gz -C /data .Pulihkan dengan membalikkan proses tersebut ke dalam volum baharu:
docker volume create myapp_pgdata_restored
docker run --rm \
-v myapp_pgdata_restored:/data \
-v "$PWD":/backup \
alpine tar xzf /backup/pgdata.tar.gz -C /datatar mengekalkan pemilikan berangka apabila perintah itu dijalankan sebagai root di dalam bekas. Ini memastikan volum yang dipulihkan boleh digunakan oleh aplikasi.
Satu amaran terpakai pada kedua-dua jenis. Menyalin fail pangkalan data semasa pangkalan data sedang berjalan menghasilkan arkib daripada keadaan yang terus berubah, dan arkib itu boleh dipulihkan dalam keadaan rosak. Hentikan perkhidmatan terlebih dahulu, atau lakukan dump menggunakan alat pangkalan data itu sendiri, seperti dalam docker compose exec -T db pg_dump -U postgres appdb > appdb.sql. Tindakan ini menghasilkan fail biasa yang kemudiannya boleh disertakan dalam rutin sandaran restic yang disulitkan bersama-sama fail compose.
Memindahkan bind mount kepada volume bernama
Pemindahan ini ialah proses penyalinan, bukan penamaan semula, dan mengambil masa kira-kira seminit.
docker compose down
docker volume create myapp_pgdata
docker run --rm \
-v "$PWD/data":/from \
-v myapp_pgdata:/to \
alpine sh -c 'cp -a /from/. /to/'cp -a mengekalkan pemilikan, mod dan cap masa. Oleh itu, pengguna kontena yang boleh membaca direktori lama masih boleh membaca volume baharu. Kemudian ubah perkhidmatan supaya menggunakan pgdata:/var/lib/postgresql/data, tambahkan pgdata pada blok volumes: peringkat teratas, jalankan docker compose up -d, dan baca log aplikasi sebelum anda memadamkan direktori lama. Untuk arah yang bertentangan, gunakan perintah yang sama dengan /from dan /to ditukar tempat.
Ingat satu perkara semasa anda menguji. docker compose down tidak mengubah volume bernama, tetapi docker compose down -v memadamkan setiap volume bernama yang diisytiharkan oleh projek, dan tindakan ini tidak boleh dibuat asal. Bind mount kekal selepas kedua-dua perintah tersebut kerana Docker tidak pernah memiliki direktori itu. Jika perintah kitar hayat masih baharu bagi anda, panduan asas Docker Compose untuk VPS menerangkannya langkah demi langkah.
Pemilihan, mengikut perkhidmatan
Tentukan pihak yang menulis fail tersebut. Konfigurasi yang anda edit dalam penyunting teks dan commit ke git perlu diletakkan dalam bind mount, dipasang pada :ro, kerana anda mahu konfigurasi itu kelihatan dan mempunyai versi. Keadaan aplikasi yang tidak pernah anda buka secara manual perlu diletakkan dalam named volume, kerana Docker menetapkan keizinan dengan betul dan data tidak bergantung pada laluan hos.
Kes campuran ialah media. Pustaka foto ditulis oleh aplikasi tetapi juga diurus oleh anda, dan biasanya cukup besar sehingga memerlukan cakera tertentu. Bind mount pustaka itu ke laluan pada cakera tersebut, kemudian tetapkan pemilikan dengan sengaja sekali sahaja. Itulah corak yang biasanya digunakan oleh tindanan yang dihoskan sendiri: named volume untuk pangkalan data dan cache, bind mount untuk konfigurasi serta direktori besar yang penting bagi anda.
FAQ
Apakah perbezaan antara bind mount dengan volum bernama?
Bind mount memetakan laluan pada hos ke dalam kontena. Oleh itu, kedua-dua pihak melihat direktori yang sama dan anda boleh mengeditnya menggunakan alat biasa. Volum bernama ialah storan yang dicipta dan diurus oleh Docker. Volum ini dirujuk mengikut nama dan diisytiharkan dalam blok volumes: peringkat atas. Perbezaan praktikalnya ialah pemilikan: gunakan bind mount untuk konfigurasi yang anda selenggara dan volum bernama untuk data yang diselenggara oleh aplikasi.
Mengapakah saya mendapat "permission denied" dengan bind mount tetapi tidak dengan volum bernama?
Volum bernama yang kosong diisi daripada imej. Oleh itu, volum tersebut mewarisi pemilikan yang ditetapkan oleh imej dan pengguna kontena boleh menulis kepadanya. Bind mount memaparkan direktori hos tepat seperti keadaannya. Jika Docker terpaksa mencipta direktori itu, Docker menciptanya dengan pemilikan root. Jalankan docker compose exec <service> id untuk melihat id berangka yang digunakan oleh kontena. Kemudian, jalankan sudo chown -R <uid>:<gid> pada direktori hos atau tetapkan user: "1000:1000" pada perkhidmatan.
Di manakah Docker menyimpan volum bernama pada cakera?
Dengan pemacu lalai local, volum tersebut disimpan di bawah /var/lib/docker/volumes/<volume>/_data dan docker volume inspect <volume> mencetak Mountpoint yang tepat. Baca nilainya jika anda perlu menyemak sesuatu. Namun, tulis kepadanya hanya melalui kontena kerana pengeditan sebagai root pada hos mengubah pemilikan dengan cara yang tidak dijangka oleh kontena.
Bagaimanakah saya membuat sandaran volum bernama?
Jalankan kontena sementara dengan volum dan direktori hos dipasang, kemudian arkibkan data dari satu lokasi ke lokasi yang lain menggunakan docker run --rm -v myvol:/data:ro -v "$PWD":/backup alpine tar czf /backup/myvol.tar.gz -C /data .. Untuk pangkalan data, buat dump menggunakan alat pangkalan data itu sendiri dan bukannya menyalin fail yang sedang digunakan. Salinan fail yang dibuat ketika operasi penulisan sedang berlangsung boleh dipulihkan dalam keadaan rosak.
Adakah docker compose down memadam volum saya?
docker compose down mengalih keluar kontena dan rangkaian, serta mengekalkan volum bernama. docker compose down -v turut memadamkan setiap volum bernama yang diisytiharkan oleh projek secara kekal. Bind mount tidak pernah dialih keluar oleh mana-mana perintah tersebut kerana direktori itu milik hos, bukan Docker.