Привет! Меня зовут Карина, я QA-инженер в hh.ru. Наша компания растёт, а вместе с ней — число команд, вовлечённых в разработку и функционал. Появляются новые сервисы, базы данных, очереди. Каждый компонент требует слаженной работы и надёжной поддержки на тестовых стендах.

Наша инфраструктура прошла долгий и впечатляющий путь, чтобы справиться с этим ростом:

  • в статье 2015 года коллеги рассказали, как мы создавали окружение, похожее на продакшен, с помощью Docker и Ansible

  • в статье 2022 года мы подробно описали, как мигрировали в Kubernetes, чтобы эффективно масштабировать тестовые среды и управлять растущим числом наших микросервисов в R&D-среде

Сегодня hh работает с гибкой тестовой средой, которую можно настроить под любую задачу. В статье расскажу, как вся эта сложная система выглядит изнутри:

  • как устроены наши стенды в условиях постоянного роста функционала

  • зачем нам понадобились профили деплоя и как они работают

  • и главное —  как мы смогли упростить и значительно повысить эффективность управления стендами для каждого сотрудника hh

Что такое стенд в hh.ru и почему у каждого он свой

Наш стенд — это  виртуальная машина с операционной системой Ubuntu, на которой развернуты служебные Docker-контейнеры и контейнеры со stateful-сервисами (такие как Redis, PostgreSQL, Nginx, PgBouncer), а также namespace с микросервисами в составе кластера Kubernetes.

Главный принцип — у каждого сотрудника есть свой личный тестовый стенд. Это значит, что:

  • тестирование и разработка проходят изолированно друг от друга, и задачи коллег не повлияют на твой функционал

  • можно самостоятельно настраивать окружение в зависимости от текущей задачи

  • продуктивность не страдает, не нужно ждать, пока кто-то освободит или обновит стенд

Кроме  персональных стендов, есть специальные — их мы выделяем для конкретных задач. Они отличаются объёмом выделенных ресурсов:

  • релизные — по набору сервисов максимально приближены к проду, перед релизом на них происходит сборка и запускаются автотесты

  • для автотестов — чтобы не тратить время на настройку личного. Только е2е-тестов у нас более 2000, и полный их прогон требует полноценного окружения. Стенд всегда готов к работе и гарантированно свежий, так как пересоздаётся после каждой «аренды»

  • стенды предварительного тестирования — работают полностью автоматически. Как только задача переходит в статус "Need Testing", сборка ветки и запуск тестов происходят без участия человека. Результат оформляется в виде отчёта и прикрепляется к задаче в Jira

Сходство с продом: наш подход к IaC

Ранее развёртывание и обновление стендов производилось вручную с помощью различных скриптов. Ошибки были неизбежны, а поддержка актуальности сервисов отнимала много времени. Проблему решили с помощью подхода Infrastructure as Code (IaC). Вся конфигурация (и прода, и тестовых стендов) управляется с помощью Ansible. 

Весь процесс строится на взаимодействии двух ключевых репозиториев:

  • первый: содержит максимально унифицированные Ansible-плейбуки для прода. Данные о сервисе вынесены в файл переменных, который передаётся в эти плейбуки

  • второй: отвечает за подготовку тестового окружения, рендеринг K8s-манифестов для стендов и специфические тестовые оверрайды (когда нужно подменить продовые параметры на тестовые)

Теперь все процессы управления инфраструктурой автоматизированы, что гарантирует масштабируемость, контроль и идентичность вышеперечисленных окружений. Отговорка “it works on my machine” больше не works (хотя смотря какой deploy profile, но об этом чуть позже).

Актуализация окружения

Стенд — это не оторванная от жизни среда. Его синхронизация завязана на логике веток: каждый день в 21:00 изменения из prod-ветки автоматически мержатся в dev-ветку. Так на стенды попадают только стабильные версии сервисов, которые уже вышли в продакшен.

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

От кнопки до готового стенда

Благодаря IaC, создание стенда запускается одним нажатием кнопки, и далее всё выполняется автоматически:

  1. Для ускорения процесса из подготовленного cloud-init образа разворачивается виртуальная машина.

  2. Инициализируется namespace в кластере Kubernetes, соответствующий доменному имени стенда.

  3. Запускается основной Ansible-плейбук и разворачивается окружение для работы стенда.

  4. Раскатка инфраструктурных сервисов: база данных, очереди, Scylla, Consul и т. п.

  5. Python-скрипт, с учетом приоритетов и зависимостей, раскатывает микросервисы. Этот скрипт деплоит сервисы параллельно: существенную часть в Kubernetes и некоторые в Docker-контейнеры прямо на стенд.

  6. Для Service discovery используем Consul: большинство приложений регистрируются в нем самостоятельно, а те, где такой функционал не предусмотрен — через внешнюю регистрацию (утилиты).

Упрощённая схема, как работают наши тестовые стенды:

Архитектурно стенд — это виртуальная машина, которая служит «точкой входа». На ней развёрнуты базовые инфраструктурные компоненты и прокси-сервисы (Nginx/Squid). Сами же сервисы деплоятся в Kubernetes-кластер.

Некоторые сервисы отличаются своей ресурсоёмкостью — например, ML-сервисы. При этом их специфика позволяет использовать один экземпляр сразу на несколько тестовых окружений без потери качества тестирования. Каждый такой сервис имеет свой hostname и проксируется через reverse-proxy на стенд, где он запущен. Поэтому для таких сервисов мы используем архитектурный подход Shared Service.

Оптимизация ресурсов и времени на деплой

Выше мы уже говорили о плюсах персональных стендов, теперь пора перейти и к минусам. Создание и поддержка полноценного окружения — это колоссальная нагрузка на инфраструктуру. Сегодня в работе участвуют более 500 стендов, в каждом из которых по 150-200 сервисов. Содержать такой арсенал без оптимизации — непозволительная роскошь.

Профили деплоя

Для оптимизации мы внедрили профили деплоя — фиксированные наборы сервисов, которые позволяют не разворачивать «всё сразу», если в этом нет необходимости. 

При создании стенда выбираем один из них:

  1. Базовый профиль: содержит около 100 микросервисов, поэтому функционал ограничен, можно открыть только главную страницу hh.ru и, например, запустить генерацию тестовых данных.

  2. Общий профиль (regular): содержит около 180 сервисов, наследуется от базового и уже предназначен для работы с основным функционалом hh.ru.

  3. Кастомизированные профили: создаются на базе regular, а команды дополняют их под свои требования. Здесь также работает наследование: любые обновления в «родителе» автоматически долетают до командных профилей. Такой профиль обычно называют именем команды для удобной идентификации. Например, наша команда называется «Конверсы», а наш профиль деплоя «Converse». В результате получаем стенд, содержащий только необходимые для работы сервисы. 

  4. Релизный профиль (release): используется главным образом для релизов и стендов для прогона автотестов. Если требуется максимально приблизиться к продовой версии, мы применяем его. 

Собственная система деплоя

Помимо профилей, мы сократили и время деплоя. Разворачивать 180+ сервисов по очереди — процесс не быстрый.

Эту задачу решили системой деплоя собственной разработки. Она строит дерево зависимостей и делает развёртывание поэтапно: сначала устанавливаем базовые и архитектурные сервисы, затем все остальные сервисы деплоятся параллельно на своих уровнях иерархии.

Оптимизация БД

Работа с БД раньше была в прямом смысле тяжёлым процессом. Архив, который разворачивался на стендах, весил около 40–50 ГБ, что съедало место и замедляло деплой. Поэтому, вместо сжатия и анонимизации продовой-базы (для экономии времени и ресурсов приходилось оставлять в БД существенный объём анонимизированных данных) мы перешли на заливку чистой схемы с подкладыванием только действительно необходимых данных. Результат: объём архива сократился до 3-4 ГБ.

Управление стендами

hh.ru прошёл большой путь от ручного управления стендами к полной автоматизации. Мы гордимся этим результатом – давайте расскажу, как нам удалось его достигнуть.

Уровень I. Продвинутый пользователь Linux

Раньше весь процесс был сродни квесту. Например, для сборки ветки нужно было вручную выполнять 5-6 операций в командной строке. Долгий процесс с высоким риском ошибки — сделать опечатку или запутаться в последовательности команд было довольно легко.  

Уровень II. Разблокировано достижение: автоматизация

Вышеупомянутые неудобства решили созданием специального скрипта - hhc.py. Он заменил весь набор ручных команд, позволил упорядочить и унифицировать процесс. Теперь одна команда выполняет всю цепочку действий. Возьмём для примера процесс сборки сервиса:

С помощью hhc.py можно выполнять операции как и с различными параметрами, так и без них:

  • сборку сервиса: с указанием ветки и без запуска скриптов/ в dev-режиме/ с несколькими ветками/ с пользовательскими опциями/ …

  • деплой сервиса: определённой версии/ с дополнительными переменными окружения/ с деплоем зависимых сервисов/ …

  • запуск интеграционных тестов

Уровень III. Куда я жмал?

Венец нашей эволюции — это Crab. Команда Инфраструктуры разработала инструмент для максимально удобного и наглядного управления стендами. Веб-интерфейс предоставляет доступ ко многим операциям, часть из них реализована как обертка над скриптом hhc.py.

Интерфейс выглядит так:

Не hhc.py единым

Есть чем похвастаться помимо скриптовых операций.

Генерация тестовых данных. Больше не нужно ничего создавать вручную. Магия одной кнопки работает и здесь. Запускается цепочка:

  • Crab выступает менеджером-интерфейсом для удобного запуска генерации, далее задача передаётся в Jenkins

  • Jenkins выполняет автотесты с фикстурами, которые создают тестовые данные. Для получения живых данных часть кейсов прогоняется через WebDriver

Готово! На стенде вас ждут разнообразные вакансии, соискатели, чаты и многое другое. 

Управление жизненным циклом стенда. Для поддержания актуальности окружения мы предлагаем два варианта. 

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

  2. Полное пересоздание виртуальной машины и k8s namespace. Подходит для более кардинальных изменений, например, если нужно сменить профиль деплоя или в ходе работы «сломали» окружение.

Запуск E2E-тестов. Можно инициировать запуск сквозных (e2e) тестов, передавая параметры прямо из интерфейса.

Мониторинг состояния. Crab предоставляет наглядный интерфейс для просмотра логов и текущего состояния всех микросервисов на стенде, что важно для быстрой диагностики.

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

Дополнительные функции Crab

Автоматический планировщик задач помогает оптимизировать рабочий день и избавляет от рутины. Настройте  расписание (дни и время), и он самостоятельно запустит любые задачи. Например, пересоздание стенда с последующей генерацией тестовых данных.

Уведомления в Mattermost (платформа для командного взаимодействия, обмена файлами и интеграций) получаете уведомление с результатами после совершения любой операции. Например, логи успешной (или не очень) сборки ветки или отчёт по запущенным тестам.

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

Информационный раздел —  сведения о стендах и их владельцах, а также полная информация о командах разработки: состав, должности и контактные данные.

Заключение

Давайте посмотрим на основные результаты, которые повысили эффективность работы команд и удобство использования инфраструктуры.

  1. Скорость и масштабируемость. Благодаря IaC и системе параллельно-поэтапного деплоя время на создание стенда ощутимо сократилось. Теперь за 16 минут поднимаем 220 сервисов (против 80 ранее). 

  2. Оптимизация затрат. Гибкий механизм профилей стал компромиссом между потребностями сотрудников и экономической целесообразностью. Команды используют только то, что им действительно нужно.

  3. Удобство разработки и тестирования. Персональные стенды дают полную свободу для изолированной работы, а инструмент Crab позволяет комфортно управлять окружением. 

Все эти достижения — заслуга наших команд hh.ru: инфраструктуры, эксплуатации и k8s-команд. Они проложили путь к главной цели — дать сотрудникам возможность заниматься важным. Делегируя стандартные операции автоматике, мы освобождаем время для реализации идей, профессионального развития и креативных задач. 

Спасибо коллегам за их огромный труд и помощь в подготовке этой статьи. 

Тема стендов довольно индивидуальна — у каждой компании она своя. Будет интересно почитать в комментариях, как это устроено у вас!