В мире контейнеризации Docker сеть — не просто способ подключения к интернету. Это механизм, который определяет, как контейнеры видят друг друга, хост и внешние сети. Одним из базовых, но ключевых элементов этой архитектуры является bridge-сеть — программный сетевой мост, который по умолчанию связывает контейнеры на одном Docker-хосте.
Bridge-сеть обеспечивает:
- изоляцию контейнеров от остальной сети,
- возможность взаимодействия контейнеров внутри одной подсети,
- NAT-маршрутизацию для выхода в интернет,
- публикацию портов и доступ извне при необходимости.
В этой статье мы подробно разберём, как устроена bridge-сеть в Docker, как пакеты проходят через неё и что происходит “под капотом”, когда контейнер общается с внешним миром или с другим контейнером на том же хосте.
Общая архитектура bridge-сети #
┌───────────────────────────────────────────────────┐
│ DOCKER HOST (10.130.0.5) │
│ ┌═════════════════════════════════════════════┐ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Контейнер A │ │ Контейнер B │ │ │
│ │ │ 172.17.0.2 │ │ 172.17.0.3 │ │ │
│ │ │ ┌─────┐ │ │ ┌─────┐ │ │ │
│ │ │ │eth0 │ │ │ │eth0 │ │ │ │
│ │ │ └──┬──┘ │ │ └──┬──┘ │ │ │
│ │ └──────┼──────┘ └──────┼──────┘ │ │
│ │ veth123 veth456 │ │
│ │ (veth883b6aa) (vethXYZ) │ │
│ │ └──────────┬────────────┘ │ │
│ │ ┌───────┴───────┐ │ │
│ │ │ docker0 │ │ │
│ │ │ bridge │ │ │
│ │ │ 172.17.0.1 │ │ │
│ │ └───────┬───────┘ │ │
│ │ ┌───────┴───────┐ │ │
│ │ │ iptables │ │ │
│ │ │ NAT │ │ │
│ │ └───────┬───────┘ │ │
│ │ ┌───────┴───────┐ │ │
│ │ │ eth0 │ │ │
│ │ │ 10.130.0.5 │ │ │
│ │ └───────┬───────┘ │ │
│ └────────────────────┼────────────────────────┘ │
└───────────────────────┼───────────────────────────┘
┌──────┴──────┐
│ INTERNET🌐 │
└─────────────┘
Настройки сети на сервере с Docker #
root@ubuntu:~# ip -br a
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 10.130.0.5/24 metric 100 fe80::d20d:1dff:fe15:a32f/64
docker0 UP 172.17.0.1/16 fe80::80f8:64ff:fe5b:40d9/64
veth883b6aa@if2 UP fe80::9cda:1dff:fe14:4d9/64
root@ubuntu:~# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.82f8645b40d9 no veth883b6aa
root@ubuntu:~# docker network ls
NETWORK ID NAME DRIVER SCOPE
03478b020492 bridge bridge local
081f803a9ecb host host local
58f54b28e459 none null local
root@ubuntu:~# docker network inspect bridge
Путешествие пакета: как трафик проходит через Docker bridge #
Исходящий трафик (контейнер → Интернет):
172.17.0.5:42495 -(SNAT)-> 10.130.0.5:42495 -(SNAT)-> 158.160.151.151:42495 -(Интернет)-> 137.74.42.42:80
Входящий трафик (Интернет → контейнер):
137.74.42.42:45448 -(Интернет)-> 158.160.151.151:80 -(DNAT)-> 10.130.0.5:80 -(DNAT)-> 172.17.0.5:80
Из контейнера в Интернет #
Источник: 172.17.0.5:42495 (контейнер)
Назначение: 137.74.42.42:80 (внешний сервер)
nc -lv 80
nc -vz 137.74.42.42 80
Путь исходящего пакета
┌─────────────┐ 1. SYN ┌─────────────┐ 2. SYN ┌─────────────┐
│ Контейнер │ ──────────> │ veth пара │ ──────────> │ docker0 │
│ 172.17.0.5 │ │ veth883b6aa │ │ bridge │
└─────────────┘ └─────────────┘ └──────┬──────┘
3. SYN│
(SNAT)│
↓
┌─────────────┐ 4. SYN ┌─────────────┐ 5. SYN ┌─────────────┐
│ Внешний │ <────────── │ eth0 │ <────────── │ NAT │
│ сервер │ │ 10.130.0.5 │ │ iptables │
│ 137.74.42.42│ └─────────────┘ └─────────────┘
└─────────────┘
Реальный дамп трафика (исходящее соединение)
# TCP SYN (SNAT)
# Three-Way Handshake
veth883b6aa P IP 172.17.0.5.42495 > 137.74.42.42.80: Flags [S]
docker0 In IP 172.17.0.5.42495 > 137.74.42.42.80: Flags [S]
eth0 Out IP 10.130.0.5.42495 > 137.74.42.42.80: Flags [S]
# TCP SYN-ACK (DNAT)
eth0 In IP 137.74.42.42.80 > 10.130.0.5.42495: Flags [S.]
docker0 Out IP 137.74.42.42.80 > 172.17.0.5.42495: Flags [S.]
veth883b6aa Out IP 137.74.42.42.80 > 172.17.0.5.42495: Flags [S.]
# TCP ACK (SNAT)
veth883b6aa P IP 172.17.0.5.42495 > 137.74.42.42.80: Flags [.]
docker0 In IP 172.17.0.5.42495 > 137.74.42.42.80: Flags [.]
eth0 Out IP 10.130.0.5.42495 > 137.74.42.42.80: Flags [.]
# TCP FIN-ACK (SNAT)
# Four-Way Handshake
veth883b6aa P IP 172.17.0.5.42495 > 137.74.42.42.80: Flags [F.]
docker0 In IP 172.17.0.5.42495 > 137.74.42.42.80: Flags [F.]
eth0 Out IP 10.130.0.5.42495 > 137.74.42.42.80: Flags [F.]
# TCP ACK + FIN-ACK (DNAT)
eth0 In IP 137.74.42.42.80 > 10.130.0.5.42495: Flags [.]
docker0 Out IP 137.74.42.42.80 > 172.17.0.5.42495: Flags [.]
veth883b6aa Out IP 137.74.42.42.80 > 172.17.0.5.42495: Flags [.]
eth0 In IP 137.74.42.42.80 > 10.130.0.5.42495: Flags [F.]
docker0 Out IP 137.74.42.42.80 > 172.17.0.5.42495: Flags [F.]
veth883b6aa Out IP 137.74.42.42.80 > 172.17.0.5.42495: Flags [F.]
# TCP ACK (SNAT)
veth883b6aa P IP 172.17.0.5.42495 > 137.74.42.42.80: Flags [.]
docker0 In IP 172.17.0.5.42495 > 137.74.42.42.80: Flags [.]
eth0 Out IP 10.130.0.5.42495 > 137.74.42.42.80: Flags [.]
Из Интернета в контейнер #
Источник: 137.74.42.42.45448 (внешний сервер)
Назначение: 172.17.0.5:80:80 (контейнер)
nc -lv 80
nc -vz 158.160.151.151 80
Путь входящего пакета
┌─────────────┐ 1. SYN ┌─────────────┐ 2. SYN ┌─────────────┐
│ Внешний │ ──────────> │ eth0 │ ──────────> │ NAT │
│ клиент │ │ 10.130.0.5 │ │ iptables │
│ 137.74.42.42│ └─────────────┘ └──────┬──────┘
└─────────────┘ 3. SYN│
(DNAT)│
↓
┌─────────────┐ 6. SYN ┌─────────────┐ 5. SYN ┌─────────────┐
│ Контейнер │ <────────── │ veth пара │ <────────── │ docker0 │
│ 172.17.0.5 │ │ veth883b6aa │ │ bridge │
└─────────────┘ └─────────────┘ └─────────────┘
Реальный дамп трафика (входящее соединение)
# TCP SYN (DNAT)
# Three-Way Handshake
eth0 In IP 137.74.42.42.45448 > 10.130.0.5.80: Flags [S]
docker0 Out IP 137.74.42.42.45448 > 172.17.0.5.80: Flags [S]
veth883b6aa Out IP 137.74.42.42.45448 > 172.17.0.5.80: Flags [S]
# TCP SYN-ACK (SNAT)
veth883b6aa P IP 172.17.0.5.80 > 137.74.42.42.45448: Flags [S.]
docker0 In IP 172.17.0.5.80 > 137.74.42.42.45448: Flags [S.]
eth0 Out IP 10.130.0.5.80 > 137.74.42.42.45448: Flags [S.]
# TCP ACK (DNAT)
eth0 In IP 137.74.42.42.45448 > 10.130.0.5.80: Flags [.]
docker0 Out IP 137.74.42.42.45448 > 172.17.0.5.80: Flags [.]
veth883b6aa Out IP 137.74.42.42.45448 > 172.17.0.5.80: Flags [.]
# TCP FIN-ACK (DNAT)
# Four-Way Handshake
eth0 In IP 137.74.42.42.45448 > 10.130.0.5.80: Flags [F.]
docker0 Out IP 137.74.42.42.45448 > 172.17.0.5.80: Flags [F.]
veth883b6aa Out IP 137.74.42.42.45448 > 172.17.0.5.80: Flags [F.]
# TCP FIN-ACK (SNAT)
veth883b6aa P IP 172.17.0.5.80 > 137.74.42.42.45448: Flags [F.]
docker0 In IP 172.17.0.5.80 > 137.74.42.42.45448: Flags [F.]
eth0 Out IP 10.130.0.5.80 > 137.74.42.42.45448: Flags [F.]
# TCP ACK (DNAT)
eth0 In IP 137.74.42.42.45448 > 10.130.0.5.80: Flags [.]
docker0 Out IP 137.74.42.42.45448 > 172.17.0.5.80: Flags [.]
veth883b6aa Out IP 137.74.42.42.45448 > 172.17.0.5.80: Flags [.]