Mount volume Docker gagal setelah VPN terhubung: periksa daemon
Bind mount Anda baik-baik saja. VPN mengubah daemon mana yang menjawab klien, jadi cetak endpoint, buktikan jalurnya di sana, dan berhenti mengedit volume.
Hampir setiap tulisan tentang masalah ini menyalahkan volume, dan itulah sebabnya perbaikannya butuh waktu lama. Anda punya bind mount yang berfungsi, VPN kantor terhubung, dan docker compose up sekarang gagal dengan jalur sumber yang hilang, direktori kosong, atau mount yang ditolak dibuat oleh mesin. Di lingkungan yang saya rapikan, berkas Compose tidak berubah dan jalurnya benar. Yang berubah adalah daemon mana yang menerima permintaan, dan kesalahan mount hanyalah tempat pertama perbedaan itu terlihat.
Volumenya tidak pernah berpindah; permintaannya yang berpindah
Bendera -v /srv/app:/app bukan salinan direktori yang dilakukan shell Anda. Klien mengubahnya menjadi permintaan API, dan daemon yang menjawab menyelesaikan /srv/app terhadap sistem berkasnya sendiri. Ketika kedua sisi berjalan pada kernel yang sama, jalur itulah yang Anda lihat di pengelola berkas. Ketika endpoint berubah, string yang sama dicari di mesin yang belum pernah mendengar direktori proyek Anda, dan daemon melaporkan sumbernya hilang atau diam-diam membuat direktori kosong sebagai gantinya.
Itu juga sebabnya volume bernama tetap berfungsi sementara bind mount tidak. -v appdata:/app menamai penyimpanan yang dimiliki daemon, jadi tidak ada jalur host yang harus ada di tempat tertentu. Jika mengganti satu layanan dari bind mount ke volume bernama membuat kesalahan hilang, Anda belum memperbaiki masalahnya. Anda telah memastikan bahwa klien dan daemon tidak sepakat tentang sistem berkas mana jalur itu milik, dan ketidaksepakatan itu kembali begitu Anda memerlukan direktori host sungguhan lagi.
Cetak endpoint sebelum menyentuh mount
Beberapa pengaturan dapat mengarahkan klien ke endpoint, dan tidak selalu sepakat: bendera --context , DOCKER_CONTEXT, DOCKER_HOST di shell saat ini, dan konteks yang disimpan dalam konfigurasi klien. Daripada menalar prioritas, cetak semuanya dan bandingkan jawabannya.
docker context show
docker context ls
docker version
docker info --format "{{.Name}} {{.OperatingSystem}} {{.ServerVersion}}"
Konfigurasi klien berada di ~/.docker/config.json di Linux dan macOS dan di %USERPROFILE%\.docker\config.json di Windows, dan nilai yang diekspor di terminal saat ini menimpa nilai tersimpan hanya untuk sesi itu. Jika endpoint adalah nama host alih-alih socket lokal, resolusi nama dan rute menentukan di mana ia mendarat, dan itulah yang ditulis ulang oleh klien VPN. Terowongan yang menambahkan rute atau mengganti resolver dapat mengirim nama yang dulu berarti laptop ini ke alamat di dalam jaringan kantor.
Bandingkan keadaan, bukan konfigurasi. Jalankan docker ps -a dan docker images dengan terowongan mati, lalu lagi dengan terowongan hidup. Daftar kontainer yang berbeda adalah bukti lebih kuat daripada berkas konfigurasi mana pun, karena menunjukkan bahwa daemon lain menjawab permintaan Anda.
Tanyakan kepada daemon apakah jalur itu ada di sana
Setelah Anda tahu daemon mana yang dicapai, suruh ia melihat direktori itu. Bentuk --mount gagal dengan pesan yang lebih jelas daripada bendera pendek, karena memvalidasi sumber sebelum memulai kontainer:
docker run --rm --mount type=bind,source=/srv/app,target=/app alpine ls -la /app
Jika ia melaporkan sumbernya hilang, buatlah di mesin yang menjawab, atau arahkan layanan ke volume bernama dan salin datanya ke sana. Yang tidak boleh Anda lakukan adalah membuat ulang volume dan memasang ulang mesin sebelum pemeriksaan ini. Tindakan itu mengubah lingkungan cukup untuk menyembunyikan ketidakcocokan sambil membiarkannya di tempatnya.
Satu jalur lagi berjalan di tempat yang sama sekali berbeda: menarik image adalah pekerjaan daemon, bukan klien. Penarikan yang berhasil hanya membuktikan bahwa daemon dapat mencapai registry, dan bind mount yang berfungsi hanya membuktikan bahwa sebuah jalur terselesaikan. Uji setiap jalur di tempat ia benar-benar dijalankan, atau Anda akan menghabiskan satu sore pada jalur yang salah.
Nama intranet gagal karena alasan berbeda
Paruh kedua laporan yang sama biasanya adalah kontainer tidak dapat menjangkau intranet.corp.example. Itu mekanisme terpisah, bukan masalah volume kedua. Kontainer mendapatkan /etc/resolv.conf nya saat mulai, dihasilkan dari pengaturan resolver daemon, jadi server DNS yang ditambahkan VPN setelah kontainer dibuat tidak akan muncul di sana sampai kontainer dibuat ulang.
Resolver bawaan Docker pada jaringan yang ditentukan pengguna meneruskan pencarian eksternal ke server yang dikonfigurasi di host, yang membantu ketika VPN menulis ulang resolver host dan merugikan ketika DNS terpisah mengirim zona internal ke server yang tidak lagi dilihat daemon. Pemetaan sempit dan eksplisit menghindari perdebatan untuk nama yang tidak pernah berubah:
services:
web:
extra_hosts:
- "intranet.corp.example:10.20.30.40"
Ini menulis entri ke berkas hosts kontainer, sehingga kontainer tidak pernah tahu apa pun tentang terowongan, dan itu juga membekukan alamatnya. Ketika host internal berpindah, entri itu tetap salah sampai seseorang mengedit berkas Compose. Gunakan untuk perangkat tetap atau basis data yang dipatok, dan biarkan DNS menangani nama yang berpindah.
Apa yang sebenarnya diubah oleh pemasangan ulang
Memasang ulang Docker Desktop membuat ulang VM, socket, dan daftar konteks, dan mount mulai berfungsi lagi. Hasil itu nyata dan tidak mengajarkan apa pun, itulah sebabnya kegagalan yang sama kembali setelah pembaruan VPN berikutnya. Pemasangan ulang menggantikan endpoint yang dipakai klien; itu tidak menyelaraskan jalur yang dinamai proyek Anda dengan sistem berkas yang benar-benar dibaca daemon.
Urutan kerja saya singkat. Pastikan endpoint mana yang akan dipakai klien. Pastikan daemon mana yang menjawab dengan membandingkan daftar kontainer. Minta daemon itu mencantumkan jalur sumber. Baru setelah itu edit mount, tambahkan entri hosts, atau ubah jenis volume. Jika Anda memelihara berkas Compose untuk tim yang bekerja lewat VPN, utamakan volume bernama untuk data yang seharusnya dimiliki daemon, agar jalur host tidak pernah menjadi bagian dari kontrak.