Pull to refresh
DDoS-Guard
Эксперт в сфере защиты от DDoS-атак

Как мы автоматизировали VDS и пытались не сгореть

Level of difficultyMedium
Reading time9 min
Views3K

Привет, меня зовут Даниил, и я алкоголик инженер, занимаюсь автоматизацией разных штук в компании DDoS-Guard, люблю творческие решения и сложные проекты. Сегодня расскажу про свой опыт автоматического конфигурирования VDS.

Начну со спойлера — не сгореть не получилось.
Начну со спойлера — не сгореть не получилось.

Задачей моей команды было реализовать автоматическое создание VDS, развертывание и конфигурирование образов для клиентов. В качестве инструмента виртуализации мы используем гипервизор VMware. Автоматизация необходима в первую очередь для того, чтобы клиент мог получить свой VDS в максимально короткие строки, и это не нужно было конфигурировать вручную.

Такое решение удобно для провайдера — автоматизация минимизирует время работы инженера, которое тратится на технические процессы, связанные с поддержкой виртуальных серверов, и, соответственно, возможностью ошибки из-за человеческого фактора. Оно удобно и для клиента, который получает необходимую услугу в кратчайшие сроки (буквально за 3-5 минут).

Выбор средства автоматического конфигурирования сводился к двум технологиям: cloud-init и VMware-tools. От первого варианта пришлось отказаться, так как в нем частично не соответствовал формат ключей для передачи параметров в метаданных. Второй вариант оказался проще в конфигурировании со стороны инженера и первичной настройки для пользователя.

Как мы к этому пришли

Первичная кастомизация в случае обычного сервера выполняется вручную. Чтобы ускорить этот процесс и минимизировать возможные ошибки, мы отправились на поиски решения для автоматизированного развертывания VDS. Создание и конфигурирование виртуального сервера в идеале должно быть для клиента легким, бесшовным и быстрым процессом. 

Обеспечить это на практике оказалось непросто. Мы искали способ автоматического сбора и передачи пользовательских данных для создания VDS, чтобы клиент мог оперативно попасть в нее по SSH/RDP. Для этого, помимо первичных сведений про ОС и имя машины, с нашей стороны также нужно передавать IP, login и pass.

Плюсы и минусы технологий автоматического конфигурирования
Плюсы и минусы технологий автоматического конфигурирования

Первый подход с помощью Cloud-init скриптов используется на практике достаточно часто, однако функциональный набор его компонентов весьма «тяжелый». Это как стрелять из пушки по воробьям, когда тебе нужна только одна функция из десяти. 

Другая серьезная проблема, из-за которой нам не подошел этот способ, — проблема с передачей метаданных. 

Как выяснилось, обратиться к утилите от самих VMware было логичным шагом еще по одной причине: программа поддерживает много типов виртуальных машин, в том числе AlmaLinux (основанной на Centos). Тем не менее, с ней при поиске решения возникли непредвиденные проблемы.

VMware для VDS: проблемы и решения

В нашем случае при конфигурировании используется LVM для гибкого конфигурирования партиций, в т.ч авторасширение. При изменении размеров диска требовалось динамически изменять размер рутовой партиции. Это было реализовано кастомными скриптами VMware-tools.

Трудности в процессе возникли с дистрибутивом AlmaLinux, так как Centos 8 перешел в статус deprecated (устаревший), и пользователи на данный момент ищут дистрибутив RedHat, на который можно мигрировать. Решение также было найдено с помощью очередного кастомного скрипта VMware.

Контекст про Centos и AlmaLinux

Есть крупный вендор RedHat, он выпускает коммерческие дистрибутивы для предприятий. У них есть бесплатный Fork — Centos, на котором обкатывают изменения и нужные вносят в RedHat. Мы используем для работы стабильную версию Centos 7. Centos 8 в настоящее время уже не поддерживается (с конца 2021 года). 

Пользователям нужно было куда-то переходить, так как на стабильном Centos 7 все равно старое ядро. Хотя обновления до сих пор выходят, для работы нужно что-то более свежее. Centos Stream не подходит, по той причине, что она пока не является стабильной сборкой.

Дистрибутив AlmaLinux от оригинального разработчика Centos, с другой стороны, вышел не так давно и быстро набрал популярность. Также на базе Centos 7 существует CloudLinux 7, он используется для решений по хостингу. На базе AlmaLinux существует CloudLinux 8. И на основе всего CloudLinux — Rocky Linux. 

В итоге у пользователей, которые хотят перейти с Centos 8, есть несколько вариантов «апгрейда»: либо на Rocky Linux, либо на AlmaLinux, либо на CloudLinux.

В двух словах:

  • Почему не Centos 7 — старое ядро

  • Почему не Centos Stream — пока не является стабильной сборкой

  • Почему не CloudLinux или RockyLinux — платное и проприетарное ПО

Почему мы выбрали AlmaLinux

AlmaLinux выглядит для пользователя самым привлекательным вариантом миграции, так как существует скрипт, который позволяет совершить переход с Centos 8 на «Альму» фактически в один клик.

Дистрибутив AlmaLinux является относительно новым, и у этого быстро обнаружилась обратная сторона: VMware на текущий момент его еще не поддерживает. Чтобы утилита кастомизации заработала нужно поменять название на Centos.

Казалось бы, такой «костыль» снимает проблему, но, как выяснилось, только до момента, пока не начинаешь ставить контрольные панели. Для комфортного управления сайтом на клиентской стороне они необходимы: пользователь не всегда может сам сконфигурировать веб-сервер, базу данных, увязать это все между собой. Графическая оболочка как раз и была разработана для user-friendly управления сервером.

Мы предлагаем пользователям на выбор три платные панели (есть и бесплатные, но их пользователь может самостоятельно установить отдельно): 

  • Cpanel — сочетается с Centos 7, AlmaLinux 8, Ubuntu 20.04

  • Plesk — сочетается со всеми стабильными версиями OS, в том числе Windows

  • ISP Manager 6 — сочетается со всеми стабильными версиями OS, кроме Windows

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

Для установки используется ansible. Мы написали специальные плейбуки, которые разворачивают панели, исходя из установленной ОС, и автоматически исправляют описанную выше проблему с AlmaLinux. 

При установке, когда AlmaLinux меняется на Centos, уже работают кастомизационные скрипты,  привязан IP, сформировался пароль и hostname. С установкой панели поверх ОС возникает обратная проблема: требуется временно «превратить» Centos обратно в AlmaLinux, чтобы поставить панель, и затем снова в Centos, чтобы все корректно работало. 

Ansible делает все это самостоятельно, избавляя инженера от рутинных задач.

Приключения со стороны backend

Технически стояла простая задача: собрать все данные (ОС, панель, имя машины, пароль, IP, собрать данные от пользователя) и передать в VMware. Данные собираются не вручную, а с помощью визарда, который по шагам спрашивает параметры VDS с учетом определенных правил валидации.

Использование vApp — лучшая практика VMware. А без него есть риск нестабильной работы архитектуры софта. Поэтому использование vApp было ключевым условием для решения задачи.

Что такое vApp?

vApp — это контейнер, где размещаются VDS. Он позволяет объединять несколько виртуальных машин по их назначению и управлять ими как одной единицей. Шаблон vApp (vApp Template) — это образ VM с уже установленной ОС, настроенными приложениями и другими данными. Сеть vApp (vApp Network) создается при развертывании vApp и удаляется вместе с ним.

Для сетевой части изначально было намерение использовать программно-аппаратный комплекс Fortigate (внешний провайдер, который позволяет нарезать скорость сети). Однако сейчас есть возможность работать не со всеми зарубежными решениями, поэтому пришлось искать другие. 

У компании VMware есть свои SDK для разных языков программирования и интеграции со своей технологией. Мы выбрали SDK для Golang. Это должен быть набор китов для разработчиков, который упрощает работу с внешним API. В нашем случае он упрощал только каждое новое обращение к VMware. Из-за того, что эта SDK написана с некоторыми недочетами, мы экономим чуть меньше времени, чем хотелось бы (но экономим!). 

Нам встретились и любопытные баги, как мелкие мы не можем изменить размер VDS, пока не поставим галочку «смена пароля после первого запуска», так и достаточно крупные. О самом крупном ниже.

Проблема дублирования заказов

У нас есть такая сущность, как Edge Gateway. Это шлюз, через который VM «ходит в мир». Он нужен, чтобы сообщить профиль (QoSProfile), что отвечает только за шейпер (скорость сети). 

На каждого пользователя выдается один vApp, то есть клиент может заказать одну или несколько VDS, и все его заказы будут сформированы в один такой кластер. 

Почему мы решили действовать именно через «эджи», вешать шейпер и бить сетки

Тема заслуживает отдельного материала, и мы постарались осветить ее во второй статье.

У нас есть N таких «эджей» (например, 130) — пустых хранилищ — и туда привязывается Network. Каждый раз, когда мы добавляем VDS, уменьшается количество свободных «эджей». Мы написали действие, которое говорит: «дай нам первый попавшийся свободный «эдж» (свободный, то есть, к которому не привязана ни одна сеть). Создается первый заказ, появляется первая VDS. Мы начинаем привязывать сеть, и по завершении система показывает, что Edge Gateway занят. 

Ранее наблюдался баг: если клиент одновременно заказывает две VDS, то система еще не успевает понять, что сеть для нее уже занята и выдает повторно №Х. Происходит конфликт из-за того, что между запросом, привязкой сети и занятием «эджа» проходит некоторое время. Для первой VDS запрашивается первый попавшийся слот, и он выдается. Для второй также запрашивается первый попавшийся…и это оказывается тот же самый «эдж», потому что сеть к нему еще не успела привязаться. Система не подтвердила, что он занят и индексируется как свободный. Получается ошибка. 

В настоящее время баг решен через блокировку взаимного исключения (mutex) в Golang. Суть в том, что первый запрос свободного слота выполняется по «чекпоинту», расставляя значения true/false. И когда второй запрос начинает выполняться, он проверяет значения чекпоинта и ждет до тех пор, пока не получит false.

Длинное объяснение, как работает синхронизатор

Вместо названий даны условные номера:

  • c{n} - метод с именем n запущен

  • b{n} - метод с именем n не может быть запущен из-за запущенного блокирующего метода

  • d{n} - метод с именем n завершен

Кто кого блокирует:

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

3 метод блокируется методом 3 (только в одном экземпляре), методами 2 и 1 (не может быть запущен пока работают методы 1 или 2);

2 метод блокируется только методом 3;

1 метод блокируется только методом 3;

т.е. параллельно могут быть запущены только один метод 4 И только один метод 3 ИЛИ любое количество методов 2 и 1.

Объявление вышеупомянутых блокировок в коде

syncer := methodSynchronizer.NewSynchronizer(map[string][]string{
   "1": {"3"},
   "2": {"3"},
   "3": {"3", "2", "1"},
   "4": {"4"},
}),

Что происходит на схеме: 

Вызов метода 1: Успешно
Вызов метода 4: Успешно
Вызов метода 2: Успешно
Вызов метода 4: Блокируется запущенным методом 4
Завершение метода 4

Вызов метода 4: Успешно
Вызов метода 1: Успешно, параллельно запущено сразу два метода 1
Вызов метода 3: Блокируется запущенным методом 1 или 2

Завершение метода 2
Завершение метода 1 (первого)
Завершение метода 1 (второго)

Вызов метода 3: Успешно
Вызов метода 2: Блокируется запущенным методом 3
Вызов метода 1: Блокируется запущенным методом 3
Вызов метода 3: Блокируется другим запущенным методом 3
Завершение метода 3
Завершение метода 4

Как видно четвертый метод работает независимо от всех, не давая запустить только свой дубль, третий метод блокирует методы 1,2,3, а методы 1,2 не блокируют друг друга и себя, но блокируют метод 3.

В рамках VDS методом 3 служили терминация и активация – эти методы должны были блокировать выполнение любых действий, при этом важно было позволить выполнять остальные действия параллельно. Все эти ограничения действуют в рамках одного пользователя, разные пользователи могут запускать метод 3 независимо друг от друга.  


Синхронизатор для разных пользователей (контекстов)

Блокировка методов такая же как в прошлом примере

Контекст 1 — слева; контекст 2 — справа
Контекст 1 — слева; контекст 2 — справа

Что происходит на схеме:

Вызов метода 1 в контексте 1: Успешно
Вызов метода 3 в контексте 1: Блокируется запущенным методом 1
Вызов метода 4 в контексте 1: Успешно

Вызов метода 3 в контексте 2: Успешно, т.к. в контексте 2 нет запущенных методов, блокирующих метод 3

Вызов метода 3 в контексте 1: Все ещё блокируется запущенным методом 1

Вызов метода 4 в контексте 2: Успешно, т.к. в контексте 2 нет запущенных методов, блокирующих метод 4

Завершение метода 1 в контексте 1

Вызов метода 3 в контексте 1: Успешно, т.к. в контексте 1 нет запущенных методов, блокирующих метод 3
Завершаем все методы

>> Мы можем свободно запускать метод 3 для пользователя 2, даже если у пользователя 1 запущен метод, блокирующий запуск метод 3. 

Для пользователя 1 при этом мы не можем запускать метод 3.

На языке VDS: Мы можем свободно делать терминацию или активацию двух VDS у разных пользователей, но если эти VDS у одного пользователя, то одна из них попадет в очередь.

Проблема удаления VDS

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

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

Мы нашли следующее элегантное решение: 

  1. Создаем новый vApp (по сути клонируем его). 

  2. Переносим в него все VDS, которые не нужно отключать. К нему привязываются те же сети. 

  3. Старый vApp удаляем, соответственно, удаляется его связь с сетью. 

  4. После чего Network остается привязанной только к новому vApp, который теперь становится основным. 

  5. Все мигрированные VDS продолжают работать в штатном режиме, в том числе в процессе переноса.

Что в итоге

  • Самостоятельно написали SDK, которая полностью работает с VMware 

  • Обеспечили автоматизированную установку панелей на VDS

  • Настроили автоматическую конфигурацию сети для каждого клиента

  • Наладили автоматический ресайз партиций при изменении конфигурации хранилища виртуальной машины для ОС семейства Linux и Windows.

Мы создали универсальное, полностью автоматизированное решение по быстрой сборке VDS, которое можно адаптировать к работе с любой SDK. Снимается нагрузка с DevOps, автоматически происходит смена IP. Тарифы на VDS, которые ранее можно было проапгрейдить для уже существующей VDS только по «блочному» принципу по группам параметров, теперь можно удобно кастомизировать в рамках любого отдельного параметра.

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

Также мы расширили парк поддерживаемых ОС, добавили свежие, при этом стабильные дистрибутивы. Самое главное — нам удалось успешно выдержать баланс между удобством и безопасностью. 

В следующей статье расскажу, почему мы выбрали именно Edge Gateway для решения сетевой части задачи. А пока приглашаю в комментарии высказаться тех, кто сталкивался в своей работе со схожими задачами, как вы их решали?

Tags:
Hubs:
Total votes 8: ↑7 and ↓1+8
Comments6

Articles

Information

Website
ddos-guard.net
Registered
Founded
Employees
101–200 employees
Location
Россия
Representative
netguard