Тестовый контур как спасение при частых релизах — Блог Work Solutions
Тестовый контур как спасение при частых релизах
ГлавнаяБлогКак мы работаемТестовый контур как спасение при частых релизах
Как мы работаем07 июля 2022

Тестовый контур как спасение при частых релизах

Фотография автора
Игорь ПомилуйкоTech Lead

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

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

Немного о проекте

Сейчас проект представляет собой два приложения. Фактически, одно приложение  — это копия второго, но с незначительными различиями. Каждое приложение поделено на сервисы. Условно назовем их Frontend, Backend и X-API.

Изображение статьи

Что представляют из себя эти сервисы?

Frontend

Уже наверное все привыкли, что frontend — это приложение на angular/react/vue или чем-нибудь подобном. В нашем случае это стандартное приложение на php + jquery, в котором работают пользователи.

Backend

Предоставляет API для нашего фронта, у него есть своя база данных, а также большое кол-во интеграций с внешними API.

X-API

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

  • Взаимодействие между сервисами происходит по SOAP. 
  • Устаревший стек: PHP 7.1, Zend 2, MySQL 5.6;
  • Объемная кодовая база: 400 тысяч строк кода на одно приложение, без учета шаблонов; 
  • Отсутствие автотестов; 
  • Сложная предметная область и несколько бизнес-доменов; 
  • Десятки интеграций API от различных поставщиков услуг;
  • Отсутствие моковых данных для API;
  • Плохо структурированный код с классами на пять тысяч строк кода;
  • Сотни предупреждений от PHPStorm;
Изображение статьи

Начало работы

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

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

И тогда мы разработали дорожную карту по улучшению системы:

Изображение статьи

Основные моменты, которые можно выделить:

  • Миграция на Symfony
  • Обновление PHP
  • Обновление Mysql
  • Тестовый контур
  • Рефакторинг кода
  • Внедрение Unit-тестирования
  • Реализация Mock-API поставщиков

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

С какими проблемами мы столкнулись

Как должно было быть:
Есть ветка master для прода и ветка dev для тестового сервера. Разработчик делает задачу в ветке, созданной от master. Отправляет ветку на code-review. Ревьювер мержит в dev и отправляет на тестирование. В случае успеха задача идет в master. 

Как было на деле:

В какой-то момент в dev скопилась куча задач. Это релизы, которые еще рано выливать в master, а также задачи, которые не прошли тестирование. И тогда у нас пошел рассинхрон с веткой master и начались проблемы с тестированием.

В ветке от master код работает, но после слияния с dev работает не так, как хотелось бы. Пошли постоянные merge-конфликты, что съедает время и знатно портит настроение.

Изображение статьи

Помимо прочего, релизам нужны свои тестовые стенды. Для примера:

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

И вот представьте: внутренние тестировщики все проверили, подошла наша очередь, и разработчик что-то ломает во время исправления бага в совершенно другом месте. Все, test-failed, ждем еще месяц. Неприятно, поэтому нужно что-то делать.

Тестовый контур: требования

Прежде чем делать тестовый контур, мы сформировали основные требования:

  • Одновременно может быть запущено множество стендов. У нас 9 разработчиков на проекте. В день может быть реализовано с десяток задач и нужна возможность их изолированного тестирования;
  • Создание стенда не должно вызывать сложностей и занимать много времени;
  • То же касается и удаления стенда. В противном случае есть вероятность, что старые стенды будут висеть и потреблять ресурсы;
  • Так как постановка задач происходит в Jira, то хотелось бы иметь с ней интеграцию: при переводе задачи на тестирование автоматически создавать площадку, при успешном прохождении тестирования удалять. И желательно еще автоматически добавлять в задачу ссылку на эту площадку;
  • Ну и конечно же требуется знать, какие площадки у нас запущены.

Теперь мы понимаем, чего хотим, и можно приступать к реализации.

Тестовый контур: реализация

Проектирование

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

У нас есть 2 сервера: сервер управления и сервер тестирования.

На сервере тестирования запускаются стенды, происходит это в Docker и поверх работает Reverse-proxy.

На сервере управления развернут CI-сервер, registry, приложения для удобного управления этим всем и интеграции с Jira.

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

Инфраструктура как код

Решили автоматизировать процесс настройки серверов согласно современным DevOps практикам и инструментам. 

Ansible

Создали инфраструктурный репозиторий, в него сохранили все конфигурации с использованием Ansible. Например, если нужно настроить сервер, добавить пользователей, установить cron или docker — пишем ansible-роль. Деплой компонентов управления — еще одна ansible-роль, деплой приложения тоже. Это позволило разработчикам собирать тестовые стенды локально. 

Изображение статьи

Jenkins


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

1. Сборка базовых версий образов PHP, MySQL, Nginx. Базовая версия — это конкретная версия PHP и установленные на ней утилиты. В общем, все окружение кроме кода.

Изображение статьи

2. Снятие дампов БД и упаковка их в образы. Снятие дампов по крону происходит раз в неделю, и сама упаковка занимает около 30 минут. Но это делается один раз, а потом данные в виде готовых образов запускаются на тестовом сервере.

3. Основная задача — это сборка площадок. Сюда входит сборка образов и запуск их на тестовом сервере. 

4. Удаление площадок для освобождения ресурсов. Это остановка приложения, чистка стенда и удаление образов из Registry.

В итоге получается такая схема:

Изображение статьи

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

Кастомная панель управления

Найти готовое решение с нормальным пользовательским интерфейсом не удалось, поэтому решили написать сами. Выбрали стек Django + Vue + Vuetify. Силами одного разработчика реализовали нужную функциональность всего за две недели:

Изображение статьи

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

  • Настройки. Например, ключ доступа к Jenkins или к GitLab. Грубо говоря, key-value хранилище данных
  • Конфигурация стендов. Это три сущности: проект, сервис и площадка.

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

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

Вместе проект и сервисы служат шаблоном для стенда, то есть из настроек проекта и сервисов формируются параметры стенда. Параметры можно переопределить. Эти параметры превращаются в параметры триггеров для пайплайнов в Jenkins.

  • Интеграции с Jira, Jenkins, Docker-registry, Gitlab и Traefik.

Traefik

Отдельного внимания здесь заслуживает Traefik. По нашему мнению, это лучший в мире reverse-proxy для Docker. Другие инструменты мы особо не проверяли, но когда изучили, как это делается в Nginx, то пришли в ужас и решили применять Traefik.

Чем он так хорош? Тем, что он может заставить приложение открываться по определенной ссылке. Например, эти 4 строчки делают доступным контейнер по нужному нам URL-адресу стейджа: 

Изображение статьи

Это вся конфигурация. У самого Traefik тоже есть настройки, но они такие же простые.
Для экономии мощностей мы решили внедрить правило, что запущенные стенды должны удаляться каждую ночь, но быстро столкнулись с проблемой.  Тестировщик не всегда успевает проверить задачу до удаления площадки, и на следующий день он видит 404-ошибку.

Traefik помог и в этой ситуации. Добавили мини-приложение — обработчик 404-й ошибки. Теперь, когда тестировщик заходит на площадку, он может сам запустить создание площадки по кнопке:

Изображение статьи

Registry + Portainer

Все наши образы хранятся в Docker-registry. В текущей ситуации он пригодился, так как Elastic и Logstash больше нельзя скачать без VPN. Но они теперь есть в нашем Registry.

Из минусов — тут не очень удобно реализовано удаление образа по тэгу. Метода удаления по тэгу попросту нет. Чтобы удалить, нужно сначала запросить хэш манифеста по тегу, удалить манифест по полученному хэшу и запустить сборщик мусора внутри registry. Только тогда registry почистит место. Неудобно, но терпимо.

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

Итоги

Мы избавились от боли при merge в dev-ветку. Теперь мы больше не теряем на этом время. Можем получить столько тестовых стендов, сколько нужно, причем делается это быстро. Площадка разворачивается в среднем за 4 минуты.

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

Получили средство для обкатки новых инструментов. Приложение на PHP 7.4 запускается в пару кликов.


Изображение статьи

Материал был создан на основе выступления в рамках RND PHP митапа, прошедшего 14 мая 2022г. Запись трансляции доступна по ссылке.
 

2.9к
173

Другие статьи

Ко всем статьям
Фоновое изображение: четверть круга закрыват часть круга

Интересные статьи и кейсы
от Work Solutions

Нажимая кнопку «Подписаться», я даю согласие на обработку персональных данных

Спасибо за подписку!

Фоновое изображение: верхний полукруг