Привет, Хабр! На связи вновь Кирилл Савин, архитектор SDN в Облаке Рег.ру. Недавно мы с командой взвесили все риски и приняли волевое решение — переехать на OVN. В процессе думали над архитектурой, решали возникающие вопросы и набивали шишки. Я решил поделиться нашим опытом и подходами.

В первой статье рассказали, как устроен OVN изнутри, рассмотрели особенности архитектуры. Теперь готовы перейти к практике! Во второй части опишу ручной подход для миграции облака с сетевым даунтаймом для перестроения сети, но без миграции, собственно, виртуальных машин. Для «переезда» я осознанно выбрал ручной подход — объясню, почему и что из этого получилось. Внутри — по шагам рассказываю о переезде и делюсь полезными конфигурациями, которые делают это возможным.

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

Предпосылки переезда на OVN

Как я рассказывал в предыдущей статье, плюсы OVN перевесили его минусы — и мы решили мигрировать. Кратко напомню ключевые преимущества: экономия вычислительных ресурсов за счет отказа от дополнительного программного обеспечения и сетевых namespaces, легковесные балансировщики нагрузки, технические возможности OVN и современный подход в построении SDN.

Сейчас мы используем модифицированную под наше облако конфигурацию kolla-ansible в качестве системы развертывания OpenStack и Neutron с драйвером ML2 Open vSwitch. Так, в роли файрвола — nftables, а DHCP-агенты в namespaces с dnsmasq заменили на openvswitch_agent.

Сложности к подходу миграции добавило то, что kolla-ansible разворачивает компоненты в отдельных контейнерах. Радует, что в инструменте уже есть роль для автоматического развертывания конфигурации, в отличие от полной автоматической процедуры смены настройки с переездом сетевых сущностей.

В процессе исследования, всегда предшествующем выполнению задачи, я ознакомился с несколькими материалов на тему миграции OVN. К сожалению, для нас они не подошли в полной мере.

Возможно, для себя вы найдете что-то полезное: 

Миграция с LinuxBridge

Hassle-free migration from OVS to OVN

Live-миграция Nectar Research Cloud 

Готовый план миграции для TripleO: 

  • RedHat Documentation;

  • Neutron Repository (осталась упрощенная миграция, код, связанный с TripleO, удален, так как TripleO больше не поддерживается). 

После подробного изучения материалов, многократного тестирования на dev-стенде, а также нескольких итераций на продакшен-средах, мы в команде выработали стабильный ручной подход к миграции. Решение не автоматизировать процесс полностью, а идти по пути ручной миграции было принято осознанно по причинам того, что это дало бы нам больше надежности и предсказуемости. Итак, приступим.

Настройка графиков в Grafana

На старте работ полезно настроить сбор метрик заранее, например, установить node_exporter на нодах. Для мониторинга OVS/OVN есть экспортеры от Paul Greenberg, но, как показала практика, они не очень подходят из коробки для инсталляций в контейнерах и, к сожалению, репозитории находятся в архиве. Впрочем, в будущем это может быть еще одна тема для статьи о том, как мы адаптировали его код под наши реалии :) 

Переход на OpenFlow-файрвол в Open vSwitch

Для реализации сетевой безопасности (security groups) OVN использует OpenFlow-правила, поэтому первый шаг при миграции — отказ от iptables/nftables в пользу встроенного механизма Open vSwitch. Это потребует смены драйвера файрвола в конфигурации neutron-openvswitch-agent. Как это сделать?

1. Откройте файл /etc/kolla/config/neutron/openvswitch_agent.ini и измените блок [securitygroup] следующим образом:

[securitygroup]
firewall_driver = openvswitch

2. После этого необходимо обновить конфигурацию Neutron и применить ее на всех сетевых и вычислительных нодах:

kolla-ansible -i multinode genconfig -t neutron --diff

Убедитесь, что в файле openvswitch_agent.ini действительно заменен драйвер:

[securitygroup]
-firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
+firewall_driver = openvswitch

3. Перезапустите агент neutron-openvswitch-agent на каждой из нод:

systemctl restart kolla-neutron_openvswitch_agent-container

4. Удалите таблицы из nftables и ipset:

nft list tables | while read -r table; do nft delete table "$table"; done
ipset list -n | xargs -I {} ipset destroy {}

5. Убедитесь, что правила security group продолжают применяться. Например:

  • разрешите или запретите ICMP и проверьте доступность ВМ с помощью `ping`;

  • аналогично — добавьте или удалите правило для TCP-портов 80/443 и проверьте доступность с помощью `curl` или браузером.

Подготовка конфигурации OVN Control plane

Для следующего этапа можно использовать подготовленные Docker-образы. Если используете свои — следует заранее их собрать. Перед самой процедурой миграции желательно отключить шедулинг новых виртуальных машин на все вычислительные ноды.

for i in `openstack compute service list -c Host -f value`; do openstack compute service set --disable $i nova-compute; done

Далее меняем агент neutron на ovn и включаем нативный DHCP в /etc/kolla/globals.yml:

-neutron_plugin_agent: "openvswitch"
-neutron_ovn_dhcp_agent: "no"
+neutron_plugin_agent: "ovn"
+neutron_ovn_dhcp_agent: "yes"

Если нужна поддержка DVR, когда трафик на FIP виртуальной машины идет не через сетевую ноду, а сразу на гипервизор, где находится эта виртуальная машина, вам понадобится:

+neutron_ovn_distributed_fip: “yes”

В финале меняем драйвер neutron в секции [ml2] конфига /etc/kolla/config/neutron/ml2_conf.conf:

-mechanism_drivers = openvswitch, 2population
+mechanism_drivers = ovn

Установка OVN Control Plane и перевод Neutron на OVN 

Следующий шаг — установка компонентов OVN Control Plane: базы данных ovn-nb-db, ovn-sb-db и демон ovn-northd.

По умолчанию, они ставятся на ноды указанные в секции [control] файла multinode. Если таких нод три — OVN будет развернут в кластерном режиме с использованием алгоритма консенсуса RAFT для баз данных:

  • ovn-nb-db (NorthBound) и ovn-sb-db (SouthBound) образуют отказоустойчивый кластер;

  • ovn-northd работает в режиме active+standby, используя блокировку в базе данных для выбора активного экземпляра.

Теперь мы готовы разворачивать OVN Control Plane:

kolla-ansible -i multinode deploy -t ovn --limit control --diff

Переключение Neutron на использование OVN

Дальше необходимо перенастроить neutron-server для работы с OVN как SDN-бэкендом.

⚠️ Внимание: После выполнения следующей команды Neutron начнет использовать OVN. Подключение виртуальных машин по старой схеме (например, через OVS+Hybrid Iptables) станет недоступным. Вы должны быть уверены, что готовы к этому этапу.

kolla-ansible -i multinode reconfigure -t neutron --limit control --diff --check

Проверка состояния и логов

После выполнения предыдущей команды необходимо проверить состояние компонентов и убедиться в отсутствии ошибок и предупреждений. Обратите внимание на наличие WARNING, ERROR или проблем с выбором лидера RAFT:

tail /var/log/kolla/openvswitch/ovn-nb-db.log
tail /var/log/kolla/openvswitch/ovn-sb-db.log
tail /var/log/kolla/openvswitch/ovn-northd.log
tail /var/log/kolla/neutron/neutron-server.log

Также полезно проверить состояние кластеров баз данных OVN:

docker exec ovn_nb_db ovs-appctl -t /var/run/ovn/ovnnb_db.ctl cluster/status OVN_Northbound
docker exec ovn_sb_db ovs-appctl -t /var/run/ovn/ovnsb_db.ctl cluster/status OVN_Southbound

И проверить глобальный конфиг баз данных OVN:

docker exec ovn_nb_db ovn-nbctl --no-leader-only list NB_Global
docker exec ovn_sb_db ovn-sbctl --no-leader-only list SB_Global

Подготовка к миграции: что стоит учесть заранее

Во время миграции Neutron в OVN я столкнулся с рядом нюансов, которые увеличили общее время перехода. Собрал важные моменты, которые стоит проверить до начала процесса.

1. Ошибка при синхронизации базы Neutron с OVN NB. Во время выполнения neutron-ovn-db-sync-util может возникнуть ошибка:

Unhandled error: neutron.ipam.exceptions.IpAddressGenerationFailureNoMatchingSubnet:
No valid service subnet for the given device owner, network <network-uuid>, service type network:distributed.

Причина заключается в том, что во внешней сети отсутствует подсеть с типом network:distributed, которая требуется OVN для корректной работы с распределенными портами. 

Решение: создать такую подсеть вручную:

openstack subnet create --no-dhcp --subnet-range "192.168.100.0/24" --gateway 192.168.100.1 --service-type network:distributed --network external distributed_external_subnet

Здесь важно отметить, что подсеть не должна пересекаться с существующими маршрутами внешнего мира. После миграции ее можно будет удалить.

2. Проверка и отключение DHCP на внешних подсетях. Если в какой-либо внешней подсети включен DHCP, синхронизация может завершиться ошибкой:

Failed to create port on network <UUID>, because fixed_ips included invalid subnet <UUID>

Чтобы убедиться, что всё правильно настроили, заходим в базу данных Neutron:

docker exec mariadb mysql -u root -p<PASSWORD>

Далее делаем запрос:

USE neutron;
SELECT id, name, enable_dhcp FROM subnets WHERE network_id = '<external-network-id>';

После проверки переходим к отключению DHCP:

openstack subnet set --no-dhcp <subnet-id>

3. Запуск синхронизации базы Neutron в OVN

После подготовки запускаем процесс синхронизации из базы данных Neutron в OVN NB. Сделать это можно в любом контейнере neutron_server:

docker exec -it neutron_server bash
neutron-ovn-db-sync-util --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini --log-dir /var/log/kolla/neutron --debug --ovn-ovsdb_connection_timeout=300 --ovn-neutron_sync_mode repair

Синхронизация может занять какое-то время — это зависит от количества логических свитчей, роутеров, портов и т.д. Для малых объемов, примерно 100 ВМ, уйдет около одной минуты. Процесс синхронизации можно наблюдать интерактивно в логе:

tail -f /var/log/kolla/neutron/neutron-ovn-db-sync-util.log

На этом этапе мы также можем сразу проверить, какие логические объекты появились в базе OVN:

docker exec ovn_nb_db ovn-nbctl --no-leader-only show

Если синхронизация прошла успешно, в логах neutron_server, ovn_nb_db, ovn_northd не должно быть регулярно повторяющихся ошибок. На этом этапе база OVN NB синхронизирована с Neutron, а мы переходим к следующему этапу — настройке compute и network нод.

Обновление нод без размиграции ВМ

В идеале миграция виртуальных машин между вычислительными узлами должна проходить незаметно для пользователей. Для того, чтобы не производить миграцию вообще, мы переподключим текущую сетевую часть к новой конфигурации SDN. И здесь необходимо отключить агенты на целевых нодах. Для этого вносим изменения «на лету» в Open vSwitch:

  • удаляем управление через контроллеры и менеджер — это было нужно для связки с neutron_openvswitch_agent;

  • удаляем патчи в br-int и br-tun и бридж br-tun — для OVN это не нужно, он построит Geneve-туннели в бридже bg-int;

  • снимаем ограничения по протоколам OpenFlow, для того, чтобы ovn_controller смог подключиться к Open vSwitch.

Ниже приведен простой Bash-скрипт с необходимыми командами — запускаем его на каждой вычислительной и сетевой ноде.

Развернуть Bash-скрипт:
#!/bin/bash

echo stop and disable l3, ovs, metadata agents 
systemctl disable –now kolla-neutron_l3_agent-container.service kolla-neutron_openvswitch_agent-container.service kolla-neutron_metadata_agent-container.service 

echo delete network namespaces
ip --all netns delete

echo delete controller and manager in ovs
docker exec openvswitch_vswitchd ovs-vsctl del-manager
docker exec openvswitch_vswitchd ovs-vsctl del-controller br-ex
docker exec openvswitch_vswitchd ovs-vsctl del-controller br-int

echo delete br-tun and patches
docker exec openvswitch_vswitchd ovs-vsctl del-port br-int patch-tun
docker exec openvswitch_vswitchd ovs-vsctl del-port br-tun patch-int
docker exec openvswitch_vswitchd ovs-vsctl del-br br-tun
docker exec openvswitch_vswitchd ovs-vsctl del-port br-int int-br-ex
docker exec openvswitch_vswitchd ovs-vsctl del-port br-ex phy-br-ex

echo delete Openflow version protocol limitations
docker exec openvswitch_vswitchd ovs-vsctl clear bridge br-int protocols
docker exec openvswitch_vswitchd ovs-vsctl clear bridge br-ex protocols
  • Последовательно деплоим ovn-controller и neutron ovn metadata agent + конфиг openvswitch для OVN на те ноды, где ранее выполнили скрипт:

    kolla-ansible -i multinode deploy -t ovn,neutron,openvswitch --limit computeN

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

1. Если на ноде вообще не доступны все ВМ, проверьте наличие NORMAL-правила в br-ex. При его отсутствии, добавьте вручную:

docker exec openvswitch_vswitchd ovs-ofctl dump-flows br-ex
docker exec openvswitch_vswitchd ovs-ofctl add-flow br-ex priority=0,action=normal

2. Проверьте, что нет роутеров с neutron-ovn-invalid-chassis:

docker exec ovn_nb_db ovn-nbctl --no-leader-only list Gateway_Chassis | grep invalid

Если они есть, нужно назначить сетевые шасси с приоритетом:

docker exec ovn_nb_db ovn-nbctl --no-leader-only lrp-set-gateway-chassis lrp-<uuid> network1 1

3. Если отдельные ВМ недоступны, то переподключить qvo/tap интерфейсы к br-int можно перезапуском:

systemctl restart kolla-nova_compute-cointainer

4. Также могут наблюдаться непредвиденные проблемы с работой конкретного роутера. Для проверки и решения этой проблемы можно мигрировать его на другую сетевую ноду, при ее наличии. Для этого переносим порт роутера во внешней сети LRP (Logical Router Port) на другое шасси:

  • ищем порт роутера в ovn по id-порта роутера во внешней сети, где lsp-id это uuid порта в neutron:

    docker exec ovn_nb_db ovn-nbctl list Logical_switch_port <lsp-id>
    options: router-port=<lrp-id>
  • получаем шасси и приоритеты:

    docker exec ovn_nb_db ovn-nbctl lrp-get-gateway-chassis <lrp-id>
  • выставляем имя шасси (оно же имя сетевой ноды) и приоритет. Чем больше цифра, тем выше приоритет:

    docker exec ovn_nb_db ovn-nbctl lrp-set-gateway-chassis <lrp-id> network1 3
  • проверяем, на каком шасси обслуживается lrp в данный момент:

    docker exec ovn_sb_db ovn-sbctl --no-leader-only show

    А если сетевая нода всего одна, то стоит прибегнуть к пересозданию роутера через Neutron.

5. Проверяем логи компонент и состояние OVS/OVN:

docker exec openvswitch_vswitchd ovs-vsctl show
docker exec openvswitch_vswitchd ovs-vsctl list open
docker exec openvswitch_vswitchd ovs-ofctl dump-flows br-ex
docker exec ovn_sb_db ovn-sbctl --no-leader-only show

tail /var/log/kolla/openvswitch/ovn-controller.log
tail /var/log/kolla/openvswitch/ovs-vswitchd.log
tail /var/log/kolla/openvswitch/ovsdb-server.log
tail /var/log/kolla/neutron/neutron-ovn-metadata-agent.log 

Готово! Ввод узлов в эксплуатацию

После выполнения всех описанных ранее этапов, поиска и устранения ошибок, мы наконец готовы ввести вычислительные узлы в работу. Итак, если всё хорошо, включаем обратно шедулинг виртуальных машин на ноды:

for i in `openstack compute service list -c id -k value`; do openstack compute service set --enable $i nova-compute; done

Включаем поддержку OVN-балансировщиков в Octavia

По необходимости включаем поддержку OVN-балансировщиков. Добавляем драйвер ovn в ./kolla/config/octavia.conf:

[driver_agent]
enabled_provider_agents = amphora_agent, ovn
default_provider_driver = amphora_agent

Выкатываем:

kolla-ansible -i multinode reconfigure -t octavia --diff

Удаление ненужных объектов после миграции

После завершения миграции важно почистить «мусор» и навести порядок в конфигурациях. Поехали:

1. Удаляем контейнеры агентов ml2/ovs на каждой ноде:

docker rm neutron_metadata_agent; docker rm neutron_l3_agent; docker rm neutron_openvswitch_agent

Удаляем старые агенты:

for agent in `openstack network agent list | grep XXX | awk '{print $2}'`; do openstack network agent delete $agent; done

2. Удаляем интерфейсы-«потеряшки» из OVS. Например, такие:

Развернуть пример:
docker exec openvswitch_vswitchd ovs-vsctl show
Port tapa0b5b2fc-d2                                                                                            
            tag: 4                                                                                                     
            Interface tapa0b5b2fc-d2                                                                                   
                error: "could not open network device tapa0b5b2fc-d2 (No such device)"

for tap in `docker exec openvswitch_vswitchd ovs-vsctl show | grep "No such device" | grep -oP "tap[a-f0-9]{8}-[a-f0-9]{2}"`; do docker exec openvswitch_vswitchd ovs-vsctl del-port br-int $tap; done

3. Удаляем distributed-подсеть во внешней сети — она была нужна только для миграции:

openstack subnet delete distributed_external

4. Исправляем существующие порты роутеров. Для корректной работы OVN-балансировщиков необходимо либо исправить, либо пересоздать порты в приватной сети.

Развернуть пример:
#!/bin/bash
OS="openstack --os-cloud kolla-admin"

routers=`$OS router list -c ID -f value`
for router in $routers; do
        ports=`$OS port list --device-id $router -c ID -f value`
        for port in $ports; do
                type=`$OS port show $port -c device_owner -f value`

                if [ "$type" == "network:router_centralized_snat" ]; then
                        echo "router: $router port: $port type: $type FOR DELETE!!!"
                        $OS port show $port
                        $OS port delete $port
                elif [ "$type" == "network:router_interface_distributed" ]; then
                        echo "router: $router port: $port type: $type FOR CHANGE!!!"
                        $OS port show $port
                        $OS port set --device-owner network:router_interface $port
                fi
        done
done

Почти готово! Также можно удалить подсеть и порты с типом network:floatingip_agent_gateway. Они использовались для DVR в связке Neutron + Open vSwitch — в OVN это не нужно, так как используется распределенный NAT на основе правил OpenFlow.

«Если бы мы знали, что это такое», или особенности миграции

В процессе миграции я подмечал интересные (и не очень) моменты и искал решения. Собрал здесь кое-какие советы, которые сам был бы счастлив услышать в моменте работы над задачей:

1. После отключения агентов примерно через минуту пропадает связность ВМ на ноде. Проблема решается отключением сброса сети при потере контроллера (openvswitch_agent). Выполните эту команду на каждой ноде:

docker exec openvswitch_vswitchd ovs-vsctl set-fail-mode br-int standalone

 2. При частичной миграции на OVN возможна потеря связности в tenant-сети, если в ней одновременно присутствуют ВМ, работающие как в старой архитектуре Neutron+Open vSwitch, так и в OVN. Возникает конфликт между двумя реализациями роутера: namespace старого qrouter и логическим роутером OVN, обслуживающими одну и ту же сеть.

3. Подключение будет оставаться в режиме ovs_hybrid_plug (а дополнительные интерфейсы qvo, qbr, qvb будут создаваться) до тех пор, пока ВМ не переедет на другой гипервизор. Автоматически сменится на ovn (один tap-интерфейс) после миграции. 

4. В данном примере описана миграция, в которой клиентские сети остаются с типом VXLAN. В таком случае ограничение на количество виртуальных сетей будет 4096. Для перевода клиентских сетей на туннелирование Geneve нужно будет понизить MTU во всех сетях на 8 байт. Для примера, MTU физической сети 1500 байт, тенантная сеть при VXLAN-туннелировании будет 1450 байт. Значит, для перехода на Geneve нужно будет понизить MTU сети до 1442 байта. И в конфиге ml2_conf.ini в секции [ml2] выставить использование tenant_network_types = geneve.

5. При переезде мы столкнулись с multicast-штормом: задело несколько сегментов сети, это наблюдалось как недоступность серверов. В частности по SSH-протоколу потери достигали до 70% трафика. На графиках показатель PPS был около 500к на некоторых нодах. Сетевая служба быстро отреагировала и купировала проблему. Со своей стороны мы также оперативно предприняли действия по исправлению. После разбора выяснилили, что из-за неверной последовательности действий одновременно были активны старые VXLAN-туннели между нодами в логическом бридже br-tun и создались Geneve-туннели в бридже br-int. Так образовалась петля и шторм в сети — благодаря BUM-трафику.

6. Возникла проблема с Drop-правилами в Datapath, связанная с несовместимостью модуля ядра и ядра Linux на хост машине. Выявили это через запуск MTR в VM:

Подобные правила появлялись в datapath Open vSwitch:

recirc_id(0x13178),in_port(2),ct_state(-new-est+rel+rpl-inv+trk),ct_mark(0/0x3),eth(src=00:42:68:6d:9f:71,dst=fa:16:3e:32:0d:d8),eth_type(0x0800),ipv4(dst=210.100.100.100,proto=1,ttl=253,frag=no), packets:188, bytes:13160, used:0.548s, actions:drop

Мы проверили массу всего: от логов до разных гипотез с конфигурациями. После включения other_config:hw-offload=true в Open vSwitch проблема перестала воспроизводится. Интересно, что не совсем понятно, как именно это помогло — видимо, в данном режиме меняется логика создания правил в самом vswitchd. Мы не используем эту возможность, так как для этого нужны специализированные сетевые карты.

Глубокая диагностика с командами ovn-trace, ovs-appctl ofproto/trace и ovn-detrace не помогла. В итоге, приняли решение обновить ядро операционной системы до 5.14.0-427.33.1.el9_4.x86_64, 6.6.70-1.el9.x86_64, 6.12.28-1.el9.x86_64. И это сработало — всё исправилось! Уточню также, что проблема воспроизводилась на ядре 5.14.0-362.18.1.el9_3.0.1.x86_64, версия Open vSwitch 3.1.3.

7. При миграции облака на OVN с 50+ вычислительными нодами стоит использовать OVSDB Relay, чтобы снизить нагрузку на SouthBound DB. Оптимальная практика — развертывание одного экземпляра OVSDB Relay на каждые 50 вычислительных нод. Это равномерно распределяет нагрузку и предотвращает вероятность остановки обслуживания всего SDN из-за потери сходимости кластера Southbound DB. Такое происходит вследствии большого числа подключений процессов ovn-controller, периодически читающих ее состояние.

Заключение (но не конец этой истории!) 

Понимаю, что ручной подход, да еще и с остановкой сети, определенно, не лучший из существующих. Но есть и положительные моменты: за счет раннего перехода на OVN мы получили бесценный опыт в конфигурировании и эксплуатации решения. Текущий подход может быть использован для автоматизированного обновления, например, через плейбук и роли в Ansible. Так что я не останавливаюсь на этом решении, и сейчас прорабатываю метод для live-миграции. К чему это приведет — покажет время.

В следующей статье расскажу про диагностику OVN и Open vSwitch, о том, как отлаживать процессы и базы, искать сетевые объекты, проводить трассировку и некоторые другие моменты.

Хочется поблагодарить за поддержку и помощь моих коллег, а также участников сообщества в Telegram OVS/OVN russian community. А вас — за то, что дочитали. До встречи в продолжении моей истории!

Комментарии (0)