ترافیک کانتینرهای Docker از VPN میزبان عبور میکند: چگونه بررسی کنیم
VPN میزبان فقط فضای نام شبکه میزبان را پوشش میدهد. با این بررسیها بفهمید ترافیک کانتینرهای روی پل وارد تونل میشود یا مستقیم بیرون میرود.
مرورگر میزبان آدرس خروج VPN را نشان میدهد، کانتینر اتصال خانگی شما را گزارش میکند و کسی آن را نشت مینامد. هیچ چیز نشت نکرده است. تونل میزبان مجموعهای از رابطها، مسیرها و قواعدی است که به فضای نام شبکه میزبان تعلق دارند، و کانتینر روی پل، فضای نام دیگری با مسیر پیشفرض خودش است. من روی یک پشته Compose نشستهام که کلاینت VPN هفتهها متصل بود و حتی یک بسته کانتینر هم هرگز وارد آن نشده بود.
پیش از آیکون سینی، فضای نام را بررسی کنید
فضاهای نام تمام استدلال هستند. وقتی Docker کانتینری را روی شبکه پل راه میاندازد، یک فضای نام شبکه میسازد، یک سر جفت veth را داخل آن متصل میکند و به آن فضای نام یک آدرس و یک مسیر پیشفرض میدهد. رابط تونل، هر نامی که داشته باشد، در فضای نام میزبان زندگی میکند. ترافیک داخل کانتینر نمیتواند آن را ببیند و هیچ تنظیمی در کلاینت این را از بیرون تغییر نمیدهد.
دو حرکت پشتیبانیشده شما را از انزوا بیرون میآورد. --network host کانتینر را داخل فضای نام میزبان قرار میدهد، پس مسیرهای میزبان و در نتیجه تونل را به ارث میبرد. --network container:vpn فضای نام کانتینر دیگری را به اشتراک میگذارد و بیشتر طراحیهای sidecar بار کاری را از این راه از یک کانتینر VPN عبور میدهند. هر دو انتخابهای صریحی هستند؛ معمولاً فقط یکی از آنها همان چیزی است که شخص مستقرکننده در نظر داشته است.
حالت میزبان ارتقای رایگان نیست. کانتینر دیگر آدرس خودش را ندارد، انتشار پورت اعمال نمیشود و فرایندی که NET_ADMIN را آنجا دارد میتواند مسیریابی میزبان را بازنویسی کند. پذیرفتن این میتواند تصمیم درستی باشد. فرض کردن اینکه از قبل روشن است، همان روشی است که مردم یک شب را صرف اشکالزدایی تونلی میکنند که هرگز در مسیر نبوده است.
بسته را از پل بیرون دنبال کنید
کانتینر روی پل بستهاش را به دروازه پیشفرض خود میفرستد که همان رابط پل روی میزبان است. سپس میزبان بسته را ارسال میکند و در پیکربندی پیشفرض، آدرس مبدأ را پیش از خروج بسته به آدرس خودش ترجمه میکند. همان مرحله ترجمه است که سیاست را بیصدا خنثی میکند.
تا زمانی که بسته به نقطه پایانی تونل برسد، آدرس میزبان را حمل میکند. هر قاعده، مسیر سیاستی یا تصمیم تونل تقسیمشده که بر آدرس اصلی کانتینر تکیه دارد دیگر مطابقت نمیکند، و دو کانتینری که قرار است از خروجیهای متفاوت بیرون بروند فقط با تکیه بر مبدأ قابل تشخیص نیستند. اگر مسیریابی برای هر کانتینر لازم دارید، تصمیم باید پیش از ترجمه یا داخل فضای نامی که کنترل میکنید گرفته شود.
Docker خودش این قواعد را نگه میدارد، از طریق هر بکاند فایروالی که دیمن با آن پیکربندی شده باشد. قواعد دستنویسی خارج از قلاب پشتیبانیشده برای ترافیک ارسالشده، DOCKER-USER، میتوانند هنگام راهاندازی مجدد دیمن یا ارتقای میزبان بازچینش شوند یا حذف شوند. مستندات Docker درباره فیلتر بسته ترتیب زنجیرهها را نشان میدهد؛ نکته عملی این است که هر قاعده به یک مالک و یک مسیر بازبارگذاری نیاز دارد که واقعاً آزمایش کرده باشید.
دو سامانه را جداگانه آزمایش کنید
شواهد از یک فضای نام درباره دیگری چیزی نمیگوید. درخواستی که داخل کانتینر VPN اجرا میشود ثابت میکند تونل برای همان کانتینر کار میکند. این شواهد درباره میزبان نیست، و همان فرمانی که از کانتینر --network host اجرا شود شواهد درباره پل نیست.
# host namespace
ip route get 1.1.1.1
ip -brief addr show
# a fresh container on the same bridge network
docker run --rm --network appnet alpine sh -c 'ip route; cat /etc/resolv.conf; ip -6 route'
سپس آزمایش را داخل کانتینر واقعی برنامه تکرار کنید، نه در تصویری مشابه. برنامه ممکن است مسیر اضافه، متغیر محیطی پروکسی یا حلکننده دیگری داشته باشد و هر یک از اینها پاسخ را تغییر میدهد. هر بار تفکیک نام و خانواده دوم آدرسها را بررسی کنید: کانتینرهای روی پلهای تعریفشده توسط کاربر از طریق حلکننده داخلی Docker در 127.0.0.11 تفکیک میشوند، و یک مسیر پیشفرض IPv6 روی پل میتواند ترافیک را بیرون ببرد در حالی که شما سرگرم آزمایش تونلی فقط IPv4 هستید.
پیش از دست زدن به اعتبارنامهها الگو را بخوانید
وقتی میزبان کار میکند و کانتینر نه، علت تقریباً همیشه ساختاری است و چرخاندن کلیدها یا نصب دوباره کلاینت یک بعدازظهر را تلف میکند. اول نشانه را مرتب کنید و اصلاح معمولاً خودش را نام میبرد.
| What you see | Usual cause | First check |
|---|---|---|
| Host exits through the VPN, container shows the ISP address | The container never entered the tunnel | Default route inside the container |
| Container works until the daemon restarts, then stops | Rules outside the supported hook, or a changed backend | Daemon's reported firewall backend and DOCKER-USER |
| Container loses internal hosts after the tunnel comes up | VPN prefix overlaps the Docker bridge subnet | ip route on the host, then docker network inspect |
| Small replies arrive, large ones hang | Tunnel MTU or missing MSS clamping | Link MTU on both ends of the tunnel |
| Container falls back to the ISP address when the tunnel drops | Nothing enforces the kill switch for forwarded traffic | Stop the tunnel with a request in flight |
ردیف همپوشانی جمله خودش را میخواهد. پروفایل VPN که مسیری برای 172.17.0.0/16 یا برای 10.0.0.0/8 که تصادفاً پیشوند پل شما را در خود دارد هُل میدهد، باعث میشود تونل زیرشبکه کانتینر را ادعا کند و پاسخها به آدرسهای ترجمهشده در جهت اشتباه میروند یا ناپدید میشوند. شمارهگذاری دوباره شبکه Docker معمولاً پاکیزهتر از انباشتن استثناهاست.
پوشش را صریح کنید و بعد عمداً آن را بشکنید
دو طراحی در بازبینی دوام میآورند. فضای نام کانتینر VPN را به اشتراک بگذارید تا هر بار کاری پوششدادهشده از یک تونل با یک مرز راهاندازی مجدد استفاده کند، که ساده است تا زمانی که یک سرویس به خروجی متفاوت یا مسیر DNS خودش نیاز پیدا کند. یا شبکه کانتینرها را به یک دروازه VPN روی میزبان مسیر دهید: ارسال فعال، پیشوند پل به سمت تونل نشانهرفته، ترافیک برگشتی صریحاً مدیریتشده. این کنترل بهازای هر شبکه را میخرد و برایتان مجموعهای از قواعد میگذارد که باید در ارتقاهای دیمن و کلاینت نگه دارید.
هر طور که باشد، آزمایشی که اهمیت دارد حالت شکست است. تونل را با درخواستی از کانتینر در میانه راه متوقف کنید و ببینید بسته کجا میرود. اگر به مسیر مستقیم برگردد، پوشش هرگز اعمال نشده بود، چون kill switch کلاینت ترافیک خود کلاینت را اداره میکند و نه بستههای ارسالشده از یک پل. بعد دیمن و میزبان را دوباره راهاندازی کنید و نتیجه را بار دوم تأیید کنید؛ همان لحظهای است که قواعد دستنویس ناپدید میشوند.
پیش از تمامشده دانستن، چهار چیز را تأیید کنید: رابط تونل در همان فضای نام ترافیک است، آزمایش کانتینر داخل کانتینر واقعی اجرا شده، تفکیک نام و هر دو خانواده آدرس بررسی شدهاند، و آزمایش شکست تونل هنوز بسته شکست میخورد. سپس بکاند فایروال، نسخه کلاینت و مالک هر قاعده را بنویسید. همان سابقه است که مانع میشود ارتقای بعدی آمیزهای مستندنشده از فرضهای قدیمی بر جای بگذارد.