Главная/Материалы/Материал

Топология сети

Путь пакета от хоста до приложения и обратно.

Что создаётся при запуске container'а

text
                      ХОСТ
   ┌───────────────────────────────────────────────┐
   │                                               │
   │   eth0 (внешняя сеть)                         │
   │     │                                         │
   │     │  правила трансляции адресов             │
   │     │  8080/tcp ──► 172.18.0.2:8000           │
   │     │                                         │
   │   ┌─┴──────────────┐                          │
   │   │  docker0 или   │  мост                    │
   │   │  br-xxxx       │  172.18.0.1              │
   │   └─┬──────────┬───┘                          │
   │     │          │                              │
   │  veth-a     veth-b       ← пары интерфейсов   │
   └─────┼──────────┼─────────────────────────────-┘
         │          │
   ┌─────┴────┐ ┌───┴──────┐
   │  eth0    │ │  eth0    │  ← внутри своих
   │172.18.0.2│ │172.18.0.3│    network namespace
   │          │ │          │
   │   api    │ │    db    │
   │ lo:      │ │ lo:      │  ← у каждого СВОЙ 127.0.0.1
   │ 127.0.0.1│ │ 127.0.0.1│
   └──────────┘ └──────────┘

Как читать

veth — пара интерфейсов, работающая как отрезок кабеля: что вошло с одного конца, вышло с другого. Один конец находится в namespace container'а и называется там eth0, другой подключён к мосту на хосте.

Мост соединяет всё, что к нему подключено. Container'ы одной сети видят друг друга напрямую.

Что здесь неочевидно

У каждого container'а свой 127.0.0.1. Это отдельный интерфейс lo внутри своего namespace. Приложение, слушающее петлю, недоступно ни с хоста, ни от соседа — только для процессов того же container'а.

text
api пытается: postgresql://localhost:5432
                          └─► свой lo, где ничего нет

должно быть:  postgresql://db:5432
                          └─► 172.18.0.3 через мост

Публикация порта — правило трансляции, а не «открытие». Оно направляет трафик с порта хоста на адрес container'а. Если приложение слушает петлю, правило ведёт в пустоту:

text
curl localhost:8080
      │
      ▼  правило: 8080 ──► 172.18.0.2:8000
      │
      ▼  на 172.18.0.2:8000 никто не слушает
   отказ                    (приложение на 127.0.0.1:8000)

EXPOSE не создаёт ни одного правила. Это запись в метаданных образа.

Разрешение имён

text
   сеть по умолчанию bridge          пользовательская сеть
   ─────────────────────────         ─────────────────────
   только адреса                     встроенный DNS 127.0.0.11
   getent hosts db → пусто           getent hosts db → 172.18.0.3

Compose создаёт пользовательскую сеть автоматически — поэтому симптом «имя не разрешается» встречается только при ручном docker run.

Изоляция сетей

text
       хост
        │  публикация 8080
        ▼
   ┌─────────┐
   │frontend │
   └────┬────┘
        │
   ┌────┴────┐
   │   api   │  состоит в обеих сетях
   └────┬────┘
        │
   ┌────┴──────────────────────┐
   │  backend (internal: true) │  нет выхода наружу
   │   ┌────┐  ┌────┐  ┌─────┐ │
   │   │ db │  │cache│ │worker│ │
   │   └────┘  └────┘  └─────┘ │
   └───────────────────────────┘

internal: trueне то же, что «не публиковать порты»:

ЧтоНаправление
Не публиковать портСнаружи внутрь
internal: trueИзнутри наружу

Второе защищает от того, что скомпрометированная зависимость обратится в интернет.

Режимы сети

text
bridge (умолчание)     свой namespace, адрес в мосте, NAT
host                   namespace ХОСТА: нет NAT, нет изоляции
none                   только lo
container:имя          тот же namespace, что у другого container'а

Последний — основной приём отладки:

bash
docker run --rm -it --network container:api nicolaka/netshoot
ss -tlnp        # видит сокеты api

От симптома к месту на схеме

СимптомГде искать
Порт опубликован, ответа нетСлушает ли приложение и на каком адресе
Изнутри отвечает, снаружи нетlo вместо eth0
Имя не разрешаетсяСеть по умолчанию вместо пользовательской
Имя разрешается, соединения нетСосед не слушает или не готов
Внешние имена не разрешаютсяinternal: true или DNS хоста
Работает только при --network hostПриложение слушает петлю

Подробнее

Урок 8.1. Основы сети
Урок 8.2. Bridge-сети
Урок 8.3. Публикация портов
Networking cheat sheet


Навигация

Раздел 08. Networking
Диаграмма стека Compose
Главное оглавление

Markdown на GitHub ↗