HomeLab.net.ua

Твоє залізо. Твої правила. Твоя мова.

Docker macvlan vs bridge у homelab: коли контейнеру справді потрібна окрема IP-адреса

Опубліковано Оновлено

docker macvlan

Docker macvlan і bridge вирішують різні задачі. Якщо контейнеру потрібна пряма присутність у LAN, окрема IP-адреса й власний MAC – беруть macvlan. Якщо достатньо доступу через порти хоста, краще лишатися на bridge. Нижче – де межа між цими підходами, де вони ламаються і як не ускладнити собі мережу без причини.

У homelab помилка тут типова: macvlan вмикають тільки тому, що так “гарніше” виглядає в DHCP-списку або хочеться бачити контейнер як окремий хост. На практиці це майже завжди зайве. Окрема IP потрібна не контейнеру як такому, а сервісу, який погано живе за NAT, port mapping або reverse proxy.

Нормальна відправна точка проста. Починати з bridge, а до macvlan переходити лише тоді, коли є конкретна мережева причина: broadcast discovery, жорстка прив’язка до порту 53 або 67, вимога бачити клієнта напряму на рівні LAN, або конфлікт однакових портів між кількома сервісами.

Коли вибирати bridge, а коли docker macvlan

Bridge – базовий режим Docker. Контейнер сидить у внутрішній мережі Docker, а назовні публікуються тільки потрібні порти. Docker macvlan підключає контейнер прямо до фізичної мережі, ніби це окремий вузол на комутаторі.

Критерій bridge macvlan
IP-адреса в LAN Ні, контейнер ховається за IP хоста Так, окрема IP для контейнера
Доступ через port mapping Так Зазвичай не потрібен
Broadcast і multicast у LAN Часто незручно або з обмеженнями Працює природніше
Видимість контейнера як окремого хоста Ні Так
Складність підтримки Низька Вища
Типові проблеми Порти, NAT, hairpin Зв’язок host ↔ container, VLAN, DHCP-конфлікти

Для більшості self-hosted сервісів bridge достатньо. Web-додатки, dashboards, Git-сервіси, reverse proxy, metrics stack, внутрішні API – усе це нормально працює через bridge і published ports.

Docker macvlan виправданий там, де сервіс повинен поводитися як окремий пристрій у мережі. Типові приклади – DNS-сервер на 53 порту, мережевий сервіс із discovery через broadcast, legacy-додаток із жорстко заданими адресами або контейнер, який має бути доступний без участі хоста як NAT-шлюзу.

Нетривіальна межа така: якщо причина переходу до docker macvlan лише в тому, що “не хочеться пам’ятати порти”, це слабкий аргумент. Проблема тут не в bridge, а в відсутності нормального DNS або reverse proxy.

Коли контейнеру справді потрібна окрема IP-адреса

Окрема IP-адреса потрібна нечасто. Вона має сенс, коли сервіс прив’язаний до стандартного мережевого порту, коли потрібно уникнути NAT, або коли інші вузли в LAN повинні бачити контейнер напряму як повноцінний endpoint.

Найчастіші сценарії такі:

  • потрібен DNS на 53 порту, а хост уже використовує цей порт або не має його торкатися;
  • контейнер слухає DHCP-подібний сервіс, де проста публікація портів не закриває весь сценарій;
  • сервіс використовує broadcast або multicast для пошуку клієнтів;
  • треба підняти кілька контейнерів з однаковими службовими портами без гри в нестандартні порти на хості;
  • мережеві ACL, firewall або інвентаризація очікують окремий IP, а не спільний IP хоста.

У решті випадків окрема адреса тільки додає клопоту. З’являється ще один вузол у DHCP, окремі правила в firewall, окремий запис у DNS, більше шансів на плутанину з маршрутами. Для одного Pi-hole або AdGuard Home це ще терпимо. Для десятка контейнерів мережа швидко втрачає читабельність.

Особливо це помітно в невеликих homelab-сегментах, де IP-план і так щільний. Кожен додатковий macvlan-контейнер виглядає як маленький VM, але керується як контейнер. Найгірше з обох світів, якщо вибір був без реальної потреби.

Що міняє docker macvlan в мережевій схемі

У режимі docker macvlan контейнер отримує власну мережеву ідентичність у фізичному сегменті. Для комутатора і сусідніх хостів він виглядає окремим пристроєм. Docker bridge, навпаки, лишає контейнер усередині програмної мережі, а трафік назовні йде через стек хоста.

Різниця не тільки в IP. У bridge зручно керувати доступом через published ports, reverse proxy і внутрішні мережі Docker. У macvlan контейнер вилазить у LAN майже без посередників. Це спрощує деякі мережеві сервіси, але ламає звичну модель ізольованого контейнера.

На практиці головна пастка така: host і macvlan-контейнер часто не бачать один одного напряму, хоча обидва сидять в одній підмережі. Для новачка це виглядає абсурдно, але це типова поведінка схеми. Через це ламаються локальні health-check, моніторинг із хоста, резервне копіювання через localhost-подібні маршрути і просто звичка тестувати сервіс з того ж сервера.

Через це docker macvlan не варто вмикати для звичайних web-сервісів. Якщо reverse proxy, Prometheus або backup-агент працюють на тому ж хості, bridge дає передбачуваніший трафік і менше сюрпризів.

Як підняти macvlan без зайвого хаосу

Налаштування docker macvlan краще робити через окремий пул адрес поза DHCP-діапазоном. Інакше конфлікт адрес рано чи пізно трапиться. Базова схема – створити мережу macvlan, прив’язати її до фізичного інтерфейсу і видати контейнеру статичну адресу.

  1. Переконатися, що вибраний інтерфейс підключений до потрібного LAN або VLAN.
  2. Виділити підмережу чи частину діапазону, яку не роздає DHCP.
  3. Створити мережу macvlan у Docker.
  4. Запустити контейнер із фіксованою IP-адресою.
docker network create -d macvlan 
  --subnet=192.168.1.0/24 
  --gateway=192.168.1.1 
  -o parent=eth0 
  macvlan_lan

docker run -d 
  --name pihole 
  --network macvlan_lan 
  --ip 192.168.1.53 
  pihole/pihole:latest

Якщо потрібен зв’язок між хостом і контейнером, на хості зазвичай створюють додатковий macvlan-інтерфейс і окремий маршрут до цього сегмента.

ip link add macvlan-host link eth0 type macvlan mode bridge
ip addr add 192.168.1.254/32 dev macvlan-host
ip link set macvlan-host up
ip route add 192.168.1.53/32 dev macvlan-host

Схема робоча, але вже видно ціну. З bridge таких обхідних маневрів не потрібно.

Деталі мереж Docker описані в офіційній документації Docker Engine networking.

Bridge у homelab зазвичай виграє

Bridge варто вважати стандартом, а не компромісом. Для більшості homelab-сервісів він дає простішу модель: один IP хоста, явні published ports, внутрішня взаємодія контейнерів через Docker network, менше сюрпризів у firewall і маршрутах.

Якщо сервіс зовнішній, його часто простіше прокинути через reverse proxy на хості або в окремому контейнері. Якщо сервіс внутрішній, published port або внутрішня мережа Docker закривають задачу без окремої IP. Так легше переносити стек між хостами, робити резервні копії конфігів і не думати, які адреси вже зайняті в LAN.

Є ще один практичний нюанс. Коли контейнерів стає багато, bridge краще масштабується в операційному сенсі. Не тому, що трафік “швидший”, а тому, що схема простіша для голови: менше IP, менше записів у DNS, менше ручних винятків у мережевих правилах.

Для сервісів на кшталт Nginx Proxy Manager, Traefik, Grafana, Gitea, Home Assistant у звичайному режимі, Immich, Jellyfin, Vaultwarden окрема LAN-адреса рідко дає реальну користь. Зате додає ще одну площину відлагодження.

Де docker macvlan найчастіше створює проблеми

Docker macvlan працює добре, поки схема проста і зрозуміла. Проблеми починаються на стику з хостом, VLAN, свічем і локальними сервісами самого сервера. Саме там більшість дивних багів і з’являється.

Host не може достукатися до контейнера

Найтиповіша ситуація. Контейнер доступний з інших машин у LAN, але не з самого Docker-хоста. Для моніторингу, backup jobs або локального reverse proxy це ламає половину сценаріїв. Доводиться створювати окремий macvlan-інтерфейс на хості або відмовлятися від схеми.

DHCP-конфлікти і випадкові дублікати IP

Якщо адреси для docker macvlan не винесені поза DHCP pool, конфлікти неминучі. Спершу все працює. Потім роутер видає ту саму IP іншому вузлу, і починається хаос, який складно відстежити.

Комутатор або hypervisor не любить зайві MAC-адреси

У віртуалізованому homelab середовищі це трапляється регулярно. Якщо Docker-хост живе всередині VM, а зверху ще є vSwitch, bridge group або портова безпека, додаткові MAC від macvlan можуть блокуватися. Формально контейнер піднявся, але трафіку немає.

Занадто багато “маленьких окремих хостів”

До 2-3 контейнерів схема ще читається. Після цього docker macvlan починає розмножувати сутності: IP, DNS-записи, ACL, статичні lease, моніторинг. Для одного DNS-сервера це нормально. Для цілого self-hosted стека вже сумнівно.

Як перевірити, що мережа працює правильно

Після налаштування треба перевірити три речі: контейнер бачиться в LAN, потрібний сервіс слухає на очікуваному IP, а маршрути між хостом і контейнером поводяться так, як задумано. Без цього docker macvlan виглядає “майже робочим”, хоча половина сценаріїв уже зламана.

  1. Подивитися параметри мережі Docker.
  2. Переконатися, що контейнер отримав правильну IP.
  3. Перевірити доступ із іншого вузла в тій самій підмережі.
  4. Окремо перевірити доступ саме з Docker-хоста.
  5. Звірити ARP і маршрути, якщо є дивна асиметрія.
docker network inspect macvlan_lan

docker inspect pihole

ping 192.168.1.53
curl http://192.168.1.53

Якщо з LAN усе відкривається, а з хоста ні – проблема майже точно в типових обмеженнях macvlan, а не в самому контейнері. Іноді це сигнал, що для конкретного сервісу bridge був би кращим вибором.

Що ставити в homelab без зайвого героїзму

Для більшості сценаріїв вибір простий: bridge за замовчуванням, docker macvlan тільки під конкретну мережеву вимогу. Якщо сервіс нормально живе за reverse proxy або published ports, окрема IP-адреса йому не потрібна.

Macvlan має сенс для DNS, discovery-сервісів, нестандартних legacy-штук і випадків, де контейнер повинен виглядати окремим вузлом у LAN. Усе інше краще лишати на bridge. Менше магії, менше ручної маршрутизації, менше шансів зламати собі моніторинг через надто “чисту” мережеву схему.