Авторизация
Забыли пароль?
Сброс пароля
Вернуться к авторизации

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

24 октября ‘22

Заказчик: Випсервис

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

Агентство-исполнитель кейса

Work Solutions

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

1. Вводная задача от заказчика, проблематика, цели

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

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

Сейчас проект представляет собой два приложения. Фактически, одно приложение — это копия второго, но с незначительными различиями. Каждое приложение поделено на сервисы. Условно назовем их 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;

Cтруктура сервиса

Состояние проекта до начала работ

2. Описание реализации кейса и творческого пути по поиску оптимального решения

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

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

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

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

Как должно было быть:

Есть ветка 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.

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

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

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

Registry + Portainer

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

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

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

Дорожная карта по улучшению системы

Схема сборки тестовых стейджей

Панель управления

3. Результаты сотрудничества

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

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

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

4. Заключение

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

Агентство-исполнитель кейса

Work Solutions

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