DOCKER

شبکه و Volume در Docker: درایورها، انتشار پورت و ذخیره‌سازی ماندگار

تفاوت درایورهای bridge، host و overlay، DNS داخلی Docker، انتشار پورت، named volume در برابر bind mount و پشتیبان‌گیری از داده‌ی کانتینرها.

کانتینر بدون شبکه و ذخیره‌سازی درست، یا از بقیه‌ی سرویس‌ها جداست یا داده‌اش با اولین حذف کانتینر از بین می‌رود. این راهنما دو موضوع را کنار هم توضیح می‌دهد: چگونه کانتینرها به هم و به بیرون وصل می‌شوند (درایورهای شبکه، 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>                     # نمایش پورت‌های منتشرشده
warn Docker قوانین iptables خودش را پیش از ufw اعمال می‌کند، پس 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 volumeDockerدیتابیس‌ها و داده‌ی برنامهمستقل از مسیرهای میزبان؛ پشتیبان‌گیری با کانتینر کمکی
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
note کپی فایل‌های یک دیتابیس در حال اجرا ممکن است داده‌ی ناسازگار بدهد. برای دیتابیس‌ها یا کانتینر را موقتاً متوقف کنید یا از ابزار خود دیتابیس (مثل 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 -v volume حذف شده است.

جمع‌بندی و مطالعه‌ی بعدی

برای شبکه، یک bridge سفارشی با نام سرویس، پورت منتشرشده‌ی حداقلی و رنج آدرس بدون همپوشانی کافی است؛ برای داده، named volume همراه با برنامه‌ی پشتیبان‌گیری آزمایش‌شده. ادامه‌ی منطقی، امن‌سازی Docker و اشتباه‌های رایج docker-compose است.

پرسش‌های متداول

چرا کانتینرها در شبکه‌ی پیش‌فرض نمی‌توانند با نام به هم برسند؟
شبکه‌ی bridge پیش‌فرض (docker0) DNS داخلی ندارد و فقط با IP کار می‌کند. در شبکه‌ی bridge سفارشی (و شبکه‌ای که Compose می‌سازد) Docker یک DNS داخلی دارد و کانتینرها با نام سرویس یا کانتینر یکدیگر را پیدا می‌کنند.
فرق EXPOSE و -p چیست؟
EXPOSE فقط مستندسازی است و پورتی را منتشر نمی‌کند. برای دسترسی از میزبان یا بیرون باید با -p (یا ports در Compose) پورت را منتشر کنید؛ کانتینرهای هم‌شبکه بدون انتشار هم به پورت‌های یکدیگر دسترسی دارند.
چرا قانون ufw پورت منتشرشده‌ی Docker را نمی‌بندد؟
Docker قوانین iptables خودش را اضافه می‌کند که پیش از قوانین ufw ارزیابی می‌شوند. برای محدودکردن دسترسی، پورت را فقط روی 127.0.0.1 منتشر کنید یا قانون را در زنجیره‌ی DOCKER-USER بنویسید.
برای دیتابیس named volume بهتر است یا bind mount؟
در اغلب موارد named volume: مدیریت آن با Docker است، مشکل مجوز فایل کمتری دارد و روی همه‌ی سیستم‌عامل‌ها یکسان رفتار می‌کند. bind mount را برای کد و فایل‌های پیکربندی در توسعه یا وقتی به مسیر مشخص روی میزبان نیاز دارید نگه دارید.