Быстрое клонирование окружений с OpenStack с внешним DHCP
Привет, Хабр. Сегодня мы, Дмитрий Романовский и Дмитрий Тарасов, расскажем о возможности создания окружения с гипервизором OpenStack (далее по тексту — базовая ВМ с предустановленным и настроенным OpenStack), которое можно клонировать с сохранением работоспособности.
Под сохранением работоспособности здесь мы понимаем возможность создания сразу нескольких клонов, которые могут существовать в одной VLAN и не мешать работе друг друга. В нашем случае, важным дополнительным фактором была необходимость развертывания OpenStack в сети с внешним DHCP сервером. В этом сценарии подразумевалось динамическое получение IP-адреса как для самого гипервизора, так и для виртуальных машин под его управлением.
Потребность в многочисленном клонировании OpenStack связана со спецификой нашей деятельности — мы тестируем СРК Кибер Бэкап. В рамках тестирования мы проверяем все (или определенные) ВМ. Так как тестов одновременно может быть запущено несколько, то при работе с одним гипервизороми они могут начать конфликтовать друг с другом. А в нашей парадигме «Каждому тесту — свое изолированное окружение» удается избежать этих проблем.
Предлагаемое решение:
с одной стороны — упрощает нашу инфраструктуру и код — нет необходимости в поддержке подсетей, пулов статических адресов, и в то же время снимает ограничения на количество клонов — мы ограничены только подсетью, настроенной на DHCP-сервере;
с другой — немного усложняет деплой и первоначальную настройку самого OpenStack.
В силу того, что в официальных источниках (да и на многочисленных форумах) мы не нашли ни то что исчерпывающей, но практически никакой информации по такого рода конфигурации и собирали все практически по крупицам (в том числе эмпирическим путем), хотим поделиться с вами полученным опытом.
Выбираем ПО
Как известно, существует 2 популярные версии установщиков OpenStack: DevStack и PackStack. Мы остановились на установщике PackStack, так как он поддерживает возможность установки через файл answers, внутри которого можно задать буквально каждый параметр: настройки сети, хранилищ, паролей и так далее.
Документация к PackStack;
Гипервизор — oVirt, zVirt, VMWare, и т.п., на котором будет развернута базовая ВМ OpenStack;
ISO-образ установщика CentOS Linux release 8.5.2111. Данную ОС мы выбрали по двум причинам:
она основана на Red Hat Enterprise Linux (RHEL) и рекомендована разработчиками PackStack;
она бесплатная.
При деплое мы выбрали механизм сетевого взаимодействия Open vSwitch, так как у нас был опыт работы с ним на других гипервизорах.
Минимальные требования к ресурсам
В процессе эксплуатации созданного гипервизора мы определили следующие минимальные требования к ресурсам:
Чтобы вложенные в OpenStack ВМ могли получать IP-адреса с внешнего DHCP-сервера, в vSwitch вашего гипервизора необходимо включить режим Promiscuous mode.
Шаги по установке
На своем гипервизоре создаем новую вложенную ВМ для будущего OpenStack и подключаем ISO с CentOS Linux последней версий (8.5.2111 на момент написания). При установке выбираем режим Server без GUI.
Проверяем, что новая нода с CentOs 8.5 получила IP-адрес с внешнего DHCP-сервера:
Обновляем файл конфигурации чтобы включить SSH и доступ по паре логин/пароль:
nano /etc/ssh/sshd_config
Перезапускаем службу для применения настроек:
systemctl restart sshd
Добавляем альтернативные репозитории — это требуется из-за того, что официальной поддержки CentOS уже нет:
sed -i 's/^mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
Устанавливаем все доступные обновления:
yum update -y
systemctl rebootДобавляем альтернативные репозитории снова — на случай, если они перезаписались во время обновления:
sed -i 's/^mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
Устанавливаем дополнительные пакеты и делаем необходимые настройки:
dnf install network-scripts -y
systemctl stop firewalld
systemctl disable firewalld
dnf config-manager --enable powertools
sudo sed -i 's/^SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config
dnf update -y
reboot
Настраиваем репозиторий OpenStack на релиз Victoria 5.4.0:
dnf install -y centos-release-openstack-victoria-1-2.el8.noarch
Добавляем альтернативные репозитории — на случай, если они снова перезаписались во время настройки репозитория OpenStack:
sed -i 's/^mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
Развертываем установщик:
dnf install -y openstack-packstack
Выключаем NetworkManager и включаем network-scripts — это необходимо для корректной работы Open vSwitch, который мы выбрали в нашем сценарии:
systemctl disable NetworkManager
systemctl stop NetworkManager
systemctl enable network
systemctl start network
rebootФормируем файл answers с дефолтными опциями для деплоя OpenStack:
packstack --gen-answer-file=packstack-answers.txt
Обновляем необходимые опции. Внимание: все должно быть в UTF-8, иначе деплоер выдаст ошибку с неочевидным текстом.
Для всех сервисов OpenStack изменяем IP-адрес, выданный по DHCP, на 127.0.0.1 (localhost). Это необходимо для автоматического назначения IP-адреса каждому клону из нашей будущей базовой ВМ:
CONFIG_CONTROLLER_HOST=127.0.0.1
CONFIG_COMPUTE_HOSTS=127.0.0.1
CONFIG_NETWORK_HOSTS=127.0.0.1
CONFIG_AMQP_HOST=127.0.0.1
CONFIG_MARIADB_HOST=127.0.0.1
CONFIG_REDIS_HOST=127.0.0.1В OpenStack настраиваем сетевой адаптер на внешнюю сеть для будущих вложенных ВМ (заменить ens192 ниже на название вашего сетевого интерфейса):
CONFIG_NEUTRON_ML2_TYPE_DRIVERS=vxlan,flat
CONFIG_NEUTRON_ML2_TENANT_NETWORK_TYPES=vxlan
CONFIG_NEUTRON_OVS_BRIDGE_MAPPINGS=extnet:br-ex
CONFIG_NEUTRON_OVS_BRIDGE_IFACES=br-ex:ens192
CONFIG_NEUTRON_OVS_EXTERNAL_PHYSNET=extnetВыбераем механизм сетевого взаимодействия:
CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS=openvswitch
CONFIG_NEUTRON_L2_AGENT=openvswitchОтменяем создание демонстрационных сетей, подсетей, роутера и образа cirros:
CONFIG_PROVISION_DEMO=n
Запускаем установку PackStack с обновленным файлом answers:
packstack --answer-file=packstack-answers.txt
В нашем окружении установка длится примерно 20 минут. После успешной установки отобразится такое или схожее сообщение:
**** Installation completed successfully ******
Additional information:
* Time synchronization installation was skipped. Please note that unsynchronized time on server instances might be problem for some OpenStack components.
* File /root/keystonerc_admin has been created on OpenStack client host 127.0.0.1. To use the command line tools you need to source the file.
* To access the OpenStack Dashboard browse to http://127.0.0.1/dashboard.
Please, find your login credentials stored in the keystonerc_admin in your home directory.
* The installation log file is available at: /var/tmp/packstack/20 230 915–120 923–0rnwv3m9/openstack‑setup.log
* The generated manifests are available at: /var/tmp/packstack/20 230 915–120 923–0rnwv3m9/manifests
Обратите внимание: выше шрифтом выделено как после установки OpenStack подсказывает, где взять логин и пароль для первого входа в гипервизор.
Конфигурация OpenStack на базовой ВМ после первичного деплоя
Чтобы сделать доступным веб-интерфейс необходимо поменять адрес localhost (127.0.0.1) на фактический внешний IP-адрес — в примерах ниже = 10.77.237.155. В файле конфигурации horizon в секцию Server aliases добавляем следующую строку:
nano /etc/httpd/conf.d/15-horizon_vhost.conf
ServerAlias 10.77.237.155
systemctl restart httpd.serviceМеняем адрес localhost (127.0.0.1) на фактический внешний IP-адрес в файле конфигурации /etc/nova/nova.conf. Это необходимо для обеспечения возможности подсоединения к вложенным ВМ через noVNC-протокол для их настройки:
server_listen=127.0.0.1
novncproxy_base_url=http://127.0.0.1:6080/vnc_auto.htmlПерезапускаем все сервисы nova:
systemctl restart openstack-nova*Изменяем пароль для учетной записи admin:
• узнаем сгенерированный пароль
nano keystonerc_admin
• заходим в веб-интерфейс и изменяем пароль
Сохраняем новый пароль в файле keystonerc_admin.
Настраиваем внешнюю сеть в OpenStack.
Создаем сеть external network (тип: Flat, без подсетей):Выключаем port_security с помощью CLI OpenStack. В веб-интерфейсе такой возможности нет:
Если это не сделать, то при создании ВМ будем получать ошибку nova-compute сервиса:
Выключаем port security (предварительно, авторизауемся в API):
. keystonerc_admin
openstack network set --disable-port-security d1102546-e081-4b9e-be96-9cd3aada889cПри необходимости можно подготовить собственный шаблон (flavor) для ваших будущих ВМ. Flavor — это, по сути, шаблон параметров железа, необходимых для работы той машины, которую планируется создавать:
openstack flavor create --vcpus 2 --ram 4096 --disk 20 --public --id 7 aqa1.flavor
Проверяем через веб-интерфейс что шаблон создан:
Проверяем через веб-интерфейс что шаблон создан:
Устанавливаем пакет nmap.
Для нашей конфигурации (динамические IP-адреса) OpenStack не будет показывать IP-адрес для вложенной ВМ в API и в веб-интерфейсе. Поэтому, предлагается установить nmap — это позволит узнать IP-адреса вложенных ВМ:
yum install nmap -y
Загружаем в OpenStack необходимые образы для ВМ. Например, мы использовали образ Debian10×64 QCOW2:
Учитываем специфику запуска новой ВМ в конфигурации с внешней сетью (DHCP).
В связи с тем, что нам необходимо, чтобы вложенные ВМ получали уникальные IP-адреса с нашего DHCP сервера (даже если мы создали несколько клонов OpenStack), пришлось выполнить несколько шагов, чтобы обойти баг OpenStack:
В OpenStack запрещено привязывать к вложенным ВМ сети без подсетей. Подсети нас не устраивают, потому что внутри подсетей свой DHCP, поэтому высок шанс, что ВМ на клонах OpenStack возьмут чужие IP-адреса. Ведь DHCP OpenStack ничего не знают про корпоративный DHCP. Через веб-интерфейс вообще невозможно создать ВМ без сети (или с сетью без подсети):
Через CLI также получаем ошибку:
Но через CLI создать ВМ все же можно, если в конфигурации сеть будет единственной (просто не нужно явно ее указывать, она автоматически привяжется, и проверки на наличие подсетей не произойдет).
Получаем следующие ограничения:
• С нашей конфигурацией невозможно создать ВМ из веб-интерфейса;
• IP-адрес ВМ можно узнать только подключившись к ней через веб-интерфейс OpenStack, используя noVNC-протокол либо с помощью стороннего пакета nmap.Пример: как с помощью nmap мы определяем IP-адрес для вложенной ВМ в OpenStack:
nmap -sn SUBNET | grep -i -B 2 "OSTACK_PORT_MAC_ADDRESS" | grep -oE "((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5]).){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])"где SUBNET — подсеть, по которой ведем поиск, OSTACK_PORT_MAC_ADDRESS — MAC-адрес сетевого порта OpenStack, который был назначен ВМ в момент её создания.
Учитывая все ограничения выше, создаем и запускаем ВМ командой (пример):
openstack server create --image c5d8b154-fc7c-48a8-837a-ccb201b89f57 --flavor 7 --boot-from-volume 20 test_vm1
На этом этапе наша базовая ВМ с OpenStack готова. Видим, что веб‑интерфейс OpenStack не выводит IP‑адрес созданной ВМ. Но внутри машины IPадрес назначен — это мы узнаем благодаря использованию nmap. Можно выключить машину (Soft ShutDown) и создать снапшот.
Шаги при клонировании ВМ с OpenStack
Теперь опишем шаги, которые необходимо выполнить на склонированной ВМ для обеспечения ее работоспособности. Мы выбрали подход с созданием bash-скрипта, который необходимо запускать на каждом новом клоне. Этот скрипт выполняет следующие шаги:
#!/bin/bash
# Включаем Exception handling, чтобы получать расширенные сообщения по падениям скрипта
set -e
# Перенаправляем логирование в отдельный файл, чтобы при необходимости можно было его скачать
exec 3>&1 4>&2
trap 'exec 2>&4 1>&3' 0 1 2 3
exec 1>repair_openstack.log 2>&1
# Вспомогательная функция для проверки того, что сетевому интерфейсу назначен новый IP-адрес
function newIpIsNotNull {
if [[ "$new_ip" == "" ]]; then
echo "Failure. New ip-address is empty. Interrupting the script...";
exit 1;
else
echo "New ip-address: $new_ip";
fi
}
# Берем существующий MAC-адрес с br-ex интерфейса
echo "updating MAC-address for br-ex..."
old_mac=$(ifconfig br-ex | grep ether | grep -o "..:..:..:..:..:..")
echo "Old MAC-address: $old_mac"
# Берем MAC-адрес, автоматически назначенный на внешний сетевой интерфейс гипервизором после клонирования (в нашем случае ens192)
new_mac=" class="formula inline">(ifconfig ens192 | grep ether | grep -o "..:..:..:..:..:..")
echo "New MAC-address:
# Заменяем MAC-адрес на br-ex == MAC-адрес с ens192
sed -i "s/" class="formula inline">old_mac/
echo "MAC-address for br-ex updated successfully."
# Перезапускаем сервис сети
echo "restarting network service..."
service network restart
echo "network service restarted successfully."
# Ждем назначения IP-адреса на br-ex интерфейс
echo "getting new ip-address..."
new_ip=" class="formula inline">(ifconfig br-ex | grep -oE '((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5]).){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])' | head -1)
echo "new ip-address founded."
# Падаем, если IP-адрес не назначился (в коде автотестов мы перезапускаем весь скрипт целиком, чтобы исключить проблемы нестабильности сети/инфраструктуры)
echo "check new ip-address is not empty..."
newIpIsNotNull
echo "new ip-address verification completed successfully."
# После успешного получения IP-адреса обновляем /etc/hosts
echo "replacing ip-address in /etc/hosts..."
sed -i -e "s/([0-9]{1,3}.){3}[0-9]{1,3} packstack/
echo "IP replaced successfully in /etc/hosts."
# Обновляем конфигурацию horizon
echo "replacing ip-address in apache (Horizon) conf..."
sed -i -e "s/ ServerAlias 10.77.[0-9]\{1,3\}.[0-9]\{1,3\}/ ServerAlias $new_ip/g" /etc/httpd/conf.d/15-horizon_vhost.conf
echo "IP replaced successfully in /etc/httpd/conf.d/15-horizon_vhost.conf"
# Обновляем конфигурацию nova
echo "replacing ip-address in nova conf"
sed -i -e "s/server_listen=\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}/server_listen=" class="formula inline">new_ip/g" /etc/nova/nova.conf
sed -i -e "s/server_proxyclient_address=([0-9]{1,3}.){3}[0-9]{1,3}/server_proxyclient_address=
sed -i -e "s/novncproxy_base_url=http:\/\/\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}/novncproxy_base_url=http:\/\/" class="formula inline">new_ip/g" /etc/nova/nova.conf
echo "IP replaced successfully in /etc/nova/nova.conf"
# Заменяем localhost (127.0.0.1) в базе keystone в таблице endpoint в столбце URL (необходимо для подключения к OpenStack API из автотестов — тесты запускаются на отдельной машине)
echo "replacing ip-address in API endpoints"
mysql -uroot -pqwe123QWE keystone -e "UPDATE endpoint SET url = REPLACE(url, '127.0.0.1', '$new_ip');";
echo "IP replaced successfully in column 'url' of table 'endpoint' of database 'keystone'"
# Все, ожидаем успешное завершение выполнения скрипта
echo "script completed successfully."
В результате мы получаем возможность создания сразу нескольких клонов, которые могут существовать в одном VLAN и не мешать работе друг друга. За уникальностью IP-адресов следит наш «родительский» гипервизор, на котором мы разворачиваем клоны гипервизоров OpenStack. Уникальность IP-адресов обеспечивается уникальностью MAC-адресов (именно поэтому мы их и меняем в скрипте после клонирования для br-ex — копируем с основного интерфейса), чтобы наш внешний DHCP всегда выдавал новый IP-адрес на основе нового MAC-адреса.
Итак, мы научились клонировать окружения OpenStack с сохранением работоспособности. Надеемся, что наш рассказ был вам полезен, и до новых встреч.