Привет, Хабр! На связи Кирилл Савин, я — архитектор SDN в Рег.облаке. Мы уже подробно разбирали, как устроен OVN в связке с OpenStack, — в статье «OVN под капотом: как построить сеть в OpenStack». А затем показали, как трассировать пакеты в OVN и анализировать поведение трафика.

В этом материале продолжаем тему интеграции OVN с OpenStack и разбираем более узкий, но важный сценарий — работу Metadata API при использовании OVN в качестве backend для Neutron. Это перевод оригинального design-документа, в котором мы сохранили структуру и инженерную логику автора. Речь пойдет уже не столько о маршрутизации пакетов, сколько о служебной логике поверх сетевой плоскости и особенностях ее реализации в модели OVN.

Навигация по тексту:

Введение

OpenStack Nova — сервис, отвечающий за управление жизненным циклом виртуальных машин, — предоставляет инстансам доступ к Metadata API. Это механизм, через который VM получает служебные данные о себе: идентификатор, параметры конфигурации, ключи SSH и user-data. По своей идее он аналогичен тому, как это реализовано в Amazon EC2.

В обработке запросов участвует OpenStack Neutron — сетевой сервис платформы. Одного IP-адреса источника недостаточно, чтобы однозначно определить, откуда пришел запрос к Metadata API: в разных сетях могут использоваться пересекающиеся диапазоны адресов. Поэтому Neutron перехватывает такие запросы и добавляет HTTP-заголовки, позволяющие уникально идентифицировать источник, после чего пересылает их на сервер Metadata API.

Цель этого материала — описать архитектурный подход к реализации этой функциональности при использовании OVN (Open Virtual Network) в качестве backend для OpenStack Neutron.

Neutron и Metadata: текущая реализация

В этом блоге можно подробнее узнать, как виртуальные машины сегодня получают доступ к Metadata API через Neutron. А ниже — краткое описание процесс��.

Metadata proxy запускается либо в namespace маршрутизатора (router namespace), либо в namespace DHCP. Namespace DHCP используется, если к сети не подключен маршрутизатор. Ограничение такого подхода в том, что через DHCP в виртуальную машину необходимо передать статический маршрут, чтобы она знала, что запросы к metadata нужно направлять на IP-адрес DHCP-сервера.

Процесс выглядит так:

  1. Инстанс отправляет HTTP-запрос к Metadata API по адресу 169.254.169.254.

  2. В зависимости от маршрута запрос попадает либо в router namespace, либо в DHCP namespace.

  3. Сервис metadata proxy в namespace добавляет в запрос:

  4. IP-адрес инстанса (заголовок X-Forwarded-For);

  5. ID маршрутизатора или сети (X-Neutron-Network-Id или X-Neutron-Router-Id).

  6. Metadata proxy отправляет запрос агенту metadata (за пределами namespace) через UNIX domain socket.

  7. Сервис neutron-metadata-agent добавляет новые заголовки (Instance ID и Tenant ID) и пересылает запрос в Nova Metadata API [0].

Для корректной работы Neutron и Nova должны быть настроены на взаимодействие с использованием общего секрета. Neutron подписывает заголовок Instance-ID этим секретом, чтобы предотвратить подмену. Параметр metadata_proxy_shared_secret должен быть указан в конфигурационных файлах nova и neutron (опционально).

Neutron и Metadata при использовании OVN

Текущий подход к Metadata API нельзя напрямую перенести на OVN. При использовании OVN Neutron-агенты не применяются. Кроме того, OVN не использует собственные network namespaces так же, как это сделано в исходной реализации (router и dhcp namespaces).

Необходимо использо��ать модифицированный подход, соответствующий модели OVN. Ниже вы найдете предлагаемый вариант.

Обзор предлагаемого решения

Предлагаемый подход близок к сценарию изолированной сети в текущей реализации ML2+OVS. Предполагается запуск экземпляра metadata proxy (haproxy) на каждом гипервизоре — для каждой сети, к которой подключена VM на данном хосте.

Из минусов — число metadata proxy увеличится (по сравнению со сценарием с маршрутизируемыми сетями, где используется один proxy на виртуальный маршрутизатор). Однако haproxy — легкий сервис, и большую часть времени он будет простаивать. Существенное преимущество — отсутствие необходимости реализовывать логику распределения proxy по узлам и механизмы высокой доступности. При необходимости архитектуру можно развить. Как это сделать — ниже.

Подход опирается на новую функциональность в OVN: логический порт типа localport, который должен присутствовать на каждом chassis (по аналогии с localnet-портами). Для таких портов пакеты не передаются через туннели — они доставляются только локальному экземпляру.

Шаг 1. Создание порта для metadata proxy

Сейчас при использовании DHCP-агента Neutron автоматически создаёт порт для DHCP. Аналогичный механизм можно применить для metadata proxy (haproxy). Будет создан OVN localport, присутствующий на каждом chassis, с одинаковыми MAC- и IP-адресами на всех хостах. В перспективе можно использовать один и тот же neutron-порт для DHCP и metadata.

Шаг 2. Маршрутизация запросов к Metadata API

OVN настраивается так, чтобы через DHCP возвращался статический маршрут, направляющий запросы к Metadata API на localport, где размещён metadata proxy. Если DHCP отключен или клиент игнорирует маршрут, статический маршрут настраивается в логическом маршрутизаторе OVN. Если DHCP-маршрут не срабатывает в изолированной сети, VM не получит metadata — это соответствует текущему поведению и не является регрессией.

Шаг 3. Управление namespace и экземплярами haproxy

Предлагается новый агент — neutron-ovn-metadata-agent. Он запускается на каждом гипервизоре и отвечает за:

  • создание и удаление haproxy;

  • управление OVS-интерфейсами;

  • управление network namespaces;

  • проксирование запросов к Metadata API.

Шаг 4. Обработка запросов Metadata API

Как и существующий metadata agent, neutron-ovn-metadata-agent выступает посредником между haproxy и Nova Metadata API.

haproxy работает в отдельном network namespace и не имеет доступа к сетям хоста, где размещён Nova Metadata API. Он добавляет необходимые заголовки и передает запрос агенту через UNIX domain socket — аналогично текущей реализации.

Логика управления metadata proxy

В neutron-ovn-metadata-agent. При запуске

  • Выполнить полную синхронизацию.

  • Проверить, что запущены все необходимые metadata proxy.

  • Для этого агент отслеживает таблицу Port_Binding в OVN Southbound DB и выбирает строки, где поле chassis соответствует текущему хосту.

  • Для каждого datapath (сети), к которой подключены эти порты, должен быть запущен metadata proxy.

  • Ненужные proxy — удалить.

Агент поддерживает соединение с OVN Northbound DB (через ovsdbapp). При первом подключении и при переподключении выполняется полная синхронизация. Регистрируется callback на операции create/update/delete строк Logical_Switch_Port. Когда порт привязывается к chassis, агент проверяет наличие metadata proxy для соответствующей сети.

Создание сети

При создании сети:

  • создается OVN localport для metadata proxy;

  • порт принадлежит network:dhcp, поэтому удаляется автоматически вместе с сетью;

  • порт создается независимо от настроек DHCP в подсетях, если включён metadata service.

Удаление сети

При удалении сети:

  • metadata proxy (если есть) останавливается;

  • OVN localport удаляется автоматически.

Запуск metadata proxy включает:

Создание network namespace

sudo ip netns add <ns-name>

Создание VETH-пары

sudo ip link add <iface-name>0 type veth peer name <iface-name>1

Добавление OVS-интерфейса и перенос одного конца в namespace

sudo ovs-vsctl add-port br-int <iface-name>0
sudo ip link set <iface-name>1 netns <ns-name>

Настройка MAC и IP

sudo ip netns exec <ns-name> ip link set <iface-name>1 address <neutron-port-mac>
sudo ip netns exec <ns-name> ip addr add <neutron-port-ip>/<netmask> dev <iface-name>1

Подъем интерфейсов

sudo ip netns exec <ns-name> ip link set <iface-name>1 up
sudo ip link set <iface-name>0 up

Установка external-id

sudo ovs-vsctl set Interface <iface-name>0 external_ids:iface-id=<neutron-port-uuid>

И запуск haproxy в namespace.

Остановка metadata proxy включает:

  • удаление UUID сети с chassis;

  • остановку haproxy;

  • удаление OVS-интерфейса;

  • удаление namespace.

Дополнительные соображения

Функциональность включается по умолчанию при использовании ovn driver. Должна быть возможность отключить ее, если metadata не требуется. Существует потенциальная гонка при запуске первой VM в сети на гипервизоре, если metadata proxy ещё не создан. Повторные попытки cloud-init должны в итоге получить metadata.

Альтернативы

Альтернатива 1
Реализация metadata внутри ovn-controller

Подход отклонен, поскольку:

  • Metadata API — OpenStack-специфичная функция;

  • потребовалось бы встроить HTTP и TCP стек в ovn-controller;

  • это усложняет архитектуру.

Альтернатива 2
Распределенный metadata и High Availability

Предлагается запуск proxy на виртуальный маршрутизатор или на сеть. Для этого требуется:

  • планирование (scheduling);

  • поддержка HA;

  • логика перепланирования при падении хоста;

  • интеграция с L3 HA.

В neutron-server (ovn mechanism driver) предлагается опция:

[ovn] isolated_metadata = True # или False

Описана логика планирования и перепланирования proxy через таблицы Chassis и Logical_Switch_Port с использованием external_ids.

Подход признан слишком сложным на текущем этапе, хотя архитектурно возможен и может быть реализован в будущем.

Планирование metadata proxy

В варианте с распределенным размещением metadata proxy требуется явная логика планирования и перепланирования.

Выбор хостов для размещения

neutron-ovn-metadata-agent может запускаться на тех узлах, которые способны обслуживать metadata proxy. Такие узлы должны одновременно запускать ovn-controller.

Каждый такой хост имеет запись Chassis в OVN Southbound database. В таблице Chassis используется поле external_ids, куда агент может записывать дополнительную информацию.

Для обозначения хостов, способных размещать metadata proxy, в external_ids соответствующей записи Chassis устанавливается флаг:

external_ids:neutron-metadata-proxy-host=true

Логика выбора chassis

При создании metadata proxy механизм драйвера OVN (в neutron-server) должен:

  1. Получить список Chassis из OVN Southbound database.

  2. Отфильтровать узлы, у которых установлен neutron-metadata-proxy-host=true.

  3. Выбрать наименее загруженный узел (например, с минимальным числом уже размещенных metadata proxy).

  4. Назначить выбранный хост, записав в Logical_Switch_Port (в OVN Northbound database) соответствующий external_id:

external_ids:neutron-metadata-proxy-chassis=CHASSIS_HOSTNAME

CHASSIS_HOSTNAME соответствует значению hostname в записи Chassis Southbound database.

Реакция агента на планирование

neutron-ovn-metadata-agent, запущенный на каждом хосте, отслеживает изменения в Logical_Switch_Port. Когда агент обнаруживает, что metadata proxy назначен его chassis, он:

  • создает namespace;

  • поднимает VETH-пару;

  • подключает интерфейс к OVS;

  • запускает haproxy;

  • регистрирует интерфейс через external_ids.

Перепланирование и отказоустойчивость

Также необходимо учитывать сценарий отказа хоста. При недоступности chassis:

  • metadata proxy, назначенные этому узлу, должны быть перепланированы;

  • требуется механизм обнаружения отказа (аналогично L3 HA);

  • после обнаружения отказа выполняется повторный запуск процедуры планирования;

  • соответствующие записи external_ids обновляются на новый CHASSIS_HOSTNAME.

По своей природе этот механизм близок к перепланированию L3 gateway при отказе узла, поэтому желательно использовать схожую модель обработки событий.

Такой подход обеспечивает распределенное размещение metadata proxy и возможность масштабирования, но добавляет дополнительную сложность в виде логики scheduling и HA. По этой причине на текущем этапе он признан избыточным по сравнению с базовой моделью localport, хотя архитектурно остается возможным направлением развития.