Модуль 8 / 18
Сети Docker: bridge, DNS, публикация портов и IPv6
Содержание
1. Цели и модель сетевого пути
После модуля вы сможете объяснить путь пакета между network namespace, veth, bridge, firewall/NAT и host interface; использовать встроенный DNS; безопасно публиковать порты и диагностировать IPv4/IPv6 по уровням.
- network driver определяет модель связности
- user-defined bridge создаёт изолированный L2/L3 segment одного Engine
- встроенный DNS разрешает container names и aliases
- EXPOSE документирует порт, publish создаёт host mapping
- bind address определяет поверхность доступа
- IPv6 address не отменяет firewall и routing requirements
2. Теория: namespace, veth и bridge
Контейнер получает собственный network namespace с interfaces, routes и resolver configuration. Для bridge driver один конец veth находится в namespace контейнера, другой подключён к Linux bridge хоста. Docker управляет IPAM, forwarding, isolation и masquerading.
Default bridge является общей legacy-сетью и не предоставляет современное автоматическое name resolution между контейнерами. User-defined bridge даёт scoped DNS, настраиваемый subnet/MTU/options и возможность connect/disconnect без пересоздания контейнера.
3. Теория: встроенный DNS и service discovery
В user-defined network контейнеры обращаются к embedded DNS Docker, обычно через 127.0.0.11. Он разрешает container name и network-scoped aliases в адрес endpoint этой сети, а внешние запросы пересылает настроенным upstream resolvers.
IP контейнера — runtime detail. Клиент должен использовать стабильное имя/alias и container port. Один container в нескольких сетях может иметь разные адреса и aliases. DNS resolution не доказывает доступность listener: после DNS отдельно проверяют route, TCP и application protocol.
4. Теория: EXPOSE, publish и bind address
EXPOSE записывает metadata image и ничего не открывает. --publish HOST_IP:HOST_PORT:CONTAINER_PORT создаёт mapping через firewall/NAT либо routing mode. Если HOST_IP пропущен, порт обычно привязывается ко всем адресам хоста и может стать внешне доступным.
Для локальной administrative endpoint используйте 127.0.0.1 либо ::1 и проверяйте реальный listener/firewall. Publish не нужен для общения контейнеров одной сети: они обращаются к container port напрямую. -P публикует все exposed ports на случайные host ports и редко подходит production.
5. Теория: forwarding, NAT и host firewall
На Linux Docker создаёт firewall rules для bridge isolation, masquerading и published ports. Engine 29 поддерживает iptables backend и экспериментальный nftables backend. Нельзя вручную править Docker-owned chains: они являются внутренней реализацией и пересоздаются.
Отключение iptables/ip6tables в daemon почти всегда ломает network behavior. UFW может быть обойдён DNAT до его обычных INPUT/OUTPUT rules, поэтому доступ контролируют с учётом Docker forwarding path. Для iptables backend предназначен DOCKER-USER; в nftables backend этой chain нет и нужны отдельные base chains с корректным priority.
6. Теория: IPv6 и dual stack
User-defined bridge можно создать с --ipv6. Современный Engine может автоматически выделить ULA prefix, если IPv6 pool не задан. Для production обычно планируют собственный ULA/GUA subnet, routing, neighbor discovery, DNS AAAA и firewall симметрично IPv4.
IPv6 не использует NAT как обязательную модель. Gateway modes nat, routed, nat-unprotected и isolated меняют direct routing и filtering. Routed mode требует маршрута извне к container subnet; публикация и bind semantics отличаются, поэтому выбранный mode документируют и тестируют отдельно.
7. Методические указания
- Создавайте отдельную сеть для каждого application boundary
- Используйте DNS alias, а не зафиксированный container IP
- Публикуйте только необходимые ports и явный host address
- Не применяйте host network как обход DNS или firewall
- Проверяйте listener внутри контейнера до host NAT
- Не меняйте Docker-owned firewall rules вручную
- Тестируйте IPv4 и IPv6 независимо
- Собирайте network inspect до удаления failed container
8. Лабораторная работа: DNS, publish, isolation и IPv6
Зафиксируйте host/network baseline, затем создайте user-defined bridge, web endpoint и client.
docker info --format '{{json .Plugins.Network}}' | jq
docker network ls
docker network inspect bridge
sysctl net.ipv4.ip_forward net.ipv6.conf.all.forwarding
ip -brief link
ip routedocker network create --driver bridge docker-m8-app
docker run --detach --name docker-m8-web --network docker-m8-app --network-alias api nginx:1.29-alpine
docker run --detach --name docker-m8-client --network docker-m8-app alpine:3.21 sleep 600
docker exec docker-m8-client cat /etc/resolv.conf
docker exec docker-m8-client nslookup docker-m8-web
docker exec docker-m8-client nslookup api
docker exec docker-m8-client wget -qO- http://api/
docker network inspect docker-m8-appДокажите, что EXPOSE образа не публикует порт, затем создайте отдельный mapping только на loopback.
docker port docker-m8-web
curl --fail --max-time 2 http://127.0.0.1:18088/ || true
docker run --detach --name docker-m8-published --network docker-m8-app --publish 127.0.0.1:18088:80 nginx:1.29-alpine
docker port docker-m8-published
curl --fail --silent --show-error http://127.0.0.1:18088/
docker inspect docker-m8-published --format '{{json .NetworkSettings.Ports}}' | jqПроверьте isolation двух bridge networks и динамическое подключение endpoint.
docker network create docker-m8-backend
docker run --detach --name docker-m8-isolated --network docker-m8-backend alpine:3.21 sleep 600
docker exec docker-m8-isolated nslookup docker-m8-web || true
docker network connect docker-m8-app docker-m8-isolated
docker exec docker-m8-isolated wget -qO- http://docker-m8-web/
docker network disconnect docker-m8-app docker-m8-isolated
docker inspect docker-m8-isolated --format '{{json .NetworkSettings.Networks}}' | jqСоздайте временную IPv6-enabled сеть с автоматически назначенным ULA и проверьте ICMPv6 по DNS-имени.
docker network create --ipv6 docker-m8-v6
docker run --detach --name docker-m8-v6-server --network docker-m8-v6 alpine:3.21 sleep 600
docker run --rm --network docker-m8-v6 alpine:3.21 ping -6 -c 3 docker-m8-v6-server
docker network inspect docker-m8-v6 --format '{{json .IPAM.Config}}' | jq
docker inspect docker-m8-v6-server --format '{{json .NetworkSettings.Networks}}' | jqКритерий: aliases разрешаются; unpublished endpoint недоступен через host port; loopback mapping отвечает; отдельная сеть изолирована; IPv6 endpoint получает адрес и отвечает.
9. Диагностика: DNS работает, соединения нет
Идите по пути packet последовательно: выбранный context → endpoint membership → DNS → route → listener → firewall/NAT → protocol. Замена network mode до локализации причины уничтожает evidence.
docker container ls --all --filter name=docker-m8
docker network ls
docker network inspect docker-m8-app
docker exec docker-m8-client ip address
docker exec docker-m8-client ip route
docker exec docker-m8-client nslookup api
docker exec docker-m8-client wget -S -O- http://api/ 2>&1 | head -40
ss -lntp | grep 18088 || true
docker logs docker-m8-published- inspect Networks — подключён ли endpoint и какой alias
- resolv.conf/nslookup — работает ли DNS
- ip route — существует ли gateway/path
- listener должен слушать нужный address и container port
- docker port/inspect Ports — существует ли host mapping
- ss — слушается ли host port
- logs — дошёл ли request до приложения
- MTU и asymmetric routing проверяются после базовой связности
10. Контроль, cleanup и шпаргалка
- Почему user-defined bridge лучше default bridge?
- Что разрешает 127.0.0.11?
- Чем EXPOSE отличается от --publish?
- Почему контейнеры одной сети используют container port?
- Как omission HOST_IP меняет exposure?
- Почему UFW может не ограничить published port ожидаемым образом?
- Что требуется routed IPv6 network?
- В каком порядке диагностировать connection refused?
docker container rm --force docker-m8-web docker-m8-client docker-m8-published docker-m8-isolated docker-m8-v6-server 2>/dev/null || true
docker network rm docker-m8-app docker-m8-backend docker-m8-v6
docker network lsМодуль освоен, если вы проектируете network boundaries, не зависите от container IP и доказываете каждый участок пути DNS → route → listener → firewall → application.