Хабрахабр

Непрерывная интеграция в Unity: как сократить время сборок и сэкономить ресурсы + пайплайн в подарок

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

В этой статье речь пойдёт о CI/CD для реализации наших Unity-проектов для мобильной геймдев-разработки: с какими проблемами мы столкнулись, как их удалось решить, каких улучшений мы добились и как прописан наш пайплайн сборок билдов. Платформы непрерывной разработки и интеграции, или CI/CD, сейчас используются повсеместно в тех отраслях, где решающую роль играет итеративность и отлаженность технических процессов.

Сразу договоримся, что в качестве сервера CI мы используем TeamCity от JetBrains, в качестве хранилища Git-репозиториев ― GitHub, для хранения артефактов сборки ― Nexus.
Итак, перед нами возникли следующие проблемы:

  • Отсутствие общего стандарта создания сборок: доступ к серверу TeamCity был практически у всех разработчиков, в результате чего скрипты сборок писались на разных языках программирования (BASH, PowerShell, Python), и логика часто дублировалась;
  • Слабый парк машин: из-за того, что нам необходимо собирать билды для iOS, приходилось использовать парк машин из Mac mini. И поскольку в Unity практически вся сборка происходит в один поток, распараллелить сборки на одной машине оказывалось делом проблематичным;
  • Мало отлаженная оперативность работы: из-за низкой производительности нашего технического обеспечения сборки происходили очень долго;
  • Большие очереди в ожидании сборки при наличии достаточного количества агентов TeamCity;
  • Отдельный пул агентов для каждого проекта: в связи с различным установленным окружением на устройствах, а также конфликтующими между проектами конфигурационными файлами (файлы настройки кэш-сервера и т.д.) невозможно было организовать общий пул.

Что в результате сделали?

  • Репозиторий для сборочных скриптов

В первую очередь мы завели единый репозиторий скриптов для сборок на Python. Запуск производится в среде управления виртуальным окружением Pipenv с проксированием сторонних библиотек на своем сервере для быстрого обновления и контроля версий необходимых библиотек. Таким образом мы обеспечили единую точку входа для сборок всех существующих проектов. Переписали все скрипты на Python, унифицировали конфигурации, привели к общему стандарту, убрали дублирования кода.

  • Новый парк машин

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

Добавим к этому солидное количество обращений на запись к жёсткому диску и получим, что один Mac mini едва справляется с 1-2 одновременными сборками. Изначально у нас была ферма из 13 компьютеров Mac mini, но данное решение далеко от оптимального: ввиду особенности сборок на Unity около 80% времени сборки будут производиться только в одном потоке.

Результат ― необходимость пересмотра технического обеспечения.

В ходе поиска и сравнения альтернатив по Unity-сборкам мы заметили, что компьютеры на базе AMD Ryzen благодаря своей производительности позволяют собирать до 8-12 сборок одновременно без существенной потери производительности, в связи с чем было решено закупить четыре таких устройства с шестью SSD и установить по два агента на каждый жёсткий диск.

Сравнение того, как было и что стало, приведено в таблице.

Среднее время сборок:

Раньше у каждого нашего проекта был свой пул агентов, и ввиду мультиплатформенности игр проектно-зависимое окружение не позволяло создать общий пул. Кроме того, мы организовали приоритезацию выбора агентов TeamCity для уменьшения времени нахождения сборки в очереди. Теперь, после реорганизации работы системы, мы оставили ряд закрепленных за проектами агентов, которые служат для автоматических сборок, но смогли добавить и несколько общих агентов для всех проектов: они включаются в работу, когда заняты все агенты, привязанные к нужному проекту.

  • Библиотека BuildPipeline для Unity

Завели небольшую библиотеку для Unity, которая даёт возможность задавать настройки сборки билдов в отдельном окне редактора Unity, а также обладает возможностью запускать сборку билдов в режиме batchmode. Из основного функционала библиотеки: она позволяет добавлять и удалять defines перед сборкой, отключать сторонние библиотеки или конкретные файлы, добавлять кастомные шаги пре- и пост-обработки, все её настройки хранятся в конфигурационных файлах, также есть возможность их наследования.


Окно defines в библиотеке BuildPipeline

Наш текущий пайплайн CI/CD

Сборка PullRequest. Для каждого коммита производится:

  1. запуск Unity для проверки на ошибки компиляции, обновления defines и генерации решений;
  2. запуск тестов;
  3. запуск статического анализатора: с его помощью производится инкрементальный анализ на файлы, затронутые в рамках текущего PullRequest;
  4. сообщение о результате проверки, которое сохраняется в GitHub.

Шаги сборки Unity-проекта:

Установка Pipenv и запуск скриптов для сборки на Python: обновление и установка сторонних библиотек Python с нашего сервера (проксирование хранилища pypi.org) и последующий запуск скрипта сборки. 1.

Предварительная подготовка для сборки Unity: 2.

  • удаление папки Library, Bundles, выборочных ассетов (по маске и/или конкретных файлов), удаление solutions (файлов .sln) ― при необходимости;
  • генерация файла с информацией о сборке: наименование ветки, номер сборки и проч. ― для дальнейшего использования в билде для отладки и тестирования;
  • установка кэш-сервера Unity для проекта. У каждого проекта он свой. Также у каждого разработчика выставлен кэш-сервер для более быстрого наполнения: при добавлении разработчиком нового ассета он автоматически появится на кэш-сервере и на сервере сборки, ― таким образом импорт ассетов происходит гораздо быстрее.

3. Запуск Unity для проверки на ошибки компиляции, обновление defines и генерации решений.

Запуск тестов и выход из них при наличии ошибок ― при необходимости. 4.

Запуск Unity BuildPipeline с указанием нужной конфигурации и дополнительных параметров проекта. 5.

Для сборок Android/iOS ― запуск Gradle/Xcode: 6.

  • Gradle ― GradleWrapper;
  • XCode ― архивируем XcodeProject, полученный после Unity, и копируем его на Mac mini. Отдельно устанавливаем и обновляем все необходимые сертификаты и файлы Provisioning Profile. Запускаем команды Clean, Archive, Export.
  • На этапе экспорта есть возможность разделения подписи билда, разработчика и AppStore. В зависимости от того, что собираем, выбираем нужный plist, либо каждый по очереди. На выходе получаем два файла: Developer и Release ― для установки на тестовые девайсы и для заливки в AppStore соответственно.

7. Заливка собранных билдов и сопутствующих файлов (логи, результаты тестов, .obb, manifest для установки iOS приложений, dsym-файлы и т.д.) в хранилище артефактов, для standalone-сборок ― заливка в хранилище архива собранного билда.

Генерация страницы с QR-кодом для установки билда, добавление ссылок из хранилища и информации по билду в базу данных для дальнейшей работы с приложением PixLauncher ― о нем расскажем далее. 8.

Сообщение в Slack о результате сборки: тому, кто запустил сборку, а также в необходимые каналы. 9.


Такие сообщения приходят в Slack

Дальнейшие шаги

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

Его мы устанавливаем на каждое устройство, где есть возможность выбора билда из TeamCity. Для установки билдов на устройства мы написали небольшое приложение для Android и iOS ― PixLauncher. В случае билдов для Android при необходимости автоматически скачивается файл в разрешении .obb. Для удобства в нём можно установить фильтры ― например, добавить конфигурацию в избранное и далее производить действия с ней в один клик.

Затем на эти устройства поступает push-уведомление со ссылкой на установку ― таким образом она теперь осуществляется в одно нажатие. Кроме того, мы организовали возможность установки билда через push-уведомления: на сервер TeamCity мы добавили самописный плагин, который на странице с билдом позволяет выбрать MAC-адреса девайсов, подключенных к локальной сети.

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


Внешний вид приложения PixLauncher для iOS

Наконец, загрузка билдов в сторы

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

Изначально проблемы возникали по большей части с AppStore:

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

Это приводило к большим потерям времени на заливку и сбоям в загрузке файлов в админку стора. Поэтому мы задумались над автоматизацией процесса.

В результате имеем следующее:

  1. В Google Disk мы завели табличку с описанием приложения на всех языках;
  2. Видеоролики и скриншоты приложения разложили по папкам с определённым неймингом;
  3. В Teamcity для возможности выбора уже собранного билда сделали конфигурацию, зависимую от релизной сборки;
  4. Через API GooglePlay и iTMSTransporter для Apple заливаем билды и мета-информацию о приложении в стор для всех необходимых языков. При возникновении проблем (например, с сетью) ― производим несколько попыток и присылаем сообщение в Slack с текстом ошибок.


Так выглядит выгрузка билда в AppStore

В качестве итога ― немного цифр

  • Теперь у нас производится около 400 сборок и до 60 установок билдов на девайсы в день;
  • Существует 57 различных конфигураций сборок на TeamCity;
  • Мы используем 22 агента TeamCity, при этом есть возможность расширения без существенной потери производительности до 48 агентов;
  • Есть возможность горизонтального расширения парка машин.
Теги
Показать больше

Похожие статьи

Добавить комментарий

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

Кнопка «Наверх»
Закрыть