Привет, Хабр! Меня зовут Ярослав Фоменко, я iOS-разработчик в компании Даблтап. После того, как мы с ребятами из iOS-отдела настроили наш CI/CD на Mac mini, начали задумываться о его масштабировании и инкапсулировании и пошли ресерчить то, как это можно сделать. Первым на ум пришел Docker, но инфы оказалось довольно мало как о нем, так и о других возможных способах. В этой статье мы рассмотрим найденные нами возможные решения по развертыванию Gitlab CI/CD на железе и в облаке.
Варианты развертывания CI/CD
Мы изучили возможные варианты развертывания, сравнили простоту и время настройки, использования и масштабирования:
-
На своем железе:
без виртуалок и контейнеров;
на виртуальных машинах;
в докере.
-
В облачных сервисах:
в Xcode Cloud;
в Gitlab SaaS;
на виртуальных машинах.
Для расчета времени выполнения задач возьмем проект, который активно разрабатывается почти 2 года, имеет 20 зависимостей через Cocoapods, включая Rx, Realm, Firebase, Swinject и прочие.
Сборка на своем железе
Без виртуалок и контейнеров
Можно купить и поставить в офисе Mac mini. Данный способ является довольно удобным, но не самым надежным. Единственное, что нужно сделать, это установить Xcode Command Line Tools, rbenv, Fastlane и Gitlab Runner. Также на локальной машинке можно устанавливать любые необходимые зависимости, что для нас очень важно: при запуске сборки мы используем скрипты на Python для занесения инфы о билде в репозиторий, а также изменяем статус задачи в таск-трекере. После этого можно регистрировать раннеры и запускать pipeline.
Мы используем Mac mini 2018 года с 6-ядерным Intel Core i7 с 16 ГБ оперативной памяти. Время сборки проекта составляет 3 минуты, а сборка и выгрузка в App Store Connect — еще 9 минут.
Да, вот так все просто. Однако в этой простоте кроется и большой минус: если кто-то решит настроить CI для другого проекта, то он с легкостью может какой-нибудь новой зависимостью положить весь ваш CI/CD. Или же во время настройки у вас ничего не будет работать из-за уже установленных зависимостей.
Также у вас не получится просто взять и запустить на одном раннере несколько задач без подготовки и написания пары строчек кода.
При масштабировании CI/CD появляются сложности с тем, что на каждой машине нужно установить/обновить все необходимые зависимости и следить за тем, чтобы никто ничего не сломал.
Виртуализируем macOS
Первым способом отделить наши раннеры от внешней среды является виртуализация. Gitlab Runner предлагает Parallels и VirtualBox в качестве executor. В связке с Vagrant можно написать довольно удобный скрипт, который поможет быстро поднять виртуалку с нужными зависимостями и выполнять на ней задания.
Виртуализация является одним из самых ресурсоемких процессов, если развертывать их на своих устройствах: виртуальным машинам нужно приличное количество ресурсов для работы. Поэтому вам точно понадобится мощное железо.
Каждая виртуальная машина — это отдельный образ с полноценной системой и Xcode, что в сумме требует 50 ГБ, а если учитывать зависимости, сам проект, а также кэши Xcode, то под одну VM следует отводить 75 ГБ.
Что касается требований к вычислительным мощностям — каждому инстансу можно дать конкретное количество ресурсов. Но стоит помнить, что если выделенных ресурсов не будет хватать, то джоба будет выполняться дольше.
На нашем маке без проблем одновременно может работать 2 задачи на сборку проекта. Если же их уже 3, то время выполнения каждой увеличивается с 3 до 5 минут. Таким образом мы можем создать 3 виртуалки по 2 ядра CPU и 5 ГБ оперативки, если хватит пространства SSD.
Но можно и изменять количество CPU и RAM перед запуском, т.к. нет необходимости держать виртуалку постоянно запущенной: можно закрывать ее или уводить в сон после каждой задачи.
Контейнеризируем macOS
Или все-таки нет?
На Github можно найти Docker-OSX, который для нас показался довольно интересным решением, потому что контейнеры требуют намного меньше ресурсов, запускаются намного быстрее и могут передавать данные между собой. При более детальном рассмотрении выяснилось, что macOS нельзя засунуть в контейнер, а в Docker-OSX macOS на самом деле виртуализируется на Linux и для запуска контейнера нужна Linux или Windows.
После ресерча по Discord-серверу проекта мы поняли, что это решение изначально создано для тестирования безопасности, а для CI/CD оно не подходит из-за того, что macOS в докере имеет большие проблемы с производительностью: сборка проектов происходит в 2-3 раза дольше, чем на реальной машине. А также существует проблема с сертификатами: данный способ развертывания macOS является нелицензированным, поэтому подпись и распространение сборок невозможны, а полученные .ipa файлы можно запустить лишь на jailbreak-устройствах.
Сборка на облачных сервисах
Xcode Cloud
По моему мнению, это самый простой способ, не требующий почти никакой подготовки, кроме установленного Xcode.
Все, что нужно сделать — это настроить проект для App Store Connect, связать проект с Git и отредактировать воркфлоу. Это все делается поэтапно в интерфейсе Xcode и занимает пару минут. Теперь в вашем распоряжении CI/CD бесплатно на 25 часов в месяц до декабря 2023 года. Дополнительные часы идут за дополнительную плату.
Xcode Cloud позволяет проводить все то же самое, что и обычный Xcode: build, test, analyze, archive. Условием запуска воркфлоу можно выбрать изменения в ветках, пул-реквесты, тэги или же расписание. Также можно выбрать версии macOS и Xcode, на которых должна запускаться воркфлоу.
Вам определенно стоит присмотреться к Xcode Cloud, если у вас 1-2 проекта, на которых нужно только лишь прогонять билды и делать пуши в тестфлайт без всяких скриптов и доп. условий, а также если вы используете SPM. Данное решение однозначно снимает проблему масштабирования (только заносите Apple деньги). И никто точно не поломает ваш CI/CD никакими зависимостями.
Вам не подойдет Xcode Cloud, если вы используете зависимости по типу Cocoapods или Carthage: для того, чтобы занести сторонние зависимости, нужно взять с сайта Apple скрипт и добавить в проект. Казалось бы, что может быть проще? Но это решение каждый раз ставит зависимости и homebrew и занимает 9 минут, что выльется в копеечку. И еще 5 минут осуществляется сам build. И это против 3 минут на железе. В настройках воркфлоу есть checkbox для clean build, но что без него, что с ним, решение зависимостей и сборка проекта происходят одинаково долго.
Запуск сборок в Testflight — тоже дело непростое. Необходимо:
создать воркфлоу с каким-нибудь стартовым условием;
деактивировать воркфлоу, чтобы оно случайно не активировалось;
зайти во вкладку Cloud в Xcode;
выбрать все PR;
выбрать нужный;
стартовать сборку.
Довольно много кликов.
Минусом может стать и то, что для закрытых сторонних зависимостей также нужно давать доступ Xcode Cloud, и здесь тоже нужны права maintainer у репозитория.
При крутом, действительно проработанном API, сервис выглядит сыровато.
Gitlab SaaS
Но что делать, если лишней железки нет, а нужно поднимать раннеры независимо и не хочется их настраивать? Gitlab предлагает SaaS-раннеры на процессорах Intel на 4 ядра и 10 ГБ оперативной памяти, в которых есть последний Xcode и macOS и, скорее всего, все нужные вам зависимости. Для их запуска нужен лишь конфигурационный файл и доступ к сертификатам для распространения сборок.
По факту SaaS-раннеры — это те же самые виртуальные машины, но только уже настроенные за вас и с кучей разных зависимостей.
К слову, раннеры на M1 обещали запустить во второй половине 2022 года, но уже конец декабря, а они все еще недоступны.
SaaS-раннеры доступны, если у вас есть подписка на Gitlab. Использование macOS SaaS-раннеров дороже, чем использование раннеров на Linux. За 1 реальную минуту выполнения CI/CD со счета подписки вычитается 6 минут. На самом продвинутом варианте подписки за 100 долларов доступно 50 000 минут.
Если взять в расчет, что в SaaS пайплайн будет выполняться по времени как на нашей машине — 12 минут, то это спишет с аккаунта 72 минуты. Чтобы укладываться в лимиты и не докупать минуты по более высоким расценкам, можно разделить репозитории между аккаунтами или выделить специальный аккаунт.
Виртуализируем macOS в облаке
Если вас не устраивает расход минут и количество нужных зависимостей в SaaS-раннерах, то существует множество сервисов, которые предоставляют в аренду доступ к виртуальным машинам, запущенным на mac с помощью Orka или Anka. Цены везде разные, но стоит отметить, что плата идет за аренду одной машины, а не за выполнение задач, как в Gitlab, а саму машину нужно будет дополнительно дольше настраивать под себя. Чаще всего цена аренды виртуалок выше цены аренды SaaS-раннеров.
Вывод
Если вам хватит 1500 минут на проекты и вы не используете сторонние зависимости, то Xcode Cloud — ваш выбор. Также он довольно хорошо подойдет для масштабирования. Цена дополнительных часов будет сопоставима с Gitlab SaaS.
Если у вас всего один проект, который требует больше времени и в перспективе его не нужно будет масштабировать, то CI/CD можно разворачивать напрямую на своем железе.
Если это не так и у вас есть железо, которого хватит на все ваши проекты, то присмотритесь к развертыванию виртуальных машин на нем. Если же его не хватает и вам достаточно времени и зависимостей, предоставляемых Gitlab, то SaaS-раннеры станут отличным решением. Но если нет, то стоит арендовать мощности у сервисов и на них настраивать машину под свои нужды.
Что интересно, Apple недавно зарелизила функцию для создания и конфигурации виртуальных машин прямо в Xcode на Swift. Посмотрим, как это повлияет на использование виртуалок для автоматизированной интеграции и распространения.
В данный момент мы рассматриваем вариант с виртуальными машинами, т.к. количество проектов, которым нужно CI/CD, растет и есть необходимость держать их изолированно. Например, у нас однажды упали джобы после того, как разработчик установил React-Native.
Докер, к сожалению, пока не пригоден для наших целей из-за плохой производительности развернутой таким образом macOS, что скажется на времени выполнения задач CI/CD. Apple реализовала возможность виртуализировать macOS, но, может, в скором времени нам дадут контейнеризировать операционную систему. Остается только ждать.
А что вы думаете по этому поводу? Какие варианты уже используете для работы с CI/CD?
Комментарии (6)
kambala
31.12.2022 22:37Однако в этой простоте кроется и большой минус: если кто-то решит настроить CI для другого проекта, то он с легкостью может какой-нибудь новой зависимостью положить весь ваш CI/CD. Или же во время настройки у вас ничего не будет работать из-за уже установленных зависимостей.
Также у вас не получится просто взять и запустить на одном раннере несколько задач без подготовки и написания пары строчек кода.
У нас уже лет 5 через дженкинс собирается по 1-4 проекта параллельно на одной машине без сучка и задоринки. Какая у вас была проблема?
radhold Автор
31.12.2022 22:38С параллельностью не было никаких проблем, а вот, когда на этот мак решили накатить что-то для React Native, то CI немного приуныл.
kambala
31.12.2022 22:58+1RN - это достаточно специфическая вещь. Стоило бы упомянуть в статье, что именно он помешал выбрать самый простой вариант для CI.
К тому же, всегда можно было бы поставить несколько его версий на одной машине.
wizard_s
Вопрос: что делать с лицензированием macos в виртуалках? (Вариант "поднимаем виртуалки у себя"). Насколько помню, на не-apple железе и десктопные версии нельзя было.
radhold Автор
Да, действительно, виртуалка будет лицензионной, только если поднимать ее на Mac. Других легальных вариантов здесь нет, к сожалению
tim3lord
Дизайн Mac Mini не спроста одинаково хорошо смотрится и на рабочем столе и в серверной стойке))