Как стать автором
Обновить
0
Pixonic
Developing and publishing games since 2009

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

Время на прочтение 6 мин
Количество просмотров 9.6K


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

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

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

Итак, перед нами возникли следующие проблемы:

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

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


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

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

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

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

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

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

В ходе поиска и сравнения альтернатив по 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-проекта:

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

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

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

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

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

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

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

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

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

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

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


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

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


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

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

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

Так, приложение позволило ускорить поиск нужного билда 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 агентов;
  • Есть возможность горизонтального расширения парка машин.
Теги:
Хабы:
+28
Комментарии 8
Комментарии Комментарии 8

Публикации

Информация

Сайт
pixonic.com
Дата регистрации
Дата основания
Численность
201–500 человек
Местоположение
Кипр

Истории