Главная » Хабрахабр » Готовим тестовое окружение, или сколько тестовых инстансов вам нужно

Готовим тестовое окружение, или сколько тестовых инстансов вам нужно

Сколько в вашем проекте тестовых стендов — 5, 10 или больше 10? Навскидку, нужны стенды для каждой команды разработки, стенды для QA под каждый проект, менеджерам проектов тоже нужны стенды, а еще CI — трудно это все точно разграничить и не вызвать конфликтные ситуации. Одним словом, почему бы нам не делать тестовый стенд ровно тогда, когда он нужен? Нужен сейчас тестовый стенд — мы его сделали, не нужен — мы его удалили.

Именно такой подход предложил Александр Дубровин (adbrvn) на Highload++ 2017 в своем докладе, расшифровку которого вы найдете под катом.

Известно, что проекты этой компании высоконагруженные. О спикере: Александр Дубровин работает в Superjob. Но сегодня мы не будем говорить о том, сколько пользователей посещают портал, и сколько данных хранится на серверах, а затронем другие показатели.

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

Немного истории

В нем есть команда разработчиков, которым надо где-то тестировать свой код. Представим себе небольшой проект S. Чтобы организовать тестирование, мы поставим тестовую машину, сделаем ее похожей на продакшен, накатим туда код, запустим и разработчики смогут там что-то тестировать.

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

Все замечательно и хорошо! Можно использовать простой подход — выделить какой-то участок для тестировщиков, накатить туда такую же копию, и вот они уже могут тестировать.

Проект продолжает расти, и появляется дополнительная команда разработки. Им также требуется где-то что-то тестировать. Подход уже знаком — мы отделяем еще одну часть тестового сервера.

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

Допустим, есть тестировщик Вася, который хочет протестировать какую-то задачу. Примерно в такой стадии можно начать замечать интересные истории. Кликает, кликает и понимает, что что-то не то, что-то не работает, и вообще задача не сделана. Он выбирает тестовый стенд, раскатывает туда код и начинает тестировать.

Все же сделано!» и кто-то наконец спрашивает: «А у тебя какая ветка на тест раскатана?» Вася смотрит — не та. В JIRA начинают падать тикеты, возле Васи начинают собираться разработчики со словами: «Да как же так? Вася продолжает тестировать, у него все работает. Ветка быстро исправляется, тикеты в JIRA закрываются, все хорошо.

Раскатывает ту, что нужно, и проблемы снова у Васи. Но в это время в другом конце комнаты разработчик Вова думает: «Странно, а почему у меня не работает?» Но он быстро понимает, что ветка не та.

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

Разработчик Коля знает про Васины проблемы, заранее приходит к нему и спрашивает, какой тестовый стенд сейчас свободен. Другая история. Через пару дней они встречаются снова, и Вася спрашивает у Коли: «Ты нам тестовый стенд вернешь? Вася указывает свободный, и все хорошо. Ты его занимал на часок, а уже 2 дня прошло».

И снова проблема — либо разработчику искать другой стенд, либо все будут бодро ждать, пока он закончит тестирование.

Здесь не хватает менеджеров. На самом деле на схеме выше отображено не все. Подход стандартный — мы снова выделяем уголок тестового сервера и делаем еще тестовые стенды. Иногда менеджеры хотят смотреть еще не протестированный сырой код.

Самая последняя часть этой системы — это конечно CI — он тоже хочет куда-то стрелять, где-то тестировать.

Схема плоха тем, что мы действительно не контролируем такие стенды — мы не знаем: Плавно развивая такую схему, мы получаем бесконтрольное изменение тестовых стендов.

  • кто тестирует на этом стенде в данный момент;
  • что там раскатано;
  • мы вообще не знаем, занят он сейчас или свободен.

Более того, мы не знаем, какие тестовые стенды сейчас свободны, может быть, на какие-то в это время стоит очередь.

Идея

В этот момент мы задумались — что же делать? Зачем нам столько тестовых стендов? Почему бы нам не делать тестовый стенд ровно тогда, когда он нужен? Нужен сейчас тестовый стенд — мы его сделали, не нужен — мы его удалили.

Следующий шаг в этой идее — делать тестовый стенд под каждую ветку кода.

Нам нужны стенды: Вроде идея хорошая, но есть технические нюансы.

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

В идеале нам хочется одну кнопку «Сделать тестовый стенд».

Суровая реальность

Еще есть суровая реальность, в которой у нас:

  • Большой сложный проект — огромный php монолит с достаточно большой историей.
  • Сервис в четырех доменных зонах. Мы одновременно поддерживаем российскую, украинскую, узбекскую и белорусскую зоны.
  • Куча поддоменов —геоподдомены и сервисные поддомены — такие, как API, students.superjob.ru и прочее.

И все это в какой-то момент тестировщики захотят протестировать. Даже если мы сейчас не тестируем это на Украине, завтра появляется задача сделать для украинской части специальную страничку — это нужно тоже учитывать.

Сказано — сделано!

Docker/docker-compose

В наше время это позволяет реализовать docker. Во-первых, мы говорили о том, что тестовые стенды должны быть изолированными и максимально похожими. Очевидно, что одним контейнером мы не обойдемся, более того, нам надо запускать кучу похожих стеков. Он даст возможность запускать контейнеры. Поэтому нужен docker-compose.

Замечательно — мы будем использовать docker — это стильно, модно, молодежно.

Распиливаем монолит выделяем сервисы

Docker пропогандирует микросервисный подход и здесь мы встаем перед проблемой, потому что у нас монолит.

Очевидно, что эта цифра измеряется в человеко-годах.
Вы когда-нибудь пробовали оценить, сколько стоит распилить монолит по микросервисам?

В какой-то момент мы посмотрели на компонентную схему нашей системы и увидели, что здесь у нас есть load-balancing, здесь — приложение на php, здесь — node.js-приложение. Почему бы нам не запускать именно это, как сервис. Давайте найдем то, что мы можем запускать в docker-контейнерах.

Настраиваем сеть

Естественно, нам необходимо вытащить 80-ый порт наружу, чтобы браузер мог открыть наш тестовый стенд, но если такие стенды будут запускаться в рамках одной машины, нам нужно выдавать IP. Дальше нам необходимо каким-то образом достучаться до нашего тестового стенда.

В документации имеется целый огромный раздел про настройку сетей.

В нашем случае очень помогла сеть типа macvlan. Docker умеет использовать различные типы сетей. При этом docker сам будет управлять этими интерфейсами: создавать, добавлять на машину и получать уже внешние, по отношению к хост-машине, IP-адреса. Это технология, которая позволяет на одном физическом сетевом интерфейсе реализовывать пачку виртуальных сетевых интерфейсов.

Мы уже можем постучаться туда при помощи браузера. Таким образом мы можем запустить пачку контейнеров, дать фронт-контейнеру (балансеру) возможность получить внешний IP-адрес и открыть на нем 80-ый порт.

Поднимаем DNS и API

Таким образом, обратиться к тестовому стенду мы можем только по домену 2-го уровня. Мы помним, что у нас есть доменные зоны и куча поддоменов. Здесь есть как колоссальный плюс, так и колоссальный минус:

  • Минус — нам очевидно придется каким-то образом перекрывать реальные домены в зоне ru, ua, uz, by.
  • Плюс — в качестве домена 2-го уровня можно зашить прямо конкретное название ветки — мы же делаем тестовые стенды под каждую ветку кода.

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

Если нам приходится перекрывать домены, мы просто добавляем префикс и таким образом ограничиваем набор перекрываемых доменов — с этим уже можно мириться. Минус обходится на самом деле просто.

Получается, нам приходится перекрывать домены только с префиксом sj — таких явно немного. В нашем случае мы выбрали префикс sj.

Как уже говорилось, необходимо поднимать тестовые стенды быстро. Еще одна часть DNS — это API. Поэтому нам нужен DNS-сервер, который позволяет быстро добавлять и быстро убирать запись по API в автоматическом режиме.

Этот сервер позволяет достаточно быстро и просто прикрутить к нему API и при помощи скриптов добавлять и удалять тестовые стенды. Решение — PowerDNS.

Мы подняли и настроили DNS, научили наши контейнеры в него прописывать свои IP, но чего-то не хватает. Замечательно!

Делаем SSL-CA

Очевидно, что весь интернет — SSL и тестовые стенды должны поддерживать SSL. Мы живем в XXI веке. Достаточно много багов специфичны для SSL, и mixed content — только вершина айсберга.

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

Велосипед пишется за один день и позволяет при помощи GET-запросов получать сертификаты, сгенерированные уже на конкретное имя домена.

Нужно это автоматизировать, потому что мы же хотим все это делать одной кнопкой. Осталось самое малое.

Автоматизируем

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

Поэтому можно, например, сделать специальную сборку, которая соберет тестовый стенд и запустит его. Очевидно, тестировщикам это не очень удобно.

Представьте, ваш тестировщик открывает JIRA-тикет, читает требование, нажимает кнопку и получает через пару минут тестовый стенд — здорово же? Но на самом деле самый крутой шаг в этом плане — это добавить такую кнопку прямо в JIRA-тикет.

Плюсы

  • Изначально мы планировали это именно под ручное тестирование, чтобы тестировщик мог запустить и прокликать любую версию своего кода, и это круто заработало.
  • Следующий дополнительный бонус — у нас появились демо-хосты. Это то же самое, только в JIRA-тикет заходит не тестировщик, а менеджер проекта. Он тоже может посмотреть и покликать сырой код.
  • Мы получили колоссальный плюс для CI. Когда мы обучили CI точно так же поднимать тестовый стенд на конкретную версию кода и потом его удалять, у нас появилась возможность запускать абсолютно любые тесты для любой ветки. Даже самые сложные интерфейсные selenium тесты я могу одним кликом прогнать для любой ветки в моем проекте.

Минусы

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

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

Тогда, мы перестали их создавать автоматически, а появилась кнопка в JIRA, CI научилась запускать и останавливать тестовые стенды, собирать с них логи.

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

Итог

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

Было: «Вася, а какой тестовый свободный — мне свою задачу раскатить потестировать».

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

Стало: «Жму кнопку и через полторы минуты получаю новый тестовый стенд под конкретную задачу».

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

Я не знаю, сколько нам нужно тестовых стендов, потому что сегодня их нужно 20, завтра — 15, послезавтра 25. Возвращаясь к своему первому вопросу, сколько же тестовых стендов нам нужно?

Но я точно знаю, что у нас ровно столько тестовых стендов, сколько нужно здесь и сейчас.

Пользуясь случаем, приводим небольшую подборку заявок RootConf для широкого круга слушателей: Время летит незаметно, и до фестиваля конференций РИТ++ осталось совсем немного, напомним он пройдет 28 и 29 мая в Сколково.

Забронировать билеты еще можно, но, не забывайте, цена неуклонно растет.


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

PHP-Дайджест № 137 (6 – 20 августа 2018)

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

Ну и куда теперь девать эти двигатели?

Недавняя публикация о возрождении и развитии двигателя SSME (RS-25) вызвала в ЖЖ наплыв лунных конспирологов в комментариях — судьбу двигателя шаттла они сравнивали с F-1 от Saturn V. Так что сегодня мы сыграем в игру «почувствуй себя руководителем Rocketdyne» и ...