Быстрое клонирование окружений с OpenStack с внешним DHCP

1b4499706c654e25a41baa51366af140.png

Привет, Хабр. Сегодня мы, Дмитрий Романовский и Дмитрий Тарасов, расскажем о возможности создания окружения с гипервизором 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.

Шаги по установке

  1. На своем гипервизоре создаем новую вложенную ВМ для будущего OpenStack и подключаем ISO с CentOS Linux последней версий (8.5.2111 на момент написания). При установке выбираем режим Server без GUI.

  2. Проверяем, что новая нода с CentOs 8.5 получила IP-адрес с внешнего DHCP-сервера:

    d19261985e4b69740f081725c8d5664b.png
  3. Обновляем файл конфигурации чтобы включить SSH и доступ по паре логин/пароль:  

    nano /etc/ssh/sshd_config

    f1c94c2e4f638fbdccfc662fcbcc66c3.png

    Перезапускаем службу для применения настроек:

    systemctl restart sshd

  4. Добавляем альтернативные репозитории — это требуется из-за того, что официальной поддержки 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-*

  5. Устанавливаем все доступные обновления:

    yum update -y
    systemctl reboot

  6. Добавляем альтернативные репозитории снова — на случай, если они перезаписались во время обновления:

    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-*

  7. Устанавливаем дополнительные пакеты и делаем необходимые настройки:

    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

  8. Настраиваем репозиторий OpenStack на релиз Victoria 5.4.0:

    dnf install -y centos-release-openstack-victoria-1-2.el8.noarch

  9. Добавляем альтернативные репозитории — на случай, если они снова перезаписались во время настройки репозитория 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-*

  10. Развертываем установщик:

    dnf install -y openstack-packstack

  11. Выключаем NetworkManager и включаем network-scripts — это необходимо для корректной работы Open vSwitch, который мы выбрали в нашем сценарии:

    systemctl disable NetworkManager
    systemctl stop NetworkManager
    systemctl enable network
    systemctl start network
    reboot

  12. Формируем файл answers с дефолтными опциями для деплоя OpenStack:

    packstack --gen-answer-file=packstack-answers.txt

  13. Обновляем необходимые опции. Внимание: все должно быть в 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

  14. Запускаем установку 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 подсказывает, где взять логин и пароль для первого входа в гипервизор.

    dd8a4266b04d20e6119714931ce7a43c.png

    Конфигурация OpenStack на базовой ВМ после первичного деплоя

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

    2. Меняем адрес 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*

    3. Изменяем пароль для учетной записи admin:

      •    узнаем сгенерированный пароль

      nano keystonerc_admin

      •    заходим в веб-интерфейс и изменяем пароль

      044afc5acf8e070331a379feed6f5291.png

      Сохраняем новый пароль в файле keystonerc_admin.

    4. Настраиваем внешнюю сеть в OpenStack.
      Создаем сеть external network (тип: Flat, без подсетей):

      963b4aabc75d3e64b7192e2a69f9cb63.png50a8af9c414993630ce3631b710cd7cf.png
    5. Выключаем port_security с помощью CLI OpenStack. В веб-интерфейсе такой возможности нет:

      324e509da61ebb39a05e05ea919cd7b0.png

      Если это не сделать, то при создании ВМ будем получать ошибку nova-compute сервиса:

      fde96b2c8d7632713e025053c01d2d05.png

      Выключаем port security (предварительно, авторизауемся в API):

      . keystonerc_admin
      openstack network set --disable-port-security d1102546-e081-4b9e-be96-9cd3aada889c

    6. При необходимости можно подготовить собственный шаблон (flavor) для ваших будущих ВМ. Flavor — это, по сути, шаблон параметров железа, необходимых для работы той машины, которую планируется создавать:

      openstack flavor create --vcpus 2 --ram 4096 --disk 20 --public --id 7 aqa1.flavor

      Проверяем через веб-интерфейс что шаблон создан:

      e943264f3982f9f2aef418dcb33a7dc9.png

      Проверяем через веб-интерфейс что шаблон создан:

      e00f24b8d2c17153760d3ab9c3ff1a5b.png
    7. Устанавливаем пакет nmap.

      Для нашей конфигурации (динамические IP-адреса) OpenStack не будет показывать IP-адрес для вложенной ВМ в API и в веб-интерфейсе. Поэтому, предлагается установить nmap — это позволит узнать IP-адреса вложенных ВМ:

      yum install nmap -y

    8. Загружаем в OpenStack необходимые образы для ВМ. Например, мы использовали образ Debian10×64 QCOW2:

      92c6ba01137da25ad2206a4d687235f8.png2e70041c75fd43b6b543d313e46bdc84.png
    9. Учитываем специфику запуска новой ВМ в конфигурации с внешней сетью (DHCP).

      В связи с тем, что нам необходимо, чтобы вложенные ВМ получали уникальные IP-адреса с нашего DHCP сервера (даже если мы создали несколько клонов OpenStack), пришлось выполнить несколько шагов, чтобы обойти баг OpenStack:  

      В OpenStack запрещено привязывать к вложенным ВМ сети без подсетей. Подсети нас не устраивают, потому что внутри подсетей свой DHCP, поэтому высок шанс, что ВМ на клонах OpenStack возьмут чужие IP-адреса. Ведь DHCP OpenStack ничего не знают про корпоративный DHCP. Через веб-интерфейс вообще невозможно создать ВМ без сети (или с сетью без подсети):

      123df47ca2857b214b54bd301995d00c.png

      Через CLI также получаем ошибку:

      7567b7aba3bd655fa37b85b289f35772.png

      Но через 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

      c4661e797c74a1236e2a35489bff2e00.pngd065fbd12b90543890a16a69cf2f8475.png1c5108a79befe646c1435f0fbb33fe29.png1c5108a79befe646c1435f0fbb33fe29.png

На этом этапе наша базовая ВМ с 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 с сохранением работоспособности. Надеемся, что наш рассказ был вам полезен, и до новых встреч.

© Habrahabr.ru