Learning Platform
Глоссарий Troubleshooting
Урок 11.01 · 22 мин
Начальный
dockernetworkingbridgehostoverlay

Network drivers: bridge, host, none, overlay, macvlan

Контейнер по умолчанию изолирован — у него собственный network namespace, своя petля lo, своя таблица маршрутов. Чтобы он получил сеть, Docker подключает его к одному из network drivers. В Docker Engine 28 их пять стандартных: bridge, host, none, overlay, macvlan. Каждый — про разные компромиссы между изоляцией, скоростью и видимостью в LAN.


Список и быстрый обзор

docker network ls
# NETWORK ID     NAME      DRIVER    SCOPE
# 7a8b9c4d2e1f   bridge    bridge    local
# 2d4e8f1a0b3c   host      host      local
# 1c2d3e4f5a6b   none      null      local

Три сети существуют сразу после установки Docker:

  • bridge — default network, куда попадает любой контейнер без явного --network.
  • host — особая сеть «нет изоляции, использовать host network stack».
  • none — нет сети вообще, только loopback.

Можно создавать свои:

docker network create my-bridge          # ещё один bridge, но user-defined
docker network create --driver overlay swarm-net  # требует swarm mode
docker network create --driver macvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o parent=eth0 \
  lan-net

Свитчи vs хабы — как кадр находит правильный порт

Bridge (default)

Самый частый driver. Технически — Linux bridge (docker0 для default-сети), к которому подключены veth-интерфейсы каждого контейнера. Из контейнера трафик идёт через eth0 -> vethXXX -> docker0 -> хост -> NAT -> внешний мир.

docker run --rm -it alpine sh
# Внутри:
ip addr show eth0
# inet 172.17.0.2/16 — типичный subnet для docker0
ip route
# default via 172.17.0.1 — это docker0
Bridge network: путь пакета от контейнера
Container eth0Внутри контейнера — собственный network namespace. eth0 в нём — это одна сторона veth-пары
vethXXX (host side)Парный интерфейс на стороне хоста. Каждому контейнеру — свой veth. Видно через ip link на хосте
docker0 bridgeLinux bridge на хосте, default name docker0. Все default-bridge контейнеры подключены сюда. У моста есть IP 172.17.0.1 — это default gateway для контейнеров
iptables MASQUERADENAT-правило: пакеты из 172.17.0.0/16, идущие на внешний интерфейс, маскируются под IP хоста. Поэтому контейнер виден в интернете как хост

Между контейнерами в default bridge нет DNS-резолва по имени. Только по IP, который Docker не гарантирует (контейнер пересоздался — IP может смениться). Поэтому правило:

WARNING

Для любых realных сценариев не используй default bridge. Создай user-defined bridge: docker network create mynet. На нём работает DNS by container name, и это меняет всё.


Host

Контейнер использует network stack хоста — никакого namespace, никаких veth. То же, что запустить процесс прямо на хосте.

docker run --rm --network host nginx:1.27-alpine
# nginx слушает 0.0.0.0:80 — но на хосте напрямую, без -p mapping.
# Если порт 80 на хосте занят — fail сразу.

Никакой публикации портов через -p — Docker её игнорирует. Контейнер сам решает, какие порты открыть, и они мгновенно на хосте.

Когда полезенПочему не подходит для большинства случаев
Performance-critical (Kafka broker, eBPF)Нет изоляции — порт-конфликты с хостом
Контейнер должен видеть LAN напрямуюКонтейнер видит ВСЕ интерфейсы хоста
Debug: контейнер делает много DNS-запросовАтакующий внутри = почти full host access

На macOS и Windows --network host работает частично: контейнер всё равно живёт в Linux VM, и «host» — это VM, а не твой macOS. То есть localhost:80 на маке не достучится до контейнера в host-network. Это известное расхождение.


None

Нет сети, кроме loopback. Контейнер изолирован полностью.

docker run --rm --network none alpine ping -c 2 8.8.8.8
# ping: bad address — нет route

Применений мало:

  • Изолированные batch-jobs, которые читают данные из bind mount и пишут в bind mount, без сети.
  • Кросс-компиляция (docker run --network none ...).
  • Защитная мера для подозрительных образов: лучше запустить с --network none и потом дать сеть точечно.

NAT — как ваш домашний роутер прячет 50 устройств за одним IP

Overlay

Multi-host network. Контейнеры на разных физических хостах попадают в одну логическую сеть через VXLAN-туннели. Требует swarm mode или k8s (CNI-плагин).

# На swarm manager:
docker swarm init
docker network create -d overlay swarm-net

# Контейнер на ноде A:
docker service create --name web --network swarm-net nginx:1.27-alpine

# Контейнер на ноде B (на той же swarm-сети):
docker service create --name db --network swarm-net postgres:17

# web может пинговать db по имени, физически они на разных хостах.

Это уровень «production-кластер». Для junior DE — знать, что такое существует, и что k8s service-mesh устроен похожим образом (хотя там другой driver). Глубокое погружение в overlay — отдельная история про swarm.


Macvlan

Контейнер получает собственный MAC-адрес и IP в физической LAN. Снаружи он выглядит как ещё одно устройство в сети.

docker network create -d macvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o parent=eth0 \
  lan-net

docker run --rm --network lan-net --ip 192.168.1.50 alpine ip addr
# eth0 имеет 192.168.1.50, MAC сгенерирован Docker'ом

Снаружи контейнер виден в LAN на IP 192.168.1.50, как будто это отдельная машина. Удобно, когда нужно дать контейнеру «настоящий» IP, например для IoT-устройств, которые ожидают broadcast в LAN.

Минусы:

  • На некоторых сетевых картах не работает promiscuous mode — без него macvlan не функционирует.
  • Контейнер с macvlan не видит host’а в LAN (известное ограничение Linux), потому что host выпадает из macvlan-loopback path.
  • Сложен в setup, требует знаний LAN.

Для DE-задач macvlan нужен редко. Но знать, что такое есть, полезно — в production-стенде с устаревшими сервисами он иногда вылезает.


Сводная таблица

Когда какой driver
bridge (user-defined)Стандартный выбор для compose-стендов и большинства dev-задач. DNS by container name работает
Compose, dev, single-host99% задач локальной разработки. Postgres + app + redis на одной машине — это bridge
hostКогда нужна максимальная производительность и каждый микросекунда важна. Цена — нет изоляции, порт-конфликты с хостом
Edge/perf-criticalKafka broker в standalone, eBPF tools, observability-агенты, которые должны видеть host network stack
noneПолная изоляция. Контейнер только сам с собой через loopback
Безопасные batch-jobsЗапуск подозрительного образа, кросс-сборка, изолированный transform без сети
overlayMulti-host. Контейнеры на разных машинах в одной логической сети через VXLAN
Production clusterSwarm и k8s (через CNI). Для junior DE — знать о существовании, не настраивать вручную
macvlanКонтейнер с собственным IP в LAN. Виден как отдельная машина
IoT, legacy, broadcastКогда сервис должен лежать в LAN и его обнаруживают по broadcast (mDNS, UPnP). Редкий кейс для DE
DriverScopeИзоляцияDNS by nameСложностьТипичный use
bridgelocalсредняяда (user-defined)низкаяdev, compose
hostlocalникакой-низкаяperf-edge
nonelocalмаксимум-низкаяsandbox
overlayswarmсредняядавысокаяmulti-host
macvlanlocalсредняянетсредняяLAN-resident

Что выбирает Docker по умолчанию

docker run -d --name pg postgres:17
# Куда подключился?
docker inspect pg --format '{{json .NetworkSettings.Networks}}'
# {"bridge":{...}}

Без явного --network — попадает в default bridge. На нём НЕТ DNS by container name. Чтобы получить адекватное окружение для dev:

docker network create etl
docker run -d --name pg --network etl postgres:17
docker run --rm --network etl alpine ping -c 2 pg
# pg резолвится в IP, ping проходит

Compose делает это автоматически. При запуске docker compose up создаётся network с именем <project>_default, и все сервисы подключаются туда. Поэтому в compose работает host: postgres из коробки, а в ручных docker run — нет (если не создал свою сеть).


Попробуй сам

# 1. Список сетей.
docker network ls

# 2. Inspect default bridge — какие контейнеры подключены?
docker network inspect bridge | grep -A 2 Containers

# 3. Создаём user-defined bridge с DNS.
docker network create demo-net
docker run -d --name a --network demo-net alpine sleep 1000
docker run -d --name b --network demo-net alpine sleep 1000

docker exec a ping -c 2 b
# 64 bytes from b (172.18.0.3): icmp_seq=1 ttl=64 time=0.05 ms
# DNS by container name работает.

# Сравним с default bridge:
docker rm -f a b
docker run -d --name a alpine sleep 1000
docker run -d --name b alpine sleep 1000
docker exec a ping -c 2 b
# ping: bad address 'b' — DNS не работает на default bridge

# 4. host network — порт сразу на хосте.
docker run -d --name h --network host nginx:1.27-alpine
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:80
# 200 — без -p mapping, на macOS не сработает.

# 5. none — изоляция.
docker run --rm --network none alpine sh -c 'wget -q -O - https://example.com'
# wget: bad address 'example.com' — сети нет

# Cleanup.
docker rm -f a b h
docker network rm demo-net
NOTE

Default bridge оставлен для совместимости со старыми сценариями. Все compose-файлы и осмысленные docker run-команды должны создавать или использовать user-defined bridge. Считай default bridge «технический долг Docker».

В следующем уроке — bridge подробнее: docker0, veth, как работает -p 8080:80 через iptables.


Проверка знанийKnowledge check
Ты запустил два контейнера через docker run --name pg postgres:17 и docker run --name app myapp . Из app пытаешься ping pg — выдаёт bad address . В compose такой проблемы нет. Почему?
ОтветAnswer
Оба контейнера в default bridge — там DNS by container name выключен (это legacy-поведение Docker, оставленное для совместимости). На default bridge между контейнерами работает только IP-связность, причём IP может меняться при перезапуске. В compose же при docker compose up автоматически создаётся user-defined bridge с именем <project>_default, и оба сервиса подключаются именно туда. На user-defined bridge Docker запускает встроенный embedded DNS server (127.0.0.11), который резолвит контейнерные имена и compose-service-name'ы. Поэтому "ping pg" в compose работает, а в ручных run — нет. Лечение: либо создать свою сеть (docker network create mynet) и подключить оба контейнера через --network mynet, либо переехать на compose.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 4. Два контейнера на default bridge сети: docker run --name a alpine, docker run --name b alpine. Из a команда ping b возвращает 'bad address'. Почему?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4