2.5. Сеть на виртуальной машине или в Docker¶
Возможные ограничения¶
Внимание
По причине слишком большого числа решений по виртуализации ОС и сетевых подсистем, работа зонда под виртуальными машинами не тестируется и не гарантируется.
Работа зонда на виртуальной машине принципиально не отличается от работы зонда на физической машине. Однако необходимо принимать во внимание, что абстракции над физическими устройствами могут приводить к недостаточной производительности гостевой системы. Данный факт может вызвать следующие потенциальные проблемы в работе зонда:
Снижение максимального трафика, который принимается без потерь пакетов;
Искажение измерений таймингов http-подключений в сторону увеличения показателей;
Измерения, связанные с работой библиотеки pcap, могут быть недостоверными: Ethernet-параметры IAT и MLR, задачи на базе сниффинга потоков и записи pcap;
Зонд не может использовать аппаратные метки времени при приёме Ethernet-пакетов.
Чтобы избежать указанных проблем, следует отказаться от работы через виртуальные интерфейсы (по крайней мере, при мониторинге протоколов на базе UDP/IPTV). В данной главе описано, как снизить уровень абстракции сетевых устройств в виртуальных машинах и в Docker-контейнерах.
Сети на виртуальных машинах¶
PCI Passthrough¶
Для виртуальных машин существует технология PCI passthrough, которая позволяет получить прямой доступ к физическому PCI-устройству, например, к сетевому адаптеру. Такое решение предоставляет более высокую производительность работы с сетью, так как адаптер устанавливается в гостевую систему под управлением полноценного драйвера.
Обязательные требования:
Аппаратная поддержка: CPU должен поддерживать технологию IOMMU (Intel VT-d или AMD-Vi), которую также необходимо включить в BIOS/UEFI.
Поддержка в ядре Linux: ядро хост-системы должно быть собрано с поддержкой IOMMU.
Драйвер VFIO: хост-система должна содержать драйвер vfio-pci. В момент запуска гостевой системы драйвер vfio-pci назначается физическому устройству в хост-системе вместо системного.
ID необходимого PCI устройства можно найти через утилиту lspci:
[root@localhost ~]# lspci -nn
...
00:1f.5 Serial bus controller [0c80]: Intel Corporation Tiger Lake-H SPI Controller [8086:43a4] (rev 11)
00:1f.6 Ethernet controller [0200]: Intel Corporation Ethernet Connection (14) I219-V [8086:15fa] (rev 11)
01:00.0 Ethernet controller [0200]: Intel Corporation 82574L Gigabit Network Connection [8086:10d3]
Рассмотрим простой пример проброса сетевого адаптера в приложении Virtual Machine Manager GUI
Двойным кликом на виртуальной машине откройте окно ее свойств и перейдите на вкладку Show virtual hardware details. Нажмите кнопку Add Hardware внизу окна.
В меню доступных устройств кликните опцию PCI Host Device.
В раскрывшемся списке выберите необходимый адаптер и нажмите кнопку Finish. В описании адаптера присутствует ID PCI-устройства и может отображаться имя интерфейса в хост-системе.
Если виртуальная машина была запущена, перезапустите её, чтобы изменения применились корректно.
После старта виртуальной машины сетевой адаптер должен получить системный драйвер в гостевой системе:
[root@localhost ~]# lspci -k
...
07:00.0 Ethernet controller: Intel Corporation 82574L Gigabit Network Connection
Subsystem: Intel Corporation Gigabit CT Desktop Adapter
Kernel driver in use: e1000e
Kernel modules: e1000e
A на хост-системе драйвер изменится на vfio-pci:
[root@localhost ~]# lspci -k
...
01:00.0 Ethernet controller: Intel Corporation 82574L Gigabit Network Connection
Subsystem: Intel Corporation Gigabit CT Desktop Adapter
Kernel driver in use: vfio-pci
Kernel modules: e1000e
Для достижения максимальной производительности проверьте, что в гостевой системе включена балансировка прерываний адаптера.
SR-IOV Virtual Functions¶
Примечание
В рамках данного раздела приводится только описание технологии. Обратитесь к документации вашего дистрибутива и гипервизора.
Следует также упомянуть, что существуют технология виртуализации SR-IOV (Single Root I/O Virtualization), которая позволяет одному физическому устройству PCI представлять себя как множество отдельных устройств. SR-IOV чаще всего используется для виртуализации сетевых адаптеров, где физический адаптер делится на множество виртуальных, доступных VM напрямую. Это повышает производительность сетевой подсистемы в виртуальных средах, поскольку виртуальные машины получают прямой доступ к аппаратным ресурсам, минуя эмуляцию гипервизором.
Обязательные требования:
Аппаратная поддержка CPU: CPU должен поддерживать технологию IOMMU (Intel VT-d или AMD-Vi), которую также необходимо включить в BIOS/UEFI.
Аппаратная поддержка NIC: сетевой адаптер должен поддерживать технологию SR-IOV Virtual Functions, которую также необходимо включить в BIOS/UEFI. Эта настройка может быть как глобальной, так и привязанной к конкретному устройству.
Технология позволяет работать как с обычным, так и с тегированным трафиком в физическом порту.
Сети в Docker¶
Примечание
На момент написания раздела Boro-зонд не распространялся в формате Docker. Данная статья дает лишь рекомендации по управлению сетевым стеком Docker и не описывает создание образа, содержащего зонд.
Запуск зонда в контейнере не добавляет больших накладных расходов на CPU, особенно при использовании «легковесных» контейнеров. Однако контейнер по умолчанию используют сетевую изоляцию Network Address Translation (NAT), что вызывает следующие проблемы для зонда:
Без дополнительных настроек со стороны Docker зонд не может принимать мультикаст-потоки;
Также зонд не может быть приёмником юникаст-вещания (UDP unicast, SRT listener mode);
Ограничения в работе: пониженная производительность сети и возможные искажения при измерении Ethernet-параметров.
Если по какой-то причине вам необходимо запускать зонд в контейнере, то можно рассмотреть режимы работы сети host и macvlan, которые позволяют работать с сетевыми устройствами без абстракций.
Host Network Driver¶
В режиме host network сетевой стек Docker перестаёт быть изолированным от хост-системы (будет использован namespace хост-системы). Это означает, что все интерфейсы хост-системы становятся доступными для использования в контейнере. Следовательно, контейнер больше не получает собственный IP-адрес, а приложения будут привязываться к интерфейсам хост-системы.
Такой подход можно рекомендовать в случае запуска зонда на сервере под управлением дистрибутива Linux, который использует glibc старее версии, необходимой для зонда.
Ограничения¶
Режим работы сети
hostподдерживается только в Docker Engine на Linux;Не работает совместно с опцией Enhanced Container Isolation;
Docker Desktop должен быть не старее версии 4.34.
Команды¶
Создайте и запустите контейнер:
docker run \
--detach --interactive --tty \
--privileged \
--network host \
ubuntu:24.04
Флаги --detach --interactive --tty использованы для примера, чтобы контейнер оставался запущенным в фоновом режиме.
Для полноценной работы зонда необходимо повысить привилегии при запуске контейнера: для этого укажите флаг --privileged.
Таким образом, pcap-процесс зонда сможет измерять Ethernet-параметры и создавать pcap-записи.
Флаг --network host указывает на использование сети в режиме host.
Пример запуска зонда¶
Следующий пример запускает Boro-зонд в контейнере на основе образа ubuntu:24.04.
Особенностью примера является то, что приложение находится в файловой системе хост-машины:
docker run \
--detach --privileged --init \
--restart always \
--network host \
--volume /opt/elecard/boro/dev/:/opt/elecard/boro/dev:z \
--name 'probe_dev' \
ubuntu:24.04 \
/opt/elecard/boro/dev/streamMonitor
При перезагрузке ОС флаг --restart always указывает на необходимость запускать контейнер вне зависимости от его текущего состояния.
Строка --volume /opt/elecard/boro/dev/:/opt/elecard/boro/dev:z монтирует каталог с зондом в контейнер по указанному пути.
Такой подход позволяет сохранять записи и конфигурационные файлы зонда, если контейнер будет перезапущен.
Флаг --name 'probe_dev' задаёт имя контейнера.
Строка /opt/elecard/boro/dev/streamMonitor — полный путь к приложению зонда, которое будет запущено при старте контейнера.
Macvlan Network Driver¶
Драйвер macvlan network в Docker позволяет назначать уникальный MAC-адрес и IP-адрес для каждого контейнера, что позволяет подключать выделенный сетевой адаптер хост-машины непосредственно к контейнеру (без использования стандартного NAT-соединения). Необходимо отметить, что контейнеры сохраняют сетевую изоляцию на уровне L2 при использовании различных macvlan-сетей, а также образуется изоляция между контейнером и хост-системой.
Идея данного подхода хорошо подходит для запуска зонда, так как:
сохраняется изоляция контейнера;
зонду предоставляется выделенный сетевой адаптер для получения данных;
контейнер имеет прямой доступ к сетевому адаптеру.
Однако при всех плюсах такого решения возникает проблема соединения Boro-зонда с Boro-сервером. Описанная выше изоляция контейнер-хост не дает возможности соединения через сетевые подключения хост-машины. А использование macvlan-адаптера является нежелательным или даже недопустимым в некоторых сетях (управляющий трафик не должен смешиваться с анализируемым трафиком, особенно при мониторинге протоколов на базе UDP/IPTV). В этом случае Docker предоставляет возможность подключить вторую сеть в классическом режиме bridge, через который зонд может получить соединение с Интернетом или хост-машиной.
Чтобы pcap-процесс зонда мог измерять Ethernet-параметры и создавать pcap-записи, укажите флаг --privileged при запуске контейнера.
Ограничения¶
Режим работы сети
macvlanподдерживается только в Docker Engine на Linux;Как правило, облачные провайдеры блокируют macvlan;
Требуется версия ядра Linux не ниже 3.9. Рекомендуется использовать версию 4.0 и выше;
Macvlan не поддерживается в rootless-режиме.
Команды¶
Без указания IP
Запуск контейнера без указания параметров сети macvlan (в таком случае Docker самостоятельно сконфигурирует сеть, этого достаточно для приема мультикаста):
Создайте macvlan сеть:
docker network create -d macvlan \ -o parent=enp1s0 test_net
Параметр
-o parent=<iface>указывает родительский интерфейс на хост-машине, через который зонд будет получать данные для анализа.Создайте обычную сеть в режиме bridge для подключения Boro-зонда к Boro-серверу:
docker network create -d bridge server_bridge
Проверьте, что сети успешно создались:
[root@localhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE a08c4253f05d bridge bridge local 1cf9579b7bda host host local 3e29a74817b7 none null local b1a5271069ae server_bridge bridge local 1c7c2a831d63 test_net macvlan local
Создайте и запустите контейнер в фоновом режиме с использованием двух сетей:
--network test_net— macvlan для приема данных на анализ,--network server_bridge— bridge для коммуникации зонда с сервером:docker run \ --detach --interactive --tty \ --privileged \ --network test_net \ --network server_bridge \ ubuntu:24.04
Флаги
--detach --interactive --ttyиспользуются для примера, чтобы сохранять контейнер в запущенном состоянии в фоновом режиме.Найдите ID запущенного контейнера и проверьте состояние сети:
[root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0ec0537c0f40 ubuntu:24.04 "/bin/bash" 2 hours ago Up 2 hours relaxed_euler
[root@localhost ~]# docker container inspect 0ec0537c0f40 ... "Networks": { "server_bridge": { "MacAddress": "02:42:ac:13:00:02", "Gateway": "172.19.0.1", "IPAddress": "172.19.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, ... }, "test_net": { "MacAddress": "02:42:ac:12:00:02", "Gateway": "172.18.0.1", "IPAddress": "172.18.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, ... } }
Назначенный IP
Запуск контейнера с назначением IP-адреса для macvlan-сети:
Создайте macvlan-сеть:
docker network create -d macvlan \ --subnet=192.168.1.0/24 \ --gateway=192.168.1.1 \ -o parent=enp1s0 test_net
Задайте соответствующие вашей сети
subnetиgateway. Параметр-o parent=<iface>указывает родительский интерфейс на хост-машине, через который зонд будет получать данные для анализа.Создайте обычную сеть в режиме bridge для подключения Boro-зонда к Boro-серверу:
docker network create -d bridge server_bridge
Проверьте, что сети успешно создались:
[root@localhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE a08c4253f05d bridge bridge local 1cf9579b7bda host host local 3e29a74817b7 none null local 1d1a25aec471 server_bridge bridge local 606796c2d96d test_net macvlan local
Создайте и запустите контейнер в фоновом режиме с использованием двух сетей:
--network test_net— macvlan для приема данных на анализ,--network server_bridge— bridge для коммуникации зонда с сервером:docker run \ --detach --interactive --tty \ --privileged \ --network test_net --ip=192.168.1.111 \ --network server_bridge \ ubuntu:24.04
Флаги
--detach --interactive --ttyиспользуются для примера, чтобы сохранять контейнер в запущенном состоянии в фоновом режиме. Строка--network test_net --ip=192.168.1.111, помимо выбора сети, задает IP-адрес.Найдите ID запущенного контейнера и проверьте состояние сети:
[root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b31a36f1ffbe ubuntu:24.04 "/bin/bash" 1 hours ago Up 1 hours fervent_nightingale
[root@localhost ~]# docker container inspect b31a36f1ffbe ... "Networks": { "server_bridge": { "MacAddress": "02:42:ac:12:00:02", "Gateway": "172.18.0.1", "IPAddress": "172.18.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, ... }, "test_net": { "IPAMConfig": { "IPv4Address": "192.168.1.111" }, "MacAddress": "02:42:c0:a8:01:6f", "Gateway": "192.168.1.1", "IPAddress": "192.168.1.111", "IPPrefixLen": 24, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, ... } }
Диапазон IP
Запуск контейнера с указанием диапазона, из которого будет назначен IP-адрес для macvlan-сети:
Создайте macvlan-сеть:
docker network create -d macvlan \ --subnet=192.168.1.0/24 \ --gateway=192.168.1.1 \ --ip-range=192.168.1.128/25 \ --aux-address="my_pc=192.168.1.128" \ --aux-address="my_router=192.168.1.129" \ -o parent=enp1s0 test_net
Задайте соответствующие вашей сети
subnetиgateway. Опционально можно указать пул допустимых IP-адресов черезip-rangeи исключить зарезервированные IP-адреса черезaux-address. Параметр-o parent=<iface>указывает родительский интерфейс на хост-машине, через который зонд будет получать данные для анализа.Создайте обычную сеть в режиме bridge для подключения Boro-зонда к Boro-серверу:
docker network create -d bridge server_bridge
Проверьте, что сети успешно создались:
[root@localhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE a08c4253f05d bridge bridge local 1cf9579b7bda host host local 3e29a74817b7 none null local d5cee5a1fcfc server_bridge bridge local 46123a9a0492 test_net macvlan local
Создайте и запустите контейнер в фоновом режиме с использованием двух сетей:
--network test_net— macvlan для приема данных на анализ,--network server_bridge— bridge для коммуникации зонда с сервером:docker run \ --detach --interactive --tty \ --privileged \ --network test_net \ --network server_bridge \ ubuntu:24.04
Флаги
--detach --interactive --ttyиспользуются для примера, чтобы сохранять контейнер в запущенном состоянии в фоновом режиме.Найдите ID запущенного контейнера и проверьте состояние сети:
[root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9464442ea8a5 ubuntu:24.04 "/bin/bash" 1 hours ago Up 1 hours kind_antonelli
[root@localhost ~]# docker container inspect 9464442ea8a5 ... "Networks": { "server_bridge": { "MacAddress": "02:42:ac:12:00:02", "Gateway": "172.18.0.1", "IPAddress": "172.18.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, ... }, "test_net": { "MacAddress": "02:42:c0:a8:01:82", "Gateway": "192.168.1.1", "IPAddress": "192.168.1.130", "IPPrefixLen": 24, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, ... } }
Пример запуска зонда¶
docker run \
--detach --privileged --init \
--restart always \
--network test_net \
--network server_bridge \
--volume /opt/elecard/boro/dev/:/opt/elecard/boro/dev:z \
--name 'probe_dev' \
ubuntu:24.04 \
/opt/elecard/boro/dev/streamMonitor
Пример запуска похож на способ, описанный в предыдущем разделе, за исключением управления сетями: --network test_net — добавляет macvlan сеть для приема данных для анализа; --network server_bridge — добавляет сеть для коммуникации зонда с сервером.