Когда вы устанавливаете Docker по умолчанию создаётся виртуальный сетевой мост docker0. Этот виртуальный сетевой мост объединяет все контейнеры, работающие в режиме bridge (по умолчанию), в одну внутреннюю сеть, и подключает их к хосту через этот мост.

Т.е. по умолчанию все запущенные контейнеры имеют доступ к остальным контейнерам по виртуальной сети, если даже контейнер создавался без флага -p. Отсюда возникает вопрос что преимущества контейнеризации в изоляции а тут общая сеть. Всё так, но только если делать всё по умолчанию. Если же нужно изолировать контейнеры в виртуальной сети, то необходимо просто создать отдельную виртуальную сеть для этих контейнеров. Лучшей практикой считается создавать отдельную виртуальную сеть для каждого приложения.

Конечно тех, кто следует такой практике очень мало и в целом использование сети bridge по умолчанию не приносит никаких видимых проблем а наоборот только упрощает работу. Но при использовании Docker в K8s об этом обязательно нужно знать.

Для начала я создам контейнер с nginx (если не понятно что происходит).

docker container run -d --name some-nginx -p 80:80 nginx:latest

ip-адрес контейнера

Если у каждого контейнера по умолчанию активна виртуальная сеть стало быть должен быть и ip-адрес отличающийся от ip-адреса самого устройства на котором установлен Docker? Да, всё верно и чтобы получить этот виртуальный ip-адрес используется docker container inspect, подробнее тут.

docker inspect -f '{{ .NetworkSettings.IPAddress }}' some-nginx
172.17.0.3

И да по умолчанию само устройство на котором установлен Docker может обращаться к этому ip-адресу контейнера.

telnet 172.17.0.3 80

Обмен трафиком

Теперь когда я знаю что у меня ip-адрес контейнера 172.17.0.3 а локальный ip-адрес устройства на котором установлен Docker 172.31.144.9 встаёт вопрос почему разные подсети и как вообще если подсети разные локальное устройство имеет доступ к контейнеру по сети. По умолчанию при создании виртуальный сетевой мост docker0 получает IP-адрес из подсети 172.17.0.0/16. И DHCP-сервер Docker автоматически выделяет IP контейнерам из этого диапазона.

Самому же виртуальному сетевому мосту docker0 присваивается IP-адрес 172.17.0.1/16. Все сетевые обращения между контейнерами и локальным хостом происходит через этот docker0.

При старте контейнера Docker делает следующее:

  1. Создаёт виртуальную пару интерфейсов veth-pair (eth0, vethXXXX)
  2. Конец на хосте (vethXXXX) подключается к мосту docker0
  3. Контейнер получает IP-адрес (172.17.0.3)
  4. Теперь контейнер может общаться с другими контейнерами в той же сети docker0 и с самим хостом (172.17.0.1)

Когда вы пытаетесь подключиться к контейнеру с локального сервера используется docker0 и в качестве исходящего ip-адреса будет использоваться 172.17.0.1 вместо 172.31.144.9.

docker container logs -f some-nginx
curl http://172.17.0.3
172.17.0.1 - - [23/Oct/2025:12:01:07 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.76.1" "-"
172.17.0.1 - - [23/Oct/2025:12:01:24 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.76.1" "-"

При обращении контейнера к другому контейнеру трафик идёт напрямую через docker0.

docker start -ai some-alpine
ip a
172.17.0.2/16
curl http://172.17.0.3
172.17.0.2 - - [23/Oct/2025:12:33:55 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/8.14.1" "-"

При обращении же контейнера к внешней сети и наоборот Docker настраивает NAT-правила через iptables , чтобы пакеты маршрутизировались наружу через хостовый интерфейс (обычно eth0). Т.е. для того чтобы обратится к контейнеру с другого сервера в сети (172.31.144.10) к контейнеру с nginx (172.17.0.3) нужно обращаться на 172.31.144.9.

docker-bridge-network.svg

docker container port

Команда docker container port показывает какие порты контейнера проброшены на хост — то есть какие порты доступны снаружи.

docker container port some-nginx
80/tcp -> 0.0.0.0:80
80/tcp -> [::]:80

Расшифровка того что вывела команда сверху:

  • 80/tcp — внутренний порт внутри контейнера (Nginx).
  • 0.0.0.0:80 — порт хоста, к которому можно обращаться извне (например, в браузере http://localhost)
  • Нижний вариант это то же самое только по ipv6

Не использовать виртуальную сеть (–net=host)

Но есть возможность не использовать вообще виртуальную сеть, а вместо этого использовать сеть хоста, т.е. использовать ip-адрес хоста (172.31.144.9). Но такой режим работает только на Linux.

Встречается такое очень редко, на моей памяти это делалось для мониторинга. Например для отправки агентами на систему мониторинга метрик нужно передавать реальный ip-адрес хоста. Т.е. в контейнере стоит агент мониторинга, который отправляет метрики на систему мониторинга. И если сделать всё по умолчанию то в метриках будет стоять ip-адрес контейнера а не хоста.

Также может использоваться в ситуациях когда необходимо убрать все лишние прослойки для лучшей производительности.

docker-host-network.svg