2.5. Сеть на виртуальной машине или в Docker

Возможные ограничения

Внимание

Так как существует множество вариантов виртуализации ОС и сетевых подсистем, компания Elecard не может протестировать и гарантировать работу зонда под каждым виртуальным решением. При необходимости свяжитесь с отделом технической поддержки.

Работа зонда на виртуальной машине принципиально не отличается от работы зонда на физической машине. Однако необходимо принимать во внимание, что абстракции над физическими устройствами могут приводить к недостаточной производительности гостевой системы. Данный факт может вызвать следующие потенциальные проблемы в работе зонда:

  • Снижение максимального трафика, который принимается без потерь пакетов;

  • Искажение измерений таймингов 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

  1. Двойным кликом на виртуальной машине откройте окно ее свойств и перейдите на вкладку Show virtual hardware details. Нажмите кнопку Add Hardware внизу окна.

  2. В меню доступных устройств кликните опцию PCI Host Device.

  3. В раскрывшемся списке выберите необходимый адаптер и нажмите кнопку Finish. В описании адаптера присутствует ID PCI-устройства и может отображаться имя интерфейса в хост-системе.

  4. Если виртуальная машина была запущена, перезапустите её, чтобы изменения применились корректно.

После старта виртуальной машины сетевой адаптер должен получить системный драйвер в гостевой системе:

[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 самостоятельно сконфигурирует сеть, этого достаточно для приема мультикаста):

  1. Создайте macvlan сеть:

    docker network create -d macvlan \
      -o parent=enp1s0 test_net
    

    Параметр -o parent=<iface> указывает родительский интерфейс на хост-машине, через который зонд будет получать данные для анализа.

  2. Создайте обычную сеть в режиме bridge для подключения Boro-зонда к Boro-серверу:

    docker network create -d bridge server_bridge
    
  3. Проверьте, что сети успешно создались:

    [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
    
  4. Создайте и запустите контейнер в фоновом режиме с использованием двух сетей: --network test_netmacvlan для приема данных на анализ, --network server_bridgebridge для коммуникации зонда с сервером:

    docker run \
      --detach --interactive --tty \
      --privileged \
      --network test_net \
      --network server_bridge \
      ubuntu:24.04
    

    Флаги --detach --interactive --tty используются для примера, чтобы сохранять контейнер в запущенном состоянии в фоновом режиме.

  5. Найдите 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-сети:

  1. Создайте 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> указывает родительский интерфейс на хост-машине, через который зонд будет получать данные для анализа.

  2. Создайте обычную сеть в режиме bridge для подключения Boro-зонда к Boro-серверу:

    docker network create -d bridge server_bridge
    
  3. Проверьте, что сети успешно создались:

    [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
    
  4. Создайте и запустите контейнер в фоновом режиме с использованием двух сетей: --network test_netmacvlan для приема данных на анализ, --network server_bridgebridge для коммуникации зонда с сервером:

    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-адрес.

  5. Найдите 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-сети:

  1. Создайте 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> указывает родительский интерфейс на хост-машине, через который зонд будет получать данные для анализа.

  2. Создайте обычную сеть в режиме bridge для подключения Boro-зонда к Boro-серверу:

    docker network create -d bridge server_bridge
    
  3. Проверьте, что сети успешно создались:

    [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
    
  4. Создайте и запустите контейнер в фоновом режиме с использованием двух сетей: --network test_netmacvlan для приема данных на анализ, --network server_bridgebridge для коммуникации зонда с сервером:

    docker run \
      --detach --interactive --tty \
      --privileged \
      --network test_net \
      --network server_bridge \
      ubuntu:24.04
    

    Флаги --detach --interactive --tty используются для примера, чтобы сохранять контейнер в запущенном состоянии в фоновом режиме.

  5. Найдите 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 — добавляет сеть для коммуникации зонда с сервером.