Vahid
Vahid
خواندن ۷ دقیقه·۳ سال پیش

شبکه در docker

مقدمه

در ادامه سری مطالب داکر قرار بود که شبکه‌ی داکر رو هم مورد بررسی قرار بدیم. فهمیدن نحوه کار شبکه‌ی داکر به ما کمک می‌کنه تا بدونیم که حامل‌ها(container) چطور با هم ارتباط می‌گیرند. تو این مطلب سعی می‌کنیم این موضوع رو بررسی و نحوه کار اون رو بفهمیم.

اگر مطالب قبلی رو نخوندین، بد نیست یک نگاهی به اون‌ها هم بندازید(البته پیش نیاز این مطلب نیستند).

https://vrgl.ir/n3zr0
https://vrgl.ir/srZqV

به طور کلی داکر ۵ نوع(یا به تفسیر دیگه ۶ نوع) شبکه رو می‌تونه داشته باشد، که عبارت‌اند از:

  • bridge(پیشفرض)
  • host
  • overlay
  • macvlan
  • none
  • Plugin(اون به عبارتی که گفتم این مورده)

اینکه هر کدوم از این موارد کی استفاده ‌می‌شوند و چه کاربردی دارند، موضوعیه که تو ادامه با هم بررسی می‌کنیم.

Bridge

اگر با تکنولوژی‌های مجازی‌ساز(vmware, kvm, ...) کار کرده باشید، باید بهتون بگم شبکه داکر تو حالت bridge با مجازی‌سازها متفاوته! ما تو مجازی‌سازها وقتی از bridge استفاده می‌کنیم، یک IP در رنج همون IP ماشین میزبان(Host) بهمون داده میشه(شاید یک تکنولوژی وجود داشته باشه که این‌طوری نباشه، اولا اینکه موارد معروف رو مدنظرم بود و دوما اینکه سواد من در این حده :) ). به عنوان مثال اگر ماشین میزبان ما تو رنج 172.19.0.0/16 باشه، ماشین مجازی(vm) ما هم تو همون رنج یک ‌IP رو می‌گیره و تو شبکه هم قابل دسترسیه، در واقع مستقیم از interface شبکه‌مون استفاده می‌کنه. اما داکر این طوری نیست! داکر میاد یک شبکه با رنجی که خودش مشخص می‌کنه، می‌سازه و حامل‌های مارو تو اون رنج IPدهی می‌کنه. دلیل این تفاوت هم تو اینه که داکر، برای ساخت bridge از software device استفاده می‌کنه. این مورد باعث ایزوله سازی این شبکه میشه. برای اینکه لیست شبکه‌های داکر رو ببینیم کافیه دستور زیر رو اجرا کنیم:

docker network ls

که خروجی اون یک همچین چیزی میشه:

خروجی دستور بالا
خروجی دستور بالا

داکر این سه مورد به صورت پیشفرض خودش می‌سازه.

حالا اگر بخوایم دامنه IPهای خودمون رو بدونیم کافیه دستور زیر رو اجرا کنیم:

docker network inspect <ID_OF_NETWORD___OR___NAME_OF_NETWORK>

توی خروجی این دستور تو بخش IPAM و داخل اون بخش Config می‌تونیم دامنه رو ببینیم:

بخشی از خروجی دستور بالا
بخشی از خروجی دستور بالا

اما bridge کی استفاده میشه؟ طبق گفته خود داکر اکثر مواقعی چندتا حامل standalone داریم و این‌ حامل‌ها با هم دیگه ارتباط دارند از bridge استفاده می‌کنیم. مثلا docker-compse یک مثال بسیار خوب برای این مورده. میایم یک شبکه برای اون چندتا حاملی که می‌خوایم با docker-compose بیاریم بالا می‌سازیم(حتی می‌تونیم شبکه جدا نسازیم) و این حامل‌ها می‌تونند با اسم با هم‌دیگه در ارتباط باشند.

نکته خوب ماجرا اینکه ما می‌تونیم شبکه bridge خودمون رو بسازیم(حتی با دامنه مدنظر خودمون). چرا این خوبه؟ فرض کنید که چند دسته حامل داریم(هر کدوم متعلق به یک سرویس) و نمی‌خوایم این دسته‌ها بتونند با هم دیگه ارتباط داشته باشند. داکر به حامل‌هایی که تو یک شبکه نباشند& اجازه ارتباط با همدیگه رو نمیده.

برای اینکه موضوع شفاف‌تر بشه. بیاین یک شبکه bridge رو بسازیم:

docker network create <NAME_OF_NETWORK>

نکته: از اونجایی که دایور پیشفرض داکر bridge هستش، دیگه نگفتیم که bridge می‌خوایم. دامنه IP رو هم می‌تونستیم مشخص کنیم و ... . برای اینکه بدونیم دستور create چه گزینه‌هایی داره از این دستور استفاده می‌کنیم:

docker network create --help
ساخت یک شبکه bridge
ساخت یک شبکه bridge


حالا اگر بخوایم که یک حامل توی این شبکه باشه کافیه:

docker create --network vahid -p 8080:80 --name my-container nginx:latest

اگر هم یک حامل در حال اجرا داریم می‌تونیم به این شکل عمل کنیم:

docker network connect vahid my_container

قطع ارتباط(disconnect) هم داریم:

docker network disconnect vahid my_container

تفاوت شبکه ایجاد شده توسط کاربر

گفتیم که به صورت پیشفرض داکر یک شبکه bridge رو اول کار میسازه که این شبکه با شبکه bridge که ما بعدا می‌سازیم، تفاوت‌هایی داره. این تفاوت‌ها عبارت‌اند از:

  • امکان وصل شدن و یا قطع ارتباط در لحظه(on the fly) به شبکه غیرپیشفرض

همون طور که مثالش رو بالا داشتیم، خیلی راحت می‌تونیم به یک شبکه که خودمون ساختیم، وصل و یا از اون قطع بشیم. در حالی که در شبکه پیشفرض برای خارج شدن، نیازه تا حامل stop بشه.

  • به اشتراک گذاشتن env variables

شبکه پیشفرض امکان به اشتراک گذاری این مقادیر بین دوتا حامل رو به ما میده(استفاده از فلگ --link)، در حالی که برای شبکه‌هایی که خودمون ساختیم این طوری نیست. هرچند که میشه برای این موضوع روش‌های بهتری نسبت به --link رو استفاده کرد.

  • امکان تعریف دامنه
    دامنه IP که به ما اختصاص داده میشه توی شبکه پیشفرض دست ما نیست و خود داکر مشخص می‌کنه در حالی که می‌تونیم یک شبکه بسازیم و دامنه IP مدنظر خودمون رو بهش اختصاص بدیم. البته این مورد رو هم میشه با فایل daemon.json حل کرد. برای این کار:
$ sudo vim /etc/docker/daemon.json

بعد محتویات زیر رو میزاریم(طبیعتا اگر تنظیمات دیگه‌ای هم داشته باشیم، این موارد میان بغل اونا):

{ &quotbip&quot: &quot192.168.1.5/24&quot, &quotfixed-cidr&quot: &quot192.168.1.5/25&quot, &quotfixed-cidr-v6&quot: &quot2001:db8::/64&quot, &quotmtu&quot: 1500, &quotdefault-gateway&quot: &quot10.20.1.1&quot, &quotdefault-gateway-v6&quot: &quot2001:db8:abcd::89&quot, &quotdns&quot: [&quot10.20.1.2&quot,&quot10.20.1.3&quot] }

در نهایت سرویس داکر رو ریستارت کنید.

یک نکته دیگه هم اینکه داکر میگه شبکه غیرپیشفرض(شبکه‌ای که کاربر می‌سازه) باعث ایزوله سازی بهتری میشه.چطور؟ اگر برای یک حامل شبکه رو مشخص نکنیم، از شبکه پیشفرض استفاده خواهد کرد. این موضوع می‌تونه باعث بشه، حامل‌هایی که نمی‌خوایم همدیگه رو ببینند، این امکان رو داشته باشند. پس روش مهندسی‌تر اینکه شبکه خودمون رو بسازیم و حامل رو موقع ساخت با اون شبکه بیاریم بالا تا دسترسی ناخواسته بهش وجود نداشته باشه.
https://memegenerator.net/img/instances/81395542/users-cant-submit-jira-tickets-if-the-network-is-down.jpg
https://memegenerator.net/img/instances/81395542/users-cant-submit-jira-tickets-if-the-network-is-down.jpg

Host

تو این مورد خیلی ساده ایزوله‌سازی‌ای وجود نداره و حامل مستقیم از به طور مستقیم از شبکه ماشین میزبان استفاده می‌کنه. در واقع حامل از خودش IP نداره و فلگ --publish یا -p هم درنظر گرفته نمیشه. مثلا یک حامل nginx داشته باشیم که شبکه ش از نوع Host باشه تنها کافیه آدرس اون ماشین رو در شبکه بزنیم تا درخواست برسه به دست حامل ما.

این نوع شبکه در ماشین‌های میزبان با سیستم‌عامل مک و ویندوز کار نمی‌کند.

شبکه Host برای مواقعی بخوایم یک طیف وسیعی از درگاه‌ها(port) رو داشته باشه ایده‌ی خوبیه(از لحاظ پرفورمنسی).

Overlay

این نوع شبکه چیز باحالیه! ما می‌تونیم به کمک overlay چندتا docker daemon رو بهم دیگه وصل کنیم. این شبکه باعث میشه بتونیم دو حامل داشته باشیم که توی دوتا docker daemon جدا با همدیگه ارتباط داشته باشند یا سرویس‌های swarm بتونند با هم حرف بزنند یا یک حامل با swarm حرف بزنه. حتی این ارتباط میتونه به کمک رمزنگاری امن هم بشه.

با یک مثال موضوع رو ادامه بدیم. یک شبکه از نوع overlay می‌سازیم:

docker network create -d overlay vahid

البته فلگ‌های --encrypted و --attachable هم زیاد استفاده می‌شوند. یکی برای فعال‌سازی رمز نگاری ارتباطات و یکی هم برای امکان ارتباط یک حامل با سرویس swarm.

اگر بخوایم یک عکس کلی از این شبکه داشته باشیم، این رو خواهیم داشت:

https://medium.com/@tukai.anirban/container-networking-overlay-networks-b712d6ddfb67
https://medium.com/@tukai.anirban/container-networking-overlay-networks-b712d6ddfb67

اینکه این شبکه چطوری کار میکنه، بحث مسیریابی(routing) چطوریه و کلا جنبه‌های مختلف اون، علاوه بر اینکه برای توضیحش سواد فنی خوبی می‌خواد(که من ندارمش)، باعث طولانی‌تر شدن مطلب میشه(مطلب طولانی مخاطب رو پس می‌زنه). ولی به واقع ارزش خوندن و فهمیدنش رو داره، مخصوصا اگر با swarm کار می‌کنید. طبیعتا گوگل بهترین گزینه ممکن هستش ولی منم دوتا لینک میزارم.

لینک ۱(مستندات خود داکر درباره شبکه overlay) و لینک ۲. اگر کسی لینک خوبی سراغ داشت لطفا به اشتراک بزاره. :)

macvlan

تو این مورد، ما به حامل‌های خودمون یک MAC Address رو اختصاص می‌دیم که باعث میشه حامل توی شبکه به عنوان یک دستگاه شناخته بشه. سرویس داکر هم عملیات مسیریابی(routing) رو بر اساس مک آدرس انجام میده. به گفته خود داکر این نوع شبکه، گاها می‌تونه به عنوان بهترین انتخاب برای نرم‌افزارهای قدیمی که انتظار دارند، مستقیم به شبکه فیزیکی(physical network) وصل شوند، باشد.

نکته اینکه برای این شبکه، تجهیزات شبکه ما باید توانایی تخصیص چندین مک آدرس رو داشته باشد(اصطلاحا بهش promiscuous mode میگن).

نکته دوم هم اینکه این مورد می‌تونه باعث مشکلاتی(VLAN spread, ip exhaustion) توی شبکه‌هایی بشه که تعداد زیادی مک آدرس یکتا(unique) تو خودشون دارند.

باز هم به خاطر اینکه مطلب طولانی نشه توضیح بیشتری نمیدم و شما رو به این لینک(از مستندات خود داکر) ارجاع میدم. توصیه می‌کنم یک نگاهی بندازین چیزای جالبی دارد.

none

بحث شبکه رو برای حامل‌مون کلا غیرفعال می‌کنه(تامام).

برای اینکه این مورد رو فعال کنیم این طوری می‌تونیم عمل کنیم:

docker run --network none --name my-container nginx:latest

Plugin

می‌تونیم یک افزونه(plugin) third-party رو نصب و استفاده کنیم. برای دیدن نمونه هم می‌تونین که اینجا(داکر هاب) رو یک نگاه بندازید. شاید برای جاهایی که شبکه‌شون رو به صورت خاصی پیاده‌سازی کردند، استفاده بشه.

جمع‌بندی

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

  • User-defined bridge networks are best when you need multiple containers to communicate on the same Docker host.
  • Host networks are best when the network stack should not be isolated from the Docker host, but you want other aspects of the container to be isolated.
  • Overlay networks are best when you need containers running on different Docker hosts to communicate, or when multiple applications work together using swarm services.
  • Macvlan networks are best when you are migrating from a VM setup or need your containers to look like physical hosts on your network, each with a unique MAC address.
  • Third-party network plugins allow you to integrate Docker with specialized network stacks.

میدونم که خیلی سریع و سطحی گفته شد، سوای بحث اینکه مطلب خیلی طولانی میشد(همین مطلب ۸ دقیقه اینا شد!)، توضیح در همین حد هم، کار خیلی‌ها(اون‌هایی که کار زیرساختی انجام نمیدن) رو راه میندازه!

همین! لبخند بزنین لطفا :)

منابع:

  • https://docs.docker.com/network/
داکرdevopsdockerdocker networkbridge
یه وحید از نوع برنامه نویسش :)
شاید از این پست‌ها خوشتان بیاید