Перейти к основному содержимому

Как работает bridge-сеть в Docker

·954 слов·5 минут
DevOps • Networks • Security • Infrastructure
Автор
DevOps • Networks • Security • Infrastructure
DevOps, Expert CyberSecurity, Network/Infrastructure Engineer

В мире контейнеризации 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 [.]

Related

Lazydocker для Docker
·89 слов·1 минута
Установка Docker на Ubuntu
·263 слов·2 минут
Настройка Policy-based и Route-based VPN через strongSwan с swanctl
·834 слов·4 минут