شبکه در Docker و ارتباط کانتینرها

ارتباط کانتینرها در لینوکس چگونه کار می‌کند؟

در هفته‌ی سوم با مفاهیم شبکه‌های کامپیوتری، سوئیچ‌ها، پورت‌ها و روتینگ آشنا شدید. داکر تمام این مفاهیم را به‌صورت مجازی درون هسته‌ی لینوکس پیاده‌سازی می‌کند:

 1       Host Network (eth0: 192.168.1.50)
 2                      ▲
 3                      │ (NAT / iptables)
 4             [ Bridge: docker0 ] (172.17.0.1)
 5               │             │
 6        (veth) │             │ (veth)
 7               ▼             ▼
 8        ┌─────────────┐  ┌─────────────┐
 9        │ Container A │  │ Container B │
10        │ 172.17.0.2  │  │ 172.17.0.3  │
11        └─────────────┘  └─────────────┘

هنگامی که داکر نصب می‌شود، یک کارت شبکه‌ی مجازی از نوع پل به نام docker0 در لینوکس می‌سازد. هر کانتینری که روشن می‌شود، یک جفت رابط شبکه‌ی مجازی (veth pair) دریافت می‌کند: یک سرِ کابل به سوئیچ مجازی داکر متصل می‌شود و سر دیگر به داخل فضای نام شبکه‌ی کانتینر می‌رود.


درایورهای شبکه‌ی پیش‌فرض داکر (Network Drivers)

داکر چند درایور شبکه‌ی پیشفرض دارد:

  • bridge (پل ارتباطی): درایور پیش‌فرض. کانتینرها در یک شبکه‌ی خصوصی و مجازی قرار می‌گیرند و برای دسترسی از بیرون باید پورت‌های آن‌ها expose شود (-p).
  • host: ایزولاسیون شبکه حذف می‌شود و کانتینر مستقیماً از کارت شبکه و پورت‌های سرور اصلی استفاده می‌کند (پورت ۸۰ کانتینر مستقیماً روی پورت ۸۰ هاست باز می‌شود). بسیار سریع است اما ایزولاسیون امنیتی را کاهش می‌دهد.
  • none: کانتینر هیچ کارت شبکه‌ای جز Loopback (127.0.0.1) ندارد؛ برای پردازش‌های کاملاً آفلاین و ایزوله.
  • overlay: برای شبکه‌سازی بین چندین سرور مجزا در کلاسترهای Docker Swarm یا ابزارهای توزیع‌شده.

تفاوت حیاتی: پل پیش‌فرض در برابر User-defined Bridge

یکی از اشتباهات رایج افراد تازه‌کار در داکر این است که کانتینرها را در شبکه‌ی پیش‌فرض اجرا می‌کنند و انتظار دارند کانتینرها با اسم یکدیگر را پیدا کنند!

ویژگیDefault Bridge (bridge)User-defined Bridge (شبکه‌ی دستی)
DNS خودکار و Service Discovery❌ ندارد (فقط بر اساس IP)✅ دارد (شناسایی با نام کانتینر)
ایزولاسیون امنیتیضعیف (همه‌ی کانتینرها پیش‌فرض در آن هستند)عالی (فقط سرویس‌های مرتبط متصل می‌شوند)
اتصال زنده (Hot Connect)نیاز به توقف کانتینر دارددر حین اجرا قابل اتصال و قطع است

در User-defined Bridge، داکر یک سرور DNS داخلی روی آدرس 127.0.0.11 فعال می‌کند. به همین دلیل کانتینرها می‌توانند بدون دانستن آدرس IP متغیر یکدیگر، فقط با تایپ کردن نام کانتینر دیگر به آن متصل شوند.


دستورهای مدیریت شبکه

 1# ایجاد یک شبکه‌ی سفارشی از نوع bridge
 2docker network create my-net
 3
 4# لیست تمام شبکه‌های موجود
 5docker network ls
 6
 7# دیدن جزئیات شبکه، ساب‌نت و کانتینرهای متصل به آن
 8docker network inspect my-net
 9
10# اتصال یک کانتینر در حال اجرا به شبکه‌ای دیگر
11docker network connect my-net container_name
12
13# قطع اتصال کانتینر از شبکه
14docker network disconnect my-net container_name
15
16# حذف شبکه
17docker network rm my-net

آزمایش عملی: کشف سرویس (Service Discovery) با DNS داکر

بیایید دو کانتینر بسازیم و ارتباط آن‌ها را از طریق نامشان آزمایش کنیم:

گام ۱: ساخت یک شبکه‌ی اختصاصی

1docker network create internal-net

گام ۲: اجرای وب‌سرور Nginx روی این شبکه با نام api-service

1docker run -d \
2  --name api-service \
3  --network internal-net \
4  nginx:alpine

دقت کنید که ما هیچ پورتی را با -p روی هاست باز نکردیم! این کانتینر فقط درون شبکه‌ی internal-net در دسترس است.

گام ۳: اجرای کانتینر دوم و فراخوانی وب‌سرور با استفاده از نام آن

1docker run --rm -it \
2  --network internal-net \
3  curlimages/curl:latest http://api-service

خروجی صفحه‌ی خوش‌آمدگویی Nginx را مشاهده خواهید کرد:

1<!DOCTYPE html>
2<html>
3<head>
4<title>Welcome to nginx!</title>
5...

داکر نام http://api-service را به صورت خودکار و از طریق DNS داخلی به آدرس IP کانتینر ترجمه کرد. این دقیقاً همان روشی است که وب‌سایت‌ها با دیتابیس‌ها و میکروسرویس‌ها با یکدیگر بدون هاردکد کردن IP صحبت می‌کنند.


انتشار پورت‌ها (Port Publishing)

برای اینکه کاربران خارج از سرور بتوانند به سرویس داخل کانتینر متصل شوند، باید پورت را نگاشت (Publish) کنید:

1docker run -d -p 8080:80 --name web nginx:alpine

این دستور به هسته‌ی لینوکس (از طریق قوانین iptables NAT) دستور می‌دهد هر بسته‌ای که به پورت 8080 سرور اصلی آمد را مستقیماً به پورت 80 درون کانتینر فوروارد کند.

اگر می‌خواهید پورت فقط برای درخواست‌های درون خود هاست در دسترس باشد (و از اینترنت عمومی دیده نشود):

1docker run -d -p 127.0.0.1:8080:80 --name secure-web nginx:alpine

ابزارهای اشکال‌زدایی شبکه‌ی کانتینرها

اگر دو کانتینر نتوانستند با هم ارتباط برقرار کنند:

  1. بررسی اتصال به یک شبکه‌ی مشترک:
    1docker network inspect <network_name>
  2. تست ارتباط و پینگ از درون کانتینر:
    1docker exec -it <container> ping <other_container_name>
  3. تست پورت با ابزار netcat یا curl:
    1docker exec -it <container> nc -zv <other_container_name> 80

منابع یادگیری

ویدیو

مستندات و مقالات