Hns container networking ics dns tcp in что это
Работа с контейнерами многим кажется волшебством, пришло время разобраться как работает сеть контейнеров. Мы покажем на примерах, что это совсем не сложно. Помните, что контейнеры - всего лишь изолированные процессы Linux.
В этой статье мы ответим на следующие вопросы:
Как виртуализировать сетевые ресурсы, чтобы контейнеры думали, что у каждого из них есть выделенный сетевой стек?
Как превратить контейнеры в дружелюбных соседей, не дать им мешать друг другу и научить хорошо общаться?
Как настроить сетевой доступ из контейнера во внешний мир (например, в Интернет)?
Как получить доступ к контейнерам, работающим на сервере, из внешнего мира (публикация портов)?
Отвечая на эти вопросы, мы настроим сеть контейнеров с нуля, используя стандартные инструменты Linux. В результате станет очевидно, что сеть контейнеров - это не что иное, как простая комбинация хорошо известных возможностей Linux:
Virtual Ethernet devices (veth)
Virtual network switches (bridge)
IP маршрутизация и преобразование сетевых адресов (NAT)
Нам потребуется немного сетевой магии и никакого кода .
Предыстория CNI
Проект Container Network Interface (CNI) зародился в компании CoreOS, известной по движку для контейнеров rkt (недавно был тоже передан в CNCF, одновременно с containerd), NoSQL-хранилищу etcd, активной работе над Kubernetes и другими Open Source-проектами, связанными с контейнерами и DevOps. Первая подробная демонстрация CNI состоялась ещё в конце 2015 года (см. видео в октябре, презентацию в ноябре). С самого начала проект позиционировался в качестве «предлагаемого стандарта для конфигурации сетевых интерфейсов для Linux-контейнеров», а использовать его первым делом начали, конечно же, в rkt. Первыми «сторонними пользователями» CNI стали Project Calico, Weaveworks, а в скором времени к ним примкнул Kubernetes.
Адаптация CNI в платформе Kubernetes стоит отдельного внимания. Поскольку потребность в стандартизации сетевой конфигурации Linux-контейнеров была очевидной и всё более актуальной на тот момент (~2015 год), CNI оказался не единственным таким проектом. Конкурирующий продукт — Container Network Model (CNM) от Docker, представленный в том же 2015-м, — решал те же задачи и получил свою эталонную реализацию в виде libnetwork — библиотеки, которая выросла из сетевого кода в libcontainer и Docker Engine. И важным этапом в противостоянии CNI и CNM стал выбор, сделанный Kubernetes. В статье «Почему Kubernetes не использует libnetwork?» (январь 2016 года) разработчики подробно описывают все технические и иные причины, объясняющие их решение. Основная же суть (помимо ряда технических моментов) сводится к следующему:
CNI ближе к Kubernetes с философской точки зрения. Он гораздо проще CNM, не требует демонов и его кроссплатформенность по меньшей правдоподобна (исполняемая среда контейнеров CoreOS rkt поддерживает его) [… а Kubernetes стремится поддерживать разные реализации контейнеров — прим. перев.]. Быть кроссплатформенным означает возможность использования сетевых конфигураций, которые будут одинаково работать в разных исполняемых средах (т.е. Docker, Rocket, Hyper). Этот подход следует философии UNIX делать одну вещь хорошо.
По всей видимости, именно это (не только выбор Kubernetes, но и сторонний взгляд технических специалистов на существующие реализации) предопределило будущее CNI и его принятие в CNCF. Для сравнения, другие конкурирующие продукты CoreOS и Docker: среды исполнения контейнеров rkt и conatinerd — были приняты в фонд вместе и одновременно, а вот с CNI/CNM этого не произошло.
Взгляд проекта Calico на сети для контейнеров в марте 2016 года
Дополнительное сравнение CNI и CNM по состоянию на сентябрь 2016 года можно также найти в англоязычной статье на The New Stack.
Создание политики
- Для сети преобразования сетевых адресов (NAT) по умолчанию HNS создает правила перенаправления портов WinNAT и сопоставления с соответствующими правилами разрешения брандмауэра Windows.
- Для всех остальных сетей HNS использует платформу виртуальной фильтрации (VFP) для создания политики, которая включает балансировку нагрузки, списки управления доступом и инкапсуляцию. Дополнительные сведения об API-интерфейсах HNS и схеме см. в разделе API службы HCN для виртуальных машин и контейнеров.
Policy Creation
- For the default network address translation (NAT) network, HNS creates the WinNAT port forwarding rules and mappings with the corresponding Windows Firewall ALLOW rules.
- For all other networks, HNS utilizes the Virtual Filtering Platform (VFP) for policy creation which includes load balancing, ACLs, and encapsulation. For more information on HNS APIs and the schema, see Host Compute Network (HCN) service API for VMs and containers.
Unsupported features and network options
The following networking options are currently NOT supported on Windows:
Обратитесь к сети контейнеров Docker , чтобы ознакомиться с общими командами, параметрами и синтаксисом Docker. За исключением случаев, описанных в неподдерживаемых функциях и параметрах сети, все сетевые команды Docker поддерживаются в Windows с тем же синтаксисом, что и в Linux. Однако сетевые стеки Windows и Linux отличаются, поэтому некоторые сетевые команды Linux (например, ifconfig) не поддерживаются в Windows.
Объединение контейнеров с помощью virtual network switch (bridge)
Вся идея контейнеризации сводится к эффективному совместному использованию ресурсов. То есть мы крайне редко запускаем на хосте единственный контейнер. Вместо этого стараемся запустить как можно больше изолированных процессов на одном хосте. Итак, чтобы произошло, если бы мы разместили несколько контейнеров на одном хосте, следуя описанному выше подходу? Добавим второй контейнер:
Что-то пошло не так. По какой-то причине мы не можем подключиться из netns1 к root namespace . А из root namespace мы не можем подключиться к netns1. Однако, поскольку оба контейнера находятся в одной IP-сети 172.18.0.0/16 , есть доступ к veth1 хоста из контейнера netns0 . Интересно.
Возможно, мы столкнулись с конфликтом маршрутов. Давайте проверим таблицу маршрутизации в root namespace :
После добавления второй пары veth в таблице маршрутизации root namespace появился новый маршрут 172.18.0.0/16 dev veth1 proto kernel scope link src 172.18.0.21 , но маршрут до этой подсети уже существовал! Когда второй контейнер пытается проверить связь с устройством veth1 , используется первый маршрут и мы видим ошибку подключения. Если бы мы удалили первый маршрут sudo ip route delete 172.18.0.0/16 dev veth0 proto kernel scope link src 172.18.0.11 и перепроверили подключение, то увидели бы обратную ситуацию, то есть подключение netns1 будет восстановлено, но netns0 останется в подвешенном состоянии.
Пожалуй, если бы мы выбрали другую подсеть для netns1 , все бы заработало. Однако наличие нескольких контейнеров в одной подсети является допустимым вариантом применения. Попробуем разобраться .
Рассмотрим Linux Bridge - еще один виртуализированный сетевой объект! Linux Bridge ведёт себя как коммутатор. Он пересылает пакеты между подключенными к нему интерфейсами. А поскольку это коммутатор, то он работает на уровне L2 (то есть Ethernet).
Чтобы предыдущие этапы нашего эксперимента в дальнейшем не вносили путаницы, удалим существующие сетевые пространства имён:
Заново создаём два контейнера. Обратите внимание, мы не назначаем IP-адреса новым устройствам veth0 и veth1 :
Убедимся, что на хосте нет новых маршрутов:
И, наконец, создадим bridge интерфейс:
Теперь подключим к нему veth0 и veth1 :
. и проверим возможность подключения между контейнерами:
Прекрасно! Все отлично работает. При этом мы даже не настраивали интерфейсы veth0 и veth1 . Мы назначили только два IP-адреса интерфейсам ceth0 и ceth1. Но поскольку они оба находятся в одном сегменте Ethernet (подключены к виртуальному коммутатору), существует возможность подключения на уровне L2:
Поздравляем, мы узнали, как превратить контейнеры в дружественных соседей, избежать проблем и сохранить сетевую связность.
Быстро попробовать CNI
«Потрогать руками» CNI можно и без контейнеров. Для этого достаточно загрузить себе файлы из репозитория проекта (и, по желанию, нужных плагинов), собрать их с ./build.sh (или скачать уже бинарную сборку), после чего — воспользоваться исполняемым файлом плагина (например, ./bin/bridge ), передав ему необходимые для функционирования аргументы через переменные окружения CNI_* , а сетевую конфигурацию — прямо JSON-данными через STDIN (так предусмотрено в спецификации CNI).
Подробности о таком эксперименте можно найти в этой статье, автор которой делает приблизительно следующее (на хосте в Ubuntu):
Дополнительные примеры для быстрого запуска CNI и сетевых плагинов представлены в README проекта (раздел «How do I use CNI?»).
С чего начать?
Все примеры в статье были сделаны на виртуальной машине CentOS 8. Но вы можете выбрать тот дистрибутив, который вам нравится.
Создадим виртуальную машину с помощью Vagrant и подключимся к ней по SSH:
Мы не будем использовать какое-либо популярное решение для контейнеризации (например, docker или podman). Вместо этого мы сосредоточимся на основных концепциях и воспользуемся минимальным набором инструментов для достижения наших учебных целей.
Container Network Management with Host Network Service
The Host Networking Service (HNS) and the Host Compute Service (HCS) work together to create containers and attach endpoints to a network. You can interact with HNS through the HNS Powershell Helper Module.
Указание имени сети для службы HNS
Применимо ко всем сетевым драйверам
Сети и rootless контейнеры
Одной из приятных особенностей диспетчера контейнеров podman является его ориентация на rootless контейнеры. Однако, как вы, вероятно, заметили, в этой статье мы использовали много эскалаций sudo и без root-прав настроить сеть невозможно. При настройке сетей rootful контейнеров Podman очень близок к Docker. Но когда дело доходит до rootless контейнеров, Podman полагается на проект slirp4netns:
Начиная с Linux 3.8, непривилегированные пользователи могут создавать network_namespaces (7) вместе с user_namespaces (7). Однако непривилегированные сетевые пространства имен оказались не очень полезными, потому что для создания пар veth (4) в пространствах имен хоста и сети по-прежнему требуются привилегии root (иначе доступ в Интернету будет отсутствовать).
slirp4netns позволяет получить доступ из сетевое пространства имен в Интернет непривилегированным пользователям, подключая устройство TAP в сетевом пространстве имен к стеку TCP/IP usermode («slirp»).
Сеть rootless контейнера весьма ограничена: «технически сам контейнер не имеет IP-адреса, потому что без привилегий root невозможно настроить сетевое устройство. Более того, проверка связи (ping) из rootless контейнера не работает, поскольку в нем отсутствует функция безопасности CAP_NET_RAW, которая необходима для работы команды ping.
Изоляция контейнеров с помощью Network namespaces
Что составляет сетевой стек Linux? Ну, очевидно, набор сетевых устройств. Что еще? Набор правил маршрутизации. И не забываем про настройку netfilter, создадим необходимые правила iptables.
Напишем небольшой скрипт inspect-net-stack.sh :
Но прежде, чем запускать его, давайте внесём изменения в правила iptables, чтобы идентифицировать их в дальнейшем:
Обратите внимание на текущий результат работы скрипта, потому что мы хотим быть уверены, что каждый из контейнеров, которые мы собираемся создать в ближайшее время, получит отдельный сетевой стек.
Мы уже упоминали об одном из Linux namespaces, используемых для изоляции контейнеров, которое называет сетевое пространство имён (Network namespace). Если заглянуть в man ip-netns , то мы прочтём, что «Network namespace логически является копией сетевого стека со своими собственными маршрутами, правилами брандмауэра и сетевыми устройствами». Мы не будем затрагивать другие Linux namespaces в этой статье и ограничимся только областью видимости сетевого стека.
Для создания Network namespace нам достаточно утилиты ip , которая входим в популярный пакет iproute2 . Создадим новое сетевое пространство имён:
Новое сетевое пространство имён создано, но как начать его использовать? Воспользуемся командой Linux под названием nsenter . Она осуществляет вход в одно или несколько указанных пространств имен, а затем выполняет в нём указанную программу:
Приведённый выше пример показывает, что процесс bash, работающий внутри пространства имён netns0 , видит совершенно другой сетевой стек. Отсутствуют правила маршрутизации, и правила iptables, есть только один loopback interface. Все идет по плану.
Устройство CNI
Авторы CNI пошли путём создания минимально возможной спецификации, предназначение которой — стать лёгкой прослойкой между исполняемой средой контейнера и плагинами. Все необходимые сетевые функции реализуются именно в плагинах, взаимодействие с которыми определено схемой в формате JSON.
CNI состоит из трёх частей:
1. Спецификации (см. GitHub), определяющей API между исполняемой средой контейнера и сетевыми плагинами: обязательные поддерживаемые операции (добавление контейнера в сеть и удаление его оттуда), список параметров, формат конфигурации сети и их списков (хранятся в JSON), а также известных структур (IP-адресов, маршрутов, DNS-серверов).
Пример конфигурации сети в CNI:
2. Официальных плагинов, предоставляющих сетевые конфигурации для разных ситуаций и служащих примером соответствия спецификации CNI. Они доступны в containernetworking/plugins и разбиты на 4 категории: main (loopback, bridge, ptp, vlan, ipvlan, macvlan), ipam (dhcp, host-local), meta (flannel, tuning), sample. Все написаны на Go. (Про сторонние плагины см. в следующем разделе статьи.)
3. Библиотеки (libcni), предлагающей реализацию спецификации CNI (тоже на языке Go) для удобного использования в исполняемых средах контейнеров.
Весь имеющийся код (и спецификация) опубликованы под свободной лицензией Apache License v2.0.
Подключаем контейнер к хосту через virtual Ethernet devices (veth)
Выделенный сетевой стек будет бесполезен, если к нему отсутствует доступ. К счастью, Linux предоставляет подходящее средство для этого - virtual Ethernet devices (veth)! Согласно man veth , «veth-device - это виртуальные устройства Ethernet. Они работают как туннели между сетевыми пространствами имён для создания моста к физическому сетевому устройству в другом пространстве имён, а также могут использоваться как автономные сетевые устройства».
Виртуальные Ethernet устройства всегда работают парами. Создадим их прямо сейчас:
С помощью этой единственной команды мы только что создали пару взаимосвязанных виртуальных Ethernet устройств. Имена veth0 и ceth0 были выбраны произвольно:
И veth0 , и ceth0 после создания находятся в сетевом стеке хоста (также называемом Root Network namespace). Чтобы связать корневое пространство имён с пространством имён netns0 , нам нужно сохранить одно из устройств в корневом пространстве имён и переместить другое в netns0 :
Как только мы включаем устройства и назначаем правильные IP-адреса, любой пакет, происходящий на одном из них, немедленно появляется на его одноранговом устройстве, соединяющем два пространства имён. Начнем с корневого пространства имён:
Продолжим с netns0 :
Обратите внимание, если мы попытаемся проверить доступность любых других адресов из пространства имен netns0, у нас ничего не получится:
Для таких пакетов в таблице маршрутизации netns0 просто нет маршрута. В настоящий момент существует единственный маршрут до сети 172.18.0.0/16:
В Linux есть несколько способов заполнения таблицы маршрутизации. Один из них - извлечение маршрутов из подключенных напрямую сетевых интерфейсов. Помните, что таблица маршрутизации в netns0 была пустой сразу после создания пространства имен. Но затем мы добавили туда устройство ceth0 и присвоили ему IP-адрес 172.18.0.10/16 . Поскольку мы использовали не простой IP-адрес, а комбинацию адреса и сетевой маски, сетевому стеку удалось извлечь из него информацию о маршрутизации. Каждый пакет, предназначенный для сети 172.18.0.0/16 , будет отправлен через устройство ceth0 . Но все остальные пакеты будут отброшены. Точно так же есть новый маршрут в корневом пространстве имен:
На этом этапе мы ответили на первый вопрос. Теперь мы знаем, как изолировать, виртуализировать и подключать сетевые стеки Linux.
Разбираемся в работе Docker network drivers
Но что же вам сделать теперь со всеми этими бесполезными знаниями? Например, мы могли бы попытаться разобраться в некоторых сетевых режимах Docker!
Начнем с режима --network host . Попробуйте сравнить вывод следующих команд ip link и sudo docker run -it --rm --network host alpine ip link . Сюрприз, они совпадут! Таким образом host mode Docker просто не использует изоляцию сетевого пространства имён и контейнеры работают в корневом сетевом пространстве имён и совместно используют сетевой стек с хост-системой.
Следующий режим, который нужно проверить, - это --network none . Вывод команды sudo docker run -it --rm --network none alpine ip link показывает только один сетевой интерфейс обратной loopback. Это очень похоже на наши наблюдения за только что созданным сетевым пространством имен. То есть до того момента, когда мы добавляли какие-либо veth устройства.
И последнее, но не менее важное: режим --network bridge (по умолчанию), это именно то, что мы пытались воспроизвести в этой статье.
Сторонние плагины для CNI
Одной из главных ценностей CNI, конечно же, являются сторонние плагины, обеспечивающие поддержку различных современных решений для Linux-контейнеров. Среди них:
- Project Calico (виртуальная сеть L3, интегрированная с инструментами оркестровки и облачными платформами);
- Weave (простая сеть для multi-host Docker-инсталляций);
- Contiv Netplugin (политики/ACL/QoS и другие возможности для контейнеров в кластерных установках типа multi-host);
- Flannel (сетевая фабрика для контейнеров от CoreOS);
- SR-IOV, Cilium (BPF/XDP), Multus (плагин Multi для Kubernetes от Intel), VMware NSX и другие…
Дополнительным индикатором зрелости проекта является его интеграция в существующие исполняемые среды для контейнеров: rkt и Kurma, — и платформы для работы с контейнерами: Kubernetes, OpenShift, Cloud Foundry, Mesos.
Указание суффикса DNS и DNS-серверов сети
Применимо ко всем сетевым драйверам
Дополнительные сведения см. в этой статье.
Настроим сетевой доступ из внешнего мира в контейнеры (port publishing)
Публикация портов контейнеров для некоторых (или всех) интерфейсов хоста - популярная практика. Но что на самом деле означает публикация порта?
Представьте, что у нас есть сервис, работающий внутри контейнера:
Однако, если бы мы получили доступ к этому серверу из внешнего мира, какой IP-адрес мы бы использовали? Единственный IP-адрес, который мы можем знать, - это адрес внешнего интерфейса хоста eth0 :
Кроме того, нам нужно включить iptables intercepting traffic over bridged networks (перехватывать трафик bridged networks):
Базовая сетевая архитектура
В этом разделе приведено описание того, каким образом Docker создает и администрирует сети узлов в Windows. В отношении сетевых подключений контейнеры Windows функционируют аналогично виртуальным машинам. У каждого контейнера есть виртуальный сетевой адаптер (vNIC), который подключен к виртуальному коммутатору Hyper-V (vSwitch). Операционная система Windows поддерживает пять различных сетевых драйверов (или по-другому "режимов"), которые можно создать через Docker: nat, overlay, transparent, l2bridge и l2tunnel. В зависимости от особенностей физической сетевой инфраструктуры и от того, должна ли сеть быть одно- или многоузловой, необходимо выбрать сетевой драйвер, который наилучшим образом соответствует вашим потребностям.
При первом запуске подсистемы Docker создается сеть NAT по умолчанию NAT, которая использует внутренний vSwitch и компонент Windows с именем WinNAT . При наличии на узле других внешних виртуальных коммутаторов, созданных с помощью оболочки командной строки PowerShell или диспетчера Hyper-V, они также будут доступны подсистеме Docker посредством сетевого драйвера transparent и будут отображаться при запуске команды docker network ls .
- Внутренний виртуальный коммутатор — это тот, который не подключен напрямую к сетевому адаптеру на узле контейнера.
- Внешний виртуальный коммутатор — это тот, который напрямую подключен к сетевому адаптеру на узле контейнера.
Сеть "nat" — это сеть по умолчанию для контейнеров под управлением Windows. Все контейнеры, которые работают под управлением Windows без каких-либо флагов или аргументов, использующихся для реализации конкретной сетевой конфигурации, будут подключены к сети "nat" по умолчанию и им будет автоматически присвоен IP-адрес из диапазона IP-адресов внутреннего префикса сети "nat". Для "nat" по умолчанию используется следующий внутренний префикс IP-адреса: 172.16.0.0/16.
Создание конечных точек
- Служба HNS создает пространство имен сети для каждой конечной точки контейнера
- Служба HNS/HCS размещает сетевой адаптер виртуальной машины в пространстве имен сети
- Служба HNS создает порты виртуального коммутатора
- Служба HNS назначает конечной точке IP-адрес, сведения DNS, маршруты и т. д. (в зависимости от сетевого режима)
Советы и полезные рекомендации
Ниже приведен список полезных советов и рекомендаций, составленный на основе стандартных вопросов о сетевых подключениях контейнеров Windows, которые задают участники сообщества.
Для работы службы HNS требуется включить IPv6 на хост-машинах контейнеров
В рамках обновления KB4015217 для работы службы HNS требуется включить IPv6 на узлах контейнеров Windows. При возникновении описанной ниже ошибки есть вероятность, что протокол IPv6 отключен на хост-компьютере.
Мы вносим соответствующие изменения в платформу, чтобы эту проблему можно было автоматически обнаружить/предотвратить. В настоящее время, чтобы убедиться, что на хост-компьютере включен протокол IPv6, можно воспользоваться представленным ниже способом.
Контейнеры Linux в Windows
НОВОЕ. Мы работаем над возможностью параллельного запуска контейнеров Linux и Windows без помощи виртуальной машины Linux Moby. Подробные сведения см. в этой записи блога о контейнерах Linux в Windows (LCOW). Вот как приступить к работе.
ПРИМЕЧАНИЕ. Решение LCOW приходит на замену виртуальной машине Linux Moby и будет использовать внутренний виртуальный коммутатор "nat" службы HNS по умолчанию.
Виртуальные машины Moby Linux используют коммутатор DockerNAT с Docker для Windows (продукт Docker CE)
Docker для Windows (драйвер Windows для подсистемы Docker CE) в Windows 10 использует внутренний виртуальный коммутатор под названием DockerNAT для подключения виртуальных машин Linux Moby к узлу контейнера. Разработчикам, использующим виртуальные машины Linux Moby в Windows, следует иметь в виду, что их узлы будут использовать виртуальный коммутатор DockerNAT вместо виртуального коммутатора "nat", созданного с помощью службы HNS (который является коммутатором по умолчанию, используемым для контейнеров Windows).
Чтобы для присвоения IP-адресов на виртуальном узле контейнеров можно было использовать протокол DHCP, необходимо активировать MACAddressSpoofing
Если узел контейнера виртуализирован и вы хотите использовать DHCP для назначения IP-адресов, необходимо включить MACAddressSpoofing на сетевом адаптере виртуальных машин. В противном случае узел Hyper-V будет блокировать сетевой трафик от контейнеров к виртуальной машине с несколькими MAC-адресами. Активировать MACAddressSpoofing в PowerShell можно с помощью следующей команды.
Если вы используете VMware в качестве гипервизора, вам необходимо включить неизбирательный режим. Подробнее см. здесь.
Создание нескольких прозрачных сетей на одном узле контейнера
Чтобы создать несколько прозрачных сетей, необходимо указать, к какому сетевому адаптеру (виртуальному) должен быть привязан внешний виртуальный коммутатор Hyper-V. Чтобы задать интерфейс для сети, используйте следующий синтаксис.
При выполнении статического назначения IP-адресов не забудьте задать параметры --subnet и --gateway
При статическом назначении IP-адресов необходимо сначала убедиться, что при создании сети указаны параметры --subnet и --gateway. IP-адрес подсети и шлюза должен совпадать с IP-адресом, указанным в параметрах сети для контейнера узла, т. е. физической сети. Ниже показано, как можно создать прозрачную сеть, а затем запустить в этой сети конечную точку, используя статическое назначение IP-адресов.
Назначение IP-адресов по протоколу DHCP не поддерживается для сетей L2Bridge
Для сетей контейнеров, созданных с помощью драйвера "l2bridge", поддерживается только статичное назначение IP-адресов. Как упоминалось выше, не забудьте задать параметры --subnet и --gateway для создания сети, которая подходит для статического назначения IP-адресов.
У сетей, в которых используется внешний виртуальный коммутатор, должен быть собственный сетевой адаптер
Обратите внимание, что если создание нескольких сетей, использующих внешний виртуальный коммутатор для подключения (например сетей Transparent, L2 Bridge, L2 Transparent) выполняется на одном узле контейнера, для каждой из них потребуется собственный сетевой адаптер.
Назначение IP-адресов: остановленные и запущенные контейнеры
Назначение статических IP-адресов выполняется непосредственно на сетевом адаптере контейнера и должно осуществляться, только когда контейнер находится в ОСТАНОВЛЕННОМ состоянии. "Горячее добавление" сетевых адаптеров контейнера или внесение изменений в сетевой стек не поддерживаются (в Windows Server 2016) во время выполнения контейнера.
Уже имеющийся виртуальный коммутатор (подсистема Docker его не видит) может блокировать создание прозрачный сети
Если при создании прозрачной сети возникнет ошибка, возможно, в системе есть внешний виртуальный коммутатор, который не был автоматически обнаружен Docker и не позволяет привязать прозрачную сеть к внешнему сетевому адаптеру узла контейнера.
При создании прозрачной сети Docker создает внешний виртуальный коммутатор для сети, а затем пытается привязать коммутатор к (внешнему) сетевому адаптеру. Адаптер может быть сетевым адаптером VM или физическим сетевым адаптером. Если виртуальный коммутатор уже создан на узле контейнера и видим Docker, подсистема Windows Docker будет использовать этот коммутатор, а не создавать новый. Но если виртуальный коммутатор создан внешними средствами (например, создан на узле контейнера при помощи диспетчера Hyper-V или PowerShell) и еще не виден Docker, подсистема Windows Docker попытается создать виртуальный коммутатор, после чего она не сможет подключить новый коммутатор к внешнему адаптеру сети узла контейнера (так как сетевой адаптер уже будет подключен к коммутатору, созданному внешними средствами).
Например, эта проблема может возникнуть, если вы сначала создали виртуальный коммутатор на узле, когда служба Docker была запущена, после чего попытались создать прозрачную сеть. В этом случае Docker не распознает созданный коммутатор и создаст новый виртуальный коммутатор для прозрачной сети.
Существует три подхода к решению этой проблемы.
- Вы можете удалить виртуальный коммутатор, созданный внешними средствами, что позволит Docker создать новый виртуальный коммутатор и подключить его к сетевому адаптеру узла без проблем. Перед тем как выбрать этот подход убедитесь, что виртуальный коммутатор, созданный внешними средствами, не используется другими службами (например, Hyper-V).
- Кроме того, если вы захотите использовать внешний виртуальный коммутатор, созданный внешними средствами, перезапустите службы Docker и HNS, чтобы коммутатор стал видим Docker.
- Другой вариант — использовать "-o com.docker.network.windowsshim.interface1", чтобы привязать внешний виртуальный коммутатор прозрачной сети к определенному сетевому адаптеру, который еще не используется в узле контейнера (например, сетевой адаптер, отличный от используемого виртуальным коммутатором, созданным внешними средствами). Параметр "-o" описан далее в разделе Создание нескольких прозрачных сетей в одном узле контейнера этого документа.
Указание политики Аутбаунднат для сети
Если существует набор назначений (например, требуется подключение контейнера к контейнеру), в котором мы не хотим Нат'инг, необходимо также указать список исключений:
Endpoint Creation
- HNS creates network namespace per container endpoint
- HNS/HCS places v(m)NIC inside network namespace
- HNS creates (vSwitch) ports
- HNS assigns IP address, DNS information, routes, etc. (subject to networking mode) to the endpoint
Неподдерживаемые функции и сетевые параметры
В Windows сейчас не поддерживаются следующие сетевые параметры:
Ряд параметров сетевых драйверов позволяет воспользоваться преимуществами особых возможностей Windows.
Несколько сетей NAT на узле контейнера WS2016
Разделы для новых сетей NAT должны быть созданы в префиксе более крупной внутренней сети NAT. Чтобы найти префикс, запустите следующую команду из PowerShell со ссылкой на поле InternalIPInterfaceAddressPrefix.
Например, внутренний префикс сети NAT узла может быть 172.16.0.0/16. В этом случае DOCKER можно использовать для создания дополнительных сетей NAT, если они являются подмножеством префикса 172.16.0.0/16. Например, можно создать две сети NAT с префиксами IP 172.16.1.0/24 (шлюз, 172.16.1.1) и 172.16.2.0/24 (шлюз, 172.16.2.1).
Созданные сети можно перечислить при помощи следующих элементов.
С чего начать?
Все примеры в статье были сделаны на виртуальной машине CentOS 8. Но вы можете выбрать тот дистрибутив, который вам нравится.
Создадим виртуальную машину с помощью Vagrant и подключимся к ней по SSH:
Мы не будем использовать какое-либо популярное решение для контейнеризации (например, docker или podman). Вместо этого мы сосредоточимся на основных концепциях и воспользуемся минимальным набором инструментов для достижения наших учебных целей.
Установка идентификатора виртуальной сети для сети
Применимо к сетевым драйверам "transparent" и "l2bridge"
Когда вы настраиваете идентификатор VLAN для сети, вы настраиваете изоляцию VLAN для любых конечных точек контейнера, которые будут присоединены к этой сети.
Убедитесь, что сетевой адаптер узла (физический) находится в магистральном режиме, чтобы весь помеченный трафик обрабатывался виртуальным коммутатором с портом vNIC (конечной точки контейнера) в режиме доступа в нужной сети VLAN.
Привязка сети к определенному сетевому интерфейсу
Применимо ко всем сетевым драйверам, за исключением "nat"
Docker Compose
Docker Compose можно использовать для определения и настройки сетей контейнера вместе с контейнерами и службами, которые будут использовать эти сети. Ключ "networks" Compose используется как ключ верхнего уровня при определении сетей, к которым будут подключены контейнеры. Например, в синтаксисе ниже определена существующая сеть NAT, создаваемая Docker в качестве сети по умолчанию для всех контейнеров и служб, определенных в указанном файле Compose.
Аналогично можно использовать следующий синтаксис для определения пользовательской сети NAT.
Примечание. Пользовательская сеть NAT, указанная в примере ниже, определена как раздел внутреннего префикса существующей сети NAT узла контейнера. Дополнительные сведения см. в разделе выше, "Несколько сетей NAT".
Более подробная информация об определении и настройке сетей контейнера при помощи Docker Compose см. в справочнике по файлам Compose.
На прошлой неделе фонд CNCF (Cloud Native Computing Foundation) объявил о принятии под своё крыло 10-го Open Source-проекта — CNI (Container Networking Interface). Его задача — обеспечить всё необходимое для стандартизированного управления сетевыми интерфейсами в Linux-контейнерах и гибкого расширения сетевых возможностей. В CNCF объяснили необходимость такого проекта активным распространением контейнеризированных приложений в мире production и утверждают, что «подобно тому, как Kubernetes позволяет разработчикам массово запускать контейнеры на тысячах машинах, этим контейнерам в больших масштабах требуется сетевое управление [и реализующий его фреймворк]».
Как же появился CNI и что он предлагает?
Управление сетью контейнера с помощью сетевой службы узлов
Сетевая служба узлов (HNS) и вычислительная служба узлов (HCS) совместно используются для создания контейнеров и подключения конечных точек к сети. Вы можете взаимодействовать с HNS с помощью вспомогательного модуля PowerShell HNS.
Объединение внедренных коммутаторов с сетями Docker
Применимо ко всем сетевым драйверам
Заключение
Рассмотренный в этой статье подход к организации сети контейнеров является лишь одним из возможных (ну, пожалуй, наиболее широко используемым). Есть еще много других способов, реализованных через официальные или сторонние плагины, но все они сильно зависят от средств виртуализации сети Linux. Таким образом, контейнеризацию по праву можно рассматривать как технологию виртуализации.
Please reference Docker Container Networking for general Docker networking commands, options, and syntax. With the exception of any cases described in unsupported features and network options, all Docker networking commands are supported on Windows with the same syntax as on Linux. However, the Windows and Linux network stacks are different, and as such you will find that some Linux network commands (for example, ifconfig) are not supported on Windows.
Basic networking architecture
This topic provides an overview of how Docker creates and manages host networks on Windows. Windows containers function similarly to virtual machines in regards to networking. Each container has a virtual network adapter (vNIC) which is connected to a Hyper-V virtual switch (vSwitch). Windows supports five different networking drivers or modes which can be created through Docker: nat, overlay, transparent, l2bridge, and l2tunnel. Depending on your physical network infrastructure and single- vs multi-host networking requirements, you should choose the network driver which best suits your needs.
The first time the Docker engine runs, it will create a default NAT network, 'nat', which uses an internal vSwitch and a Windows component named WinNAT . If there are any pre-existing external vSwitches on the host which were created through PowerShell or Hyper-V Manager, they will also be available to Docker using the transparent network driver and can be seen when you run the docker network ls command.
- An internal vSwitch is one that isn't directly connected to a network adapter on the container host.
- An external vSwitch is one that is directly connected to a network adapter on the container host.
The 'nat' network is the default network for containers running on Windows. Any containers that are run on Windows without any flags or arguments to implement specific network configurations will be attached to the default 'nat' network, and automatically assigned an IP address from the 'nat' network's internal prefix IP range. The default internal IP prefix used for 'nat' is 172.16.0.0/16.
Network Creation
- HNS creates a Hyper-V virtual switch for each network
- HNS creates NAT and IP pools as required
Настраиваем сетевой доступ из контейнера во внешний мир (IP routing and masquerading)
Сейчас контейнеры могут подключаться друг к другу. Но будут ли удачны подключения к хосту, то есть к корневому пространству имён?
Интерфейс eth0 не доступен. Всё очевидно, в netns0 отсутствует маршрут для этого подключения:
Корневое пространство имён также не может взаимодействовать с контейнерами:
Чтобы установить связь между корневым пространством имён и пространством имён контейнера, нам нужно назначить IP-адрес сетевому интерфейсу моста:
Теперь после того, как мы назначили IP-адрес интерфейсу моста, мы получили маршрут в таблице маршрутизации хоста:
Контейнер, вероятно, также получил возможность пинговать интерфейс моста, но они все ещё не могут связаться с хостом eth0 . Нам нужно добавить маршрут по умолчанию для контейнеров:
Теперь наш хост является маршрутизатором, а интерфейс моста стал шлюзом по умолчанию для контейнеров.
Отлично, нам удалось добиться сетевой связности контейнеров с корневым пространством имён. Теперь давайте попробуем подключить их к внешнему миру. По умолчанию переадресация пакетов (ip packet forwarding), то есть функциональность маршрутизатора в Linux отключена. Нам нужно её включить
Теперь самое интересное - проверка подключения:
Команда довольно проста. Мы добавляем новое правило в таблицу nat цепочки POSTROUTING с просьбой выполнить MASQUERADE всех исходящих пакетов из сети 172.18.0.0/16 , но не через интерфейс моста.
Помните, что политика iptables по умолчанию - ACCEPT для каждой цепочки, она может быть довольно опасной в реальных условиях:
В качестве хорошего примера Docker вместо этого ограничивает все по умолчанию, а затем разрешает только для известных маршрутов:
Создание сети
- Служба HNS создает виртуальный коммутатор Hyper-V для каждой сети
- Служба HNS создает преобразование сетевых адресов (NAT) и пулы IP-адресов по мере необходимости
Заключение
Текущий статус CNI позволяет уже сейчас говорить не только о «больших перспективах» проекта, но и ощутимых реалиях его практической применимости. Принятие в CNCF — официальное признание индустрией и гарантия для дальнейшего развития. А всё это означает, что самое время как минимум узнать про CNI, с которым скорее всего рано или поздно придётся встретиться.
Обходные пути известных проблем в Windows Server 2016
Несмотря на то что мы продолжаем разрабатывать и добавлять новые функции, некоторые из них не будут перенесены на платформы предыдущих версий. Поэтому в этом случае пользователям лучше всего получить последние обновления для Windows 10 и Windows Server. В разделе ниже перечислены некоторые способы обхода известных проблем и оговорки, применимые к Windows Server 2016 и более ранним версиям Windows 10 (т. е. к версиям до обновления Creators Update 1704)
Читайте также: