هر container network namespace خودش را دارد؛ بنابراین localhost داخل app به همان container اشاره میکند، نه دیتابیس یا host. Docker Network مسیر ارتباط containerها، DNS نام سرویس، دسترسی خروجی و انتشار انتخابی پورت روی host را فراهم میکند. بسیاری از خطاهای 502 و «connection refused» از اشتباه گرفتن پورت داخلی، پورت host و نام سرویس میآیند.
پاسخ سریع: در Compose سرویسهای مرتبط را روی user-defined network مشترک قرار دهید و با نام سرویس و پورت داخلی وصل کنید. فقط reverse proxy یا endpoint لازم را با ports منتشر کنید؛ دیتابیس و cache معمولاً internal میمانند. پس از recreate به IP ثابت تکیه نکنید و DNS، listener، network membership و firewall را مرحلهای بررسی کنید.
Network Namespace یعنی چه؟
Container معمولاً interface، route و port space جدا دارد. برنامهای که روی 127.0.0.1 گوش میدهد فقط داخل همان namespace قابلدسترسی است؛ برای دریافت از container دیگر باید روی interface مناسب گوش دهد. این جداسازی کامل امنیتی نیست و ruleهای host، capability و driver همچنان مهماند.
Bridge پیشفرض و User-defined Bridge
روی یک Docker host، bridge شبکه مجازی میان containerها و host میسازد. user-defined bridge برای پروژه بهتر است چون جداسازی و service discovery قابلمدیریتتری میدهد. اتصال همه سرویسها به یک شبکه بزرگ، lateral movement را آسان میکند. frontend، backend و data network را بر اساس نیاز واقعی جدا کنید؛ proxy لزوماً نباید به دیتابیس دسترسی داشته باشد.
Compose چه شبکهای میسازد؟
اگر network تعریف نکنید، Compose معمولاً یک default network برای پروژه میسازد و نام واقعی آن با project prefix همراه است. سرویسها با نام سرویس یکدیگر را پیدا میکنند. با recreate، IP میتواند عوض شود اما نام باقی میماند. اتصال کوتاهعمر باید دوباره resolve شود؛ نگهداشتن IP قدیمی در Nginx یا pool بدون reconnect میتواند failure پس از deploy بسازد.
پورت داخلی، Expose و Publish
پورت داخلی همان listener برنامه در container است. expose قرارداد دسترسی داخل network را بیان میکند و لزوماً پورت host باز نمیکند. ports mapping host به container میسازد و ممکن است سرویس را از بیرون قابلدسترسی کند. نوشتن 8080:80 یعنی مراجعه به port 8080 host به port 80 container میرود؛ container دیگر معمولاً باید service:80 را بزند، نه port host.
انتشار روی همه Interfaceها یا Loopback
اگر host address مشخص نشود، port ممکن است روی interfaceهای عمومی منتشر شود. برای سرویس محلی که Nginx نصبشده روی host مصرف میکند، binding روی 127.0.0.1 میتواند exposure را محدود کند. بااینحال firewall، IPv6 و routeهای محیط را جدا بررسی کنید. فرض نکنید چون cloud security group بسته است، config host هم امن است.
Service Discovery و DNS
Docker DNS نام سرویس را در network مشترک resolve میکند. نام container یا alias ممکن است کار کند، ولی نام پایدار سرویس بهتر است. DNS failure را از داخل container مصرفکننده بررسی کنید؛ resolve روی host نتیجه یکسانی ندارد. /etc/hosts دستی یا IP hard-codeشده، lifecycle recreate و scale را میشکند.
یک نمونه جداسازی Compose
services:
proxy:
image: nginx:stable
ports: ["80:80", "443:443"]
networks: [frontend]
app:
image: registry.example/app@sha256:...
networks: [frontend, backend]
db:
image: postgres:18
networks: [backend]
networks:
frontend:
backend:
internal: true
این فقط الگوی مفهومی است. secret، volume، health، TLS و نسخه image باید جدا تعریف شوند. شبکه internal محدودیت خروجی/ورودی خاص خود را دارد و باید dependencyهای واقعی app را بررسی کنید. proxy در این مثال به backend و در نتیجه دیتابیس وصل نیست.
Host Network چه تفاوتی دارد؟
در حالت host روی Linux، container network namespace جدا و IP مستقل معمول را ندارد و مستقیماً port host را مصرف میکند؛ در نتیجه mapping پورت بیمعنا یا نادیده گرفته میشود. این حالت isolation شبکه را کم و conflict port را بیشتر میکند. صرفاً برای حل DNS یا performance حدسی به host mode مهاجرت نکنید؛ نیاز، محدودیت platform و مدل امنیت را بسنجید.
Overlay Network برای چند Host
Overlay شبکه توزیعشده میان Docker daemonهای چند host است و معمولاً با Swarm مرتبط است. پورتهای control/data plane و firewall خاص میخواهد. Overlay رمز جادویی high availability نیست؛ state، load balancing، certificate و failure node جدا طراحی میشوند. برای standalone containerهای چند host نیز prerequisite و پیچیدگی دارد.
خروجی اینترنت و NAT
در bridge معمول، ترافیک خروجی container اغلب با NAT از host بیرون میرود. سرویس مقصد ممکن است IP host را ببیند، نه IP container. allowlist بیرونی، proxy خروجی و DNS باید با این مسیر هماهنگ باشند. اگر container اینترنت ندارد، route، DNS، firewall host و network internal را بررسی کنید؛ خاموشکردن firewall پاسخ عمومی امنی نیست.
IP واقعی کاربر پشت Reverse Proxy
App معمولاً اتصال را از proxy میبیند و IP کاربر با headerهای Forwarded منتقل میشود. فقط proxyهای مورداعتماد باید حق تعیین IP واقعی را داشته باشند؛ client میتواند header دلخواه بفرستد. راهنمای Nginx Reverse Proxy تنظیم Host، scheme و مرز اعتماد را توضیح میدهد.
IPv6 را نادیده نگیرید
DNS AAAA، firewall IPv6 و port publishing میتوانند مسیری متفاوت از IPv4 بسازند. ممکن است آزمون داخلی IPv4 موفق و کاربر IPv6 ناموفق باشد. هر دو family را از بیرون بررسی کنید. فعالسازی IPv6 در Docker و route شبکه باید آگاهانه باشد؛ ruleهای IPv4 بهطور خودکار معادل IPv6 نیستند.
Connection Refused، Timeout یا DNS Error؟
- DNS error: نام، network membership و resolver را بررسی کنید.
- Connection refused: listener، port داخلی و startup را ببینید.
- Timeout: route، firewall، saturation یا packet loss محتمل است.
- 502 proxy: upstream، health، DNS cache و log دو طرف را مقایسه کنید.
این دستهبندی تشخیص اولیه است؛ پیام دقیق و timestamp را نگه دارید.
MTU و خطاهای «بعضی درخواستها کار میکنند»
در مسیرهای VPN، cloud overlay یا tunnel ممکن است MTU شبکه container با مسیر بیرونی سازگار نباشد. اتصال کوچک موفق میشود اما response بزرگ، TLS handshake یا upload گیر میکند. پیش از تغییر MTU، packet loss، fragmentation و مسیر واقعی را اندازه بگیرید؛ مقدار کپیشده از provider دیگر ممکن است مشکل تازه بسازد. MTU باید میان interface میزبان، bridge/overlay و شبکه زیرساخت هماهنگ باشد و پس از تغییر با ترافیک واقعی آزمون شود.
External Network و اتصال چند پروژه
گاهی proxy مشترک باید به stackهای Compose جدا وصل شود. external network میتواند این اتصال را فراهم کند، اما lifecycle آن خارج از پروژه است و down همان stack مالک حذفش نیست. نام، owner، subnet و سرویسهای مجاز را مستند کنید. اتصال همه پروژهها به شبکه proxy، دسترسی متقابل ناخواسته میسازد؛ alias و network membership را حداقل نگه دارید.
همپوشانی Subnet
اگر subnet Docker با VPN، شبکه دفتر یا VPC همپوشانی داشته باشد، route اشتباه و timeout فقط برای بعضی مقصدها رخ میدهد. route table میزبان و container را پیش از تغییر ببینید. جابهجایی subnet شبکه موجود معمولاً نیازمند recreate و برنامه downtime است؛ IPAM را از ابتدا با شبکههای سازمان هماهنگ و rangeهای رزروشده را ثبت کنید.
آزمون از کدام نقطه انجام شود؟
موفق بودن درخواست از خود میزبان ثابت نمیکند مسیر container سالم است. همان درخواست را از container مصرفکننده، از network مشترک و سپس از بیرون proxy تکرار کنید و در هر مرحله نام مقصد، پورت و پاسخ DNS را ثبت کنید. برای imageهای مینیمال لازم نیست ابزار عیبیابی را دائماً داخل image production نصب کنید؛ میتوان یک container موقت و محدود را به همان network متصل کرد. این کار باید با image ابزار مورداعتماد، دسترسی حداقلی و حذف پس از بررسی انجام شود تا سطح حمله یا تغییر پنهان در artifact برنامه ایجاد نشود.
روند عیبیابی امن
- جریان مورد انتظار را از client تا service رسم کنید.
- Compose config و networkهای متصل را inspect کنید.
- نام سرویس را از container مصرفکننده resolve کنید.
- listener و port داخلی مقصد را تأیید کنید.
- اتصال TCP/HTTP کمخطر را داخل همان network بسنجید.
- log proxy، app و firewall را در یک زمان مقایسه کنید.
- پس از اصلاح، exposure پورتها را دوباره audit کنید.
اشتباههای رایج
- استفاده از localhost برای container دیگر
- اتصال به port host از network داخلی بدون نیاز
- ثابتکردن IP container
- قرار دادن proxy و database روی یک شبکه باز
- publish کردن cache و DB روی همه interfaceها
- اعتماد به Forwarded header از هر مبدأ
- تغییر به host network برای پنهانکردن config اشتباه
چه زمانی طراحی شبکه نیاز به بازبینی دارد؟
اگر چند دامنه، proxy، worker و سرویس داده دارید یا خطا فقط پس از recreate رخ میدهد، topology و DNS باید مستند شود. داکرایز اپلیکیشن میتواند شبکههای frontend/backend، exposure، health و مسیر TLS را متناسب با production طراحی کند.
پرسشهای متداول
آیا containerها برای ارتباط به publish port نیاز دارند؟
اگر در network مشترکاند، معمولاً با نام سرویس و پورت داخلی وصل میشوند.
چرا IP کانتینر بعد از deploy عوض شد؟
recreate نمونه تازه میسازد؛ نام سرویس را مبنای discovery قرار دهید.
آیا internal network کاملاً امن است؟
لایه مفیدی از محدودسازی است، اما permission برنامه، host و secret همچنان لازماند.
آیا Host Network سریعتر است؟
ممکن است NAT را حذف کند، اما tradeoff امنیت و port دارد؛ فقط با benchmark واقعی انتخاب کنید.