چرا کانتینرهای Docker ریزالور DNS شبکه VPN را نادیده میگیرند
کانتینر هنگام شروع، ریزالور میزبان را کپی میکند، بنابراین VPNی که بعداً DNS را بازنویسی میکند درون آن نامرئی میماند. ریزالور را صریحاً ارسال کنید.
VPN فعال است، مرورگر به سایتهای داخلی میرسد، و کانتینر هنوز نمیتواند همان نامها را حل کند. نصب یک بسته با خطای حل نام مانند EAI_AGAIN از کار میافتد، یا یک برنامه نمیتواند میزبان پایگاه دادهای را پیدا کند که ماشین میزبان بدون هیچ شکایتی حلش میکند. کانتینر از ریزالوری که VPN نصب کرده استفاده نمیکند. Docker هنگام ساخت کانتینر پیکربندی ریزالور میزبان را کپی کرد، و پس از آن هیچچیز دوباره آن را کپی نکرد.
دو نمای ریزالور روی یک ماشین
در Linux، Docker هنگام ساخت به هر کانتینر یک کپی از پیکربندی ریزالور میزبان میدهد، نشانیهای loopback را فیلتر میکند و یک سرور DNS توکار روی 127.0.0.11 اجرا میکند که پرسوجوها را به بیرون هدایت میکند. کلاینت VPNی که پس از شروع کانتینر /etc/resolv.conf را بازنویسی کند، چیزی را درون آن تغییر نمیدهد. راهاندازی دوباره کانتینر تنها وقتی کمک میکند که ریزالور میزبان در آن لحظه تصادفاً درست باشد.
Docker Desktop روی macOS یا Windows یک لایه اضافه میکند، چون دیمن در یک ماشین مجازی زندگی میکند. ممکن است ریزالور VPN میزبان هرگز برای آن VM قابل مشاهده نباشد، بنابراین راهاندازی دوباره هیچ چیزی را تغییر نمیدهد. پیش از انتخاب راهحل دو نما را مقایسه کنید: docker exec mycontainer cat /etc/resolv.conf در کنار فهرست ریزالورهای میزبان.
کانتینری که ریزالور عمومی فهرست میکند در حالی که میزبان ریزالور داخلی فهرست میکند، نامهای عمومی را حل میکند و در نامهای داخلی شکست میخورد. این شکاف امضای این مشکل است.
گزینه A: ارسال ریزالور تونل برای هر کانتینر
Docker تنظیمات DNS را برای هر کانتینر میپذیرد، و این کوچکترین تغییری است که کار میکند. ابتدا نشانیهای ریزالور VPN را بخوانید: scutil --dns روی macOS، resolvectl status یا خروجی وضعیت خود کلاینت روی Linux. سپس کانتینر را با آنها راهاندازی کنید، برای نمونه docker run --dns 192.168.2.1 --dns 192.168.123.1 myimage. در Compose همان تنظیم یک فهرست زیر سرویس است، جایی که در کنترل نسخه زندگی میکند نه در تاریخچه شل کسی.
آرایه dns در /etc/docker/daemon.json روی هر کانتینر جدید اعمال میشود، که مرتبتر به نظر میرسد و نیست. همچنین وقتی تونل قطع است اعمال میشود، و آنگاه ریزالوری که فقط از طریق VPN در دسترس است، کشیدن تصویرهای معمولی را میشکند. تنظیمات هر کانتینر آسانتر توجیه میشوند و آسانتر برگردانده میشوند.
گزینه B: اجازه دهید کانتینر شبکه میزبان را به اشتراک بگذارد
شبکه میزبان کپی را کاملاً دور میزند، چون کانتینر از ریزالور میزبان و تونل میزبان استفاده میکند. همچنین جداسازی شبکهای را که احتمالاً میخواستید حذف میکند، و زیر Docker Desktop رفتار یکسانی ندارد. در Linux انتخاب عملگرایانه برای ابزاری یکبارمصرف است که باید نامهای داخلی را حل کند.
برای ساختها هیچیک از دو گزینه اعمال نمیشود، چون گامهای ساخت پرچمهای زمان اجرا را به ارث نمیبرند. جایی که پلتفرم اجازه میدهد با شبکه میزبان بسازید، یا نصب وابستگیها را در مرحلهای نگه دارید که به تونل نیاز ندارد.
چیزی که هیچیک از دو گزینه درست نمیکند
نشانی DNS بیفایده است اگر کانتینر مسیری به آن نداشته باشد. ریزالور VPN معمولاً درون فضای نشانی تونل قرار دارد، بنابراین کانتینر به مسیری تا آن پیشوند نیاز دارد. پل پیشفرض Docker معمولاً از طریق میزبان به بیرون مسیریابی میکند، و وقتی میزبان مسیر تونل را دارد و ارسال به جلو فعال است کافی است. شبکههای پل سفارشی با استخرهای نشانی خودشان میتوانند با زیرشبکه VPN برخورد کنند، و آنگاه پرسوجوها کاملاً جای دیگری میروند.
پیش از اشکالزدایی خود ریزالور، زیرشبکه شبکه Docker را با زیرشبکه VPN بسنجید. همپوشانی شکستی تولید میکند که دقیقاً شبیه یک سرور DNS خراب است.
درون کانتینر بررسی کنید
درون کانتینر به جای مرورگر یا محیط اجرای زبان با getent hosts db.internal آزمایش کنید، چون آنها سیاست DNS و حافظه پنهان خودشان را اعمال میکنند. اگر getent نام را حل کند و برنامه هنوز شکست بخورد، ریزالور اکنون درست است و مشکل باقیمانده در سطح برنامه است. اگر حلش نکند، گام DNS تمام نشده است.
پس از تغییر تنظیمات DNS کانتینر، آن را دوباره بسازید. ویرایش /etc/resolv.conf درون یک کانتینر در حال اجرا با آن از بین میرود و مشکل پیکربندی را دقیقاً به همان مدت که کسی برای راهاندازی دوبارهاش وقت میگذارد پنهان میکند.