«Контейнеры видят друг друга по имени? почему порт не проброшен? зачем macvlan?» — сети в Docker спотыкают почти каждого самохостера. Разберём встроенные сетевые драйверы по официальной документации и по делу: что выбрать под реверс-прокси, под Pi-hole, под стек мониторинга.
Встроенные драйверы
Docker Engine на Linux даёт несколько сетевых драйверов:
- bridge — драйвер по умолчанию для одиночных контейнеров на одном хосте. Контейнеры в одной bridge-сети общаются между собой, изолированы от других.
- host — убирает сетевую изоляцию: контейнер использует сетевой стек хоста напрямую. Быстро, но контейнер «слышит» все порты хоста; удобно для того, что должно видеть всю сеть (например, обнаружение устройств).
- none — полная изоляция: у контейнера нет сети вообще.
- overlay — соединяет несколько демонов Docker (Swarm) в одну сеть для меж-хостового общения.
- macvlan — контейнер получает собственный MAC и выглядит как отдельное устройство в вашей физической сети (свой IP из подсети LAN).
- ipvlan — похоже на macvlan, но без отдельных MAC; удобно, когда провайдер/коммутатор ограничивает число MAC, и для работы с VLAN.
Главная развилка: default bridge vs user-defined bridge
Это то, обо что спотыкаются чаще всего.
- В дефолтной bridge-сети (куда контейнер попадает, если вы не указали сеть) контейнеры не могут обращаться друг к другу по имени — только по IP. А IP выдаются динамически, так что это боль.
- В пользовательской bridge-сети (созданной вами) работает встроенный DNS Docker (адрес
127.0.0.11), и контейнеры резолвят друг друга по имени контейнера. Это то, что вам почти всегда нужно.
Практический вывод: всегда создавайте свою сеть, а не полагайтесь на дефолтную:
docker network create appnet
docker run -d --name db --network appnet postgres:16
docker run -d --name app --network appnet myapp # достучится до db как host "db"
В docker-compose это происходит автоматически: Compose заводит отдельную сеть для проекта, и сервисы видят друг друга по именам сервисов. Поэтому в compose вы пишете в конфиге приложения db:5432, а не IP.
Проброс портов
Порты контейнера в bridge-сети доступны с самого хоста, но чтобы сервис был виден снаружи хоста, порт нужно опубликовать флагом -p/--publish:
docker run -d -p 8080:80 nginx # хост:контейнер
Тонкость безопасности: -p 8080:80 слушает на всех интерфейсах. Если сервис должен быть доступен только локально (например, за реверс-прокси), привязывайте к loopback: -p 127.0.0.1:8080:80.
Что выбрать под типовые задачи
- Реверс-прокси (Nginx Proxy Manager, Caddy, Traefik) + сервисы: одна user-defined bridge-сеть, публикуете наружу только 80/443 у прокси, остальные сервисы держите без
-p— прокси ходит к ним по именам. - Pi-hole/AdGuard, которым нужен «настоящий» IP в LAN: macvlan — контейнер получает адрес вашей подсети и виден в сети как отдельное устройство.
- Мониторинг/сервис, которому нужен доступ ко всем портам хоста: host-сеть (осознанно, помня про потерю изоляции).
- Общий сетевой namespace двух контейнеров:
--network container:<имя>— второй контейнер делит интерфейс первого и общается через127.0.0.1(частый приём для «прицепить» sidecar/VPN-контейнер).
Трезвая оценка
- macvlan — не бесплатный обед. По умолчанию хост не может общаться со своими macvlan-контейнерами (изоляция родительского интерфейса); нужен отдельный macvlan-шлюз-трюк. Плюс не все Wi-Fi-адаптеры и облачные провайдеры это переваривают.
- host-сеть ломает изоляцию. Экономит на NAT, но контейнер получает доступ ко всему сетевому стеку хоста — используйте только там, где это осознанно нужно.
- Дефолтная сеть — источник половины «почему не резолвится». Если что-то не видит соседа по имени — почти всегда забыли создать свою сеть.
Что делать
- Возьмите за правило user-defined bridge для любого много-контейнерного стека (или просто используйте
docker-compose, где это из коробки). - Публикуйте наружу минимум — в идеале только 80/443 у реверс-прокси, всё остальное держите внутри сети и биндите на
127.0.0.1, если публикация всё же нужна. - macvlan — только когда реально нужен LAN-IP (Pi-hole/AdGuard, устройства умного дома), и заранее решите вопрос «хост↔контейнер».
- Проверяйте связность из контейнера:
docker exec -it app ping dbиgetent hosts db— сразу видно, работает ли встроенный DNS.
Источники
Как у вас организованы сети в докер-стеке — одна общая сеть, сегментация по проектам, macvlan для отдельных сервисов? И ловили ли «не резолвится по имени» на дефолтной сети?
