### Обзор сетей Docker
Сеть Docker построена на Container Network Model (CNM), которая позволяет кому угодно создать свой собственный сетевой драйвер. Таким образом, у контейнеров есть доступ к разным типам сетей и они могут подключаться к нескольким сетям одновременно. Помимо различных сторонних сетевых драйверов, у самого Docker-а есть 4 встроенных:
* Bridge: в этой сети контейнеры запускаются по умолчанию. Связь устанавливается через bridge-интерфейс на хосте. У контейнеров, которые используют одинаковую сеть, есть своя собственная подсеть, и они могут передавать данные друг другу по умолчанию.
* Host: этот драйвер дает контейнеру доступ к собственному пространству хоста (контейнер будет видеть и использовать тот же интерфейс, что и хост).
Macvlan: этот драйвер дает контейнерам прямой доступ к интерфейсу и суб-интерфейсу (vlan) хоста. Также он разрешает транкинг.
* Overlay: этот драйвер позволяет строить сети на нескольких хостах с Docker (обычно на Docker Swarm кластере). У контейнеров также есть свои адреса сети и подсети, и они могут напрямую обмениваться данными, даже если они располагаются физически на разных хостах.
Сетевые драйвера Bridge и Overlay, возможно, используются чаще всего, поэтому в этой статье я буду больше уделять им внимание.
#### Сети типа мост (bridge)
По умолчанию для контейнеров используется bridge. При первом запуске контейнера Docker создает дефолтную bridge-сеть с одноименным названием.
При запуске контейне-ра Docker создает новый экземпляр пары veth (фактически программный аналог кабеля Ethernet), соединяющий интерфейс eth0 в контейнере со шлюзом. Внешние соединения обслуживаются при помощи механизма перенаправления IP forwarding и правил сетевого экрана iptables, которые определяют конфигурацию механизма преобразования IP-адресов IP masquerading, одну из форм механизма NAT (Network Address Translation).
![Структура данных буферного кэша](https://whoisdeveloper.ru/static/img/docker0.png)
```
nick@MacBook-Pro-DNA ~ % docker network ls
NETWORK ID NAME DRIVER SCOPE
3fdff1bfb8ed bridge bridge local
45178a860cc9 host host local
741de63e7bf7 none null local
```
По умолчанию все контейнеры могут обмениваться данными друг с другом, независимо от того, установлены ли соединения между ними и объявлены ли открытые или экспортируемые порты. Свободный обмен данными можно отменить, отключив эту возможность при запуске демона Docker с помощью флага --icc=false, который устанавливает соответствующее правило сетевого экрана iptables. Значения флагов --icc=false и --iptables=true позволяют обмениваться данными только контейнерам с установленными соединениями, и это тоже реализуется добавлением соответствующих правил iptables.
Чтобы проинспектировать ее свойства, запустим команду docker network inspect bridge:
```
nick@MacBook-Pro-DNA ~ % docker inspect bridge
[
{
"Name": "bridge",
"Id": "3fdff1bfb8edafcab54fbf946d820f27c31eec3233198c44cf2bb6907f1a77bd",
"Created": "2022-05-16T19:22:37.390793541Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"c191fed717d007c62645919607fe94a62ba5ad526c74e1d5104184f7f6972ae1": {
"Name": "admiring_agnesi",
"EndpointID": "efd6ccd31013c996cb81ea017b9b468903e2a467186275c339b8aaac33628e1b",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
```
Вы также можете создать свои собственные bridge-сети при помощи команды docker network create, указав опцию --driver bridge.
При разработке все это удобно и полезно, но проблемы производительности делают этот режим не вполне подходящим для эксплуатации.
#### Bridge-интерфейсы в Linux
Bridge-интерфейсы Linux похожи на свичи тем, что они присоединяют несколько интерфесов к одной подсети и перенаправляют трафик на основе MAC-адресов. Как будет видно ниже, у каждого контейнера, привязанного к bridge-сети, будет свой собственный виртуальный интерфейс на хосте, и все контейнеры в одной сети будут привязаны к одному интерфейсу, что позволит им передавать друг другу данные.
Можно получить больше данных о статусе моста при помощи утилиты brctl.
Как только мы запустим контейнеры и привяжем их к этой сети, интерфейс каждого из этих контейнеров будет выведен в списке в отдельной колонке. А если включить захват трафика в bridge-интерфейсе, то можно увидеть, как передаются данные между контейнерами в одной подсети.
#### Виртуальные интерфейсы Linux
Container Networking Model дает каждому контейнеру свое собственное сетевое пространство. Если запустить команду ifconfig внутри контейнера, то можно увидеть его интерфейсы такими, какими их видит сам контейнер.
### iptables
Docker использует linux iptables, чтобы контролировать коммуникации между интерфейсами и сетями, которые он создает. Linux iptables состоят из разных таблиц, но нам в первую очередь интересны только две из них: filter и nat. Таблица filter содержит правила безопасности, которые решают, допускать ли трафик к IP-адресам или портам. С помощью таблицы nat Docker дает контейнерам в bridge-сетях связываться с адресатами, которые находятся снаружи хоста (иначе пришлось бы добавлять маршруты к контейнерным сетям в сети хоста).
#### iptables:filter
Таблицы в iptables состоят из различных цепочек, которые соответствуют разным состояниям или стадиям обработки пакета на хосте. По умолчанию, у таблицы filter есть 3 цепочки:
Input для обработки входящих пакетов, предназначенных для того же хоста, на который они приходят;
Output для пакетов, возникающих на хосте, предназначенных для внешнего адресата;
Forward для обработки входящих пакетов, предназначенных для внешнего адресата.
Каждая цепочка включает в себя правила, которые определяют, какие действия и при каких условиях надо применить к пакету (например, отклонить или принять его). Правила обрабатываются последовательно, пока не будет найдено соответствие, иначе применяются дефолтные правила цепочки. Также в таблице можно задать кастомные цепочки.
Чтобы увидеть текущие правила цепочки и дефолтные установки в таблице filter, запустите команду iptables -t filter -L или iptables -L, если таблица filter используется по умолчанию и не указана никакая другая таблица:
#### Цепочка Docker-isolation
Docker-isolation содержит правила, которые ограничивают доступ между разными сетями.
#### icc=false
Одна из опций, которую можно передать команде docker network create, — это опция, которая отвечает за передачу данных внутри контейнера: com.docker.network.bridge.enable_icc. Если задать ей значение false, то передача данных между контейнерами внутри одной сети будет заблокирована. Для этого нужно добавить DROP-правило в цепочку forward, которое соответствует пакетам, приходящим от bridge-интерфейса, связанного с сетью для данного интерфейса.
Например, если создать новую сеть при помощи команды docker network create --driver bridge --subnet 192.168.200.0/24 --ip-range 192.168.200.0/24 -o "com.docker.network.bridge.enable_icc"="false" no-icc-network, то мы получим следующее:
#### iptables:nat
С помощью nat можно поменять IP-адрес или порт пакета. В данном случае он используется, чтобы за IP-адресом хоста спрятать адреса источников пакетов, которые приходят от bridge-сетей (например, хосты в подсети 172.18.0.0/24) и направлены во внешний мир. Эта фича контролируется опцией com.docker.network.bridge.enable_ip_masquerade, которую можно передать docker network create (если не задать ничего специфического, то по умолчанию будет значение true).
### Режим host
Контейнер, запущенный с флагом --net=host, использует пространство сетевых имен хоста, становясь полностью открытым для внешней сети. Это означает, что такой контейнер использует IP-адрес хоста совместно с другими контейнерами, но при этом исключается необходимость ручной работы, требуемой в режиме bridge, таким образом, сеть работает так же быстро, как и обычная сеть, состоящая из хостов.
Поскольку IP-адрес используется совместно, контейнеры, обменивающиеся данными друг с другом, должны правильно распределить между собой порты на хосте, поэтому необходимо тщательно продумать и, возможно, изменить структуру приложений.
Существенное улучшение производительности позволяет рассмотреть возможность реализации гибридной сетевой модели, в которой внешние контейнеры с большой сетевой нагрузкой, такие как прокси и кэши, используют сетевой режим host, а остальные контейнеры работают во внутренней сети в режиме bridge. Отметим невозможность установления прямых соединений между контейнерами, работающими в режиме bridge, с контейнерами, работающими в режиме host, но контейнеры в bridge-сети могут обмениваться данными с контейнерами host-сети, используя для этого IP-адрес шлюза docker0.
### Режим container
В этом режиме используется пространство сетевых имен из другого контейнера. В некоторых ситуациях это очень удобно (например, при запуске контейнера с предварительно сконфигурированным сетевым стеком необходимо, чтобы все прочие контейнеры также использовали этот стек). Это позволяет создавать и многократно использовать эффективные конфигурации сетевых стеков, специализированных для конкретных вариантов использования или для архитектур центров данных. Недостаток заключается в том, что все контейнеры, совместно использующие сетевой стек, вынуждены пользоваться одним IP- адресом и т. д.
### Режим none
В этом режиме сетевая среда становится полностью недоступной для контейнера. Это может оказаться удобным для контейнеров, которым сеть вообще не нужна, например для контейнера-компилятора, записывающего весь свой поток вывода на том.
Режим отключения сетевой среды также может быть полезен в ситуациях, когда необходимо настроить собственную сетевую среду с нуля. В этом случае можно воспользоваться инструментальными средствами, такими как pipework (https:// github.com/jpetazzo/pipework), обеспечивающими удобство при работе с сетями внутри cgroups и пространств имен.
## Overlay
Overlay – это реализация решения Docker «с включенным комплектом батареек» для организации сетевой среды, распределенной по многим хостам. Решение использует туннели VXLAN для соединений хостов в их внутреннем пространстве IP-адресов и NAT для установления внешних соединений. Библиотека serf (https:// serfdom.io/) используется для обмена данными между узлами.
Объединение контейнеров в сеть выполняется практически тем же способом, как и для стандартной сети со шлюзами, – устанавливается шлюз Linux для сети Overlay, затем пара виртуальных интерфейсов veth используется для установления соединения с контейнером.