کانتینر بدون شبکه و ذخیرهسازی درست، یا از بقیهی سرویسها جداست یا دادهاش با اولین حذف کانتینر از بین میرود. این راهنما دو موضوع را کنار هم توضیح میدهد: چگونه کانتینرها به هم و به بیرون وصل میشوند (درایورهای شبکه، DNS داخلی و انتشار پورت)، و چگونه دادهی ماندگار نگهداری و پشتیبانگیری میشود (volume و bind mount).
درایورهای شبکه در Docker
| درایور | رفتار | کاربرد |
|---|---|---|
| bridge | شبکهی خصوصی روی یک میزبان؛ پیشفرض | اغلب سرویسهای روی یک سرور |
| host | کانتینر مستقیم از شبکهی میزبان استفاده میکند (بدون NAT) | کارایی بالا یا برنامههایی با بازهی پورت زیاد |
| none | بدون شبکه | پردازشهای ایزولهی بدون نیاز به شبکه |
| overlay | شبکهی مشترک بین چند میزبان (Swarm) | خوشههای چندسرورهی Swarm |
| macvlan | هر کانتینر یک MAC و IP مستقل در شبکهی فیزیکی | برنامههایی که باید مستقیماً در LAN دیده شوند |
برای اغلب پروژهها bridge سفارشی کافی است و host فقط وقتی لازم است که دلیل مشخصی (کارایی یا پورتهای متعدد) دارید؛ در حالت host ایزولهسازی شبکه از بین میرود.
DNS داخلی و شبکهی سفارشی
در شبکهی bridge پیشفرض، کانتینرها فقط با IP یکدیگر را میشناسند و IP بعد از هر ریاستارت عوض میشود. در یک شبکهی سفارشی، Docker یک DNS داخلی دارد و کانتینرها با نام سرویس به هم میرسند. Compose بهطور خودکار برای هر پروژه یک شبکهی سفارشی میسازد، پس db از داخل سرویس app همانطور resolve میشود که نوشتهاید.
docker network create appnet
docker run -d --name db --network appnet postgres:16
docker run --rm --network appnet alpine getent hosts db
جداسازی لایهها با چند شبکه
با تعریف چند شبکه میتوانید مشخص کنید چه سرویسی با چه سرویسی ارتباط دارد. در این نمونه، پروکسی فقط به برنامه میرسد، دیتابیس فقط از برنامه قابلدسترس است و شبکهی backend هیچ ارتباطی با بیرون ندارد:
services:
proxy:
image: nginx:1.27-alpine
ports: ["80:80"]
networks: [frontend]
app:
image: registry.example.com/app:1.8.2
networks: [frontend, backend]
db:
image: postgres:16.4-alpine
networks: [backend]
networks:
frontend:
backend:
internal: true # بدون دسترسی به اینترنت و بیرون
YMLDocker Compose Validatorفایل Compose خود را پیش از اجرا از نظر ساختار و کلیدهای ناشناخته بررسی کنید.
انتشار پورت
کانتینرهای همشبکه بدون هیچ انتشاری به پورتهای یکدیگر دسترسی دارند. انتشار پورت (-p یا ports) فقط برای دسترسی از میزبان یا بیرون لازم است:
docker run -p 8080:80 nginx # روی همهی اینترفیسها
docker run -p 127.0.0.1:8080:80 nginx # فقط از خود میزبان
docker port <container> # نمایش پورتهای منتشرشده
ufw deny 5432 پورت منتشرشدهی دیتابیس را نمیبندد. راه امنتر، منتشرنکردن پورت یا بستن آن روی 127.0.0.1 است؛ در غیر این صورت قانون را در زنجیرهی DOCKER-USER بنویسید.رنج آدرس شبکههای Docker
Docker از رنجهایی مثل 172.17.0.0/16 و بعد از آن بازههایی در 172.x و 192.168.x برای شبکههای خودش استفاده میکند. اگر این رنجها با شبکهی شرکت، VPN یا VPC شما همپوشانی داشته باشند، دسترسی به بعضی سرورها قطع میشود. رنج پیشفرض را در /etc/docker/daemon.json عوض کنید:
{
"default-address-pools": [
{ "base": "10.200.0.0/16", "size": 24 }
]
}
بعد از ذخیره، سرویس Docker را ریاستارت کنید (شبکههای موجود تغییر نمیکنند و باید دوباره ساخته شوند). برای محاسبهی رنجها و اطمینان از نبود همپوشانی، از راهنمای CIDR و ابزار زیر استفاده کنید.
CIDRCIDR Calculatorرنج، broadcast و تعداد میزبان یک شبکه را حساب کنید و همپوشانی را بررسی کنید.ذخیرهسازی: volume، bind mount و tmpfs
سیستمفایل لایهی نوشتنی کانتینر با حذف آن از بین میرود. دادهی ماندگار باید جای دیگری باشد:
| نوع | مدیریت | مناسب برای | نکته |
|---|---|---|---|
| Named volume | Docker | دیتابیسها و دادهی برنامه | مستقل از مسیرهای میزبان؛ پشتیبانگیری با کانتینر کمکی |
| Bind mount | مسیر میزبان | کد و تنظیمات در توسعه | مراقب UID/GID و مجوز فایل باشید |
| tmpfs | حافظهی RAM | دادهی موقت و حساس | با خاموشی کانتینر از بین میرود |
services:
db:
image: postgres:16.4-alpine
volumes:
- pgdata:/var/lib/postgresql/data # named volume
app:
image: registry.example.com/app:1.8.2
volumes:
- ./config/app.yaml:/etc/app/app.yaml:ro # bind mount فقطخواندنی
tmpfs:
- /tmp
volumes:
pgdata:
پسوند :ro برای bind mountهای پیکربندی توصیه میشود تا برنامه نتواند فایل میزبان را تغییر دهد. اگر برنامه با کاربر غیر root اجرا میشود و روی bind mount نمینویسد، معمولاً مشکل از تفاوت UID/GID است: مالکیت پوشه را با chown به همان UID تغییر دهید.
پشتیبانگیری از دادهی کانتینرها
یک named volume را میتوان با یک کانتینر موقت به آرشیو تبدیل کرد:
# پشتیبان
docker run --rm -v pgdata:/data -v "$PWD":/backup alpine \
tar czf /backup/pgdata-$(date +%F).tgz -C /data .
# بازیابی در یک volume خالی
docker run --rm -v pgdata_restore:/data -v "$PWD":/backup alpine \
tar xzf /backup/pgdata-2026-10-25.tgz -C /data
pg_dump یا mysqldump) برای تهیهی نسخهی منطقی استفاده کنید. و پشتیبان را حتماً روی یک سرور دیگر ذخیره و بازیابی آن را دورهای تست کنید.عیبیابی شبکه و ذخیرهسازی
docker network ls
docker network inspect <network> # کانتینرها، IP و رنج شبکه
docker exec app getent hosts db # نام resolve میشود؟
docker exec app nc -zv db 5432 # پورت در دسترس است؟
docker volume ls
docker volume inspect pgdata # مسیر واقعی روی میزبان
- نام resolve نمیشود: کانتینرها در یک شبکهی سفارشی مشترک نیستند یا از شبکهی پیشفرض استفاده میکنند.
- اتصال برقرار نمیشود ولی نام resolve میشود: برنامه روی
127.0.0.1گوش میدهد، نه0.0.0.0؛ داخل کانتینر باید روی همهی اینترفیسها گوش بدهد. - داده بعد از ریاستارت رفته است: مسیر دادهی برنامه به volume متصل نشده یا با
docker compose down -vvolume حذف شده است.
جمعبندی و مطالعهی بعدی
برای شبکه، یک bridge سفارشی با نام سرویس، پورت منتشرشدهی حداقلی و رنج آدرس بدون همپوشانی کافی است؛ برای داده، named volume همراه با برنامهی پشتیبانگیری آزمایششده. ادامهی منطقی، امنسازی Docker و اشتباههای رایج docker-compose است.
پرسشهای متداول
چرا کانتینرها در شبکهی پیشفرض نمیتوانند با نام به هم برسند؟
docker0) DNS داخلی ندارد و فقط با IP کار میکند. در شبکهی bridge سفارشی (و شبکهای که Compose میسازد) Docker یک DNS داخلی دارد و کانتینرها با نام سرویس یا کانتینر یکدیگر را پیدا میکنند.فرق EXPOSE و -p چیست؟
EXPOSE فقط مستندسازی است و پورتی را منتشر نمیکند. برای دسترسی از میزبان یا بیرون باید با -p (یا ports در Compose) پورت را منتشر کنید؛ کانتینرهای همشبکه بدون انتشار هم به پورتهای یکدیگر دسترسی دارند.چرا قانون ufw پورت منتشرشدهی Docker را نمیبندد؟
127.0.0.1 منتشر کنید یا قانون را در زنجیرهی DOCKER-USER بنویسید.