В документации Jenkins указано, что для встроенного узла controller рекомендуется устанавливать 0 executor, а для обычного Agent наиболее безопасной отправной точкой считается один executor на узел. Это означает, что статус «Agent successfully connected and online» сам по себе не является разрешением на производственные сборки: приёмка Jenkins Mac-узла должна подтвердить подключение, планирование, инструментальную цепочку, изоляцию подписей, параллельную нагрузку и восстановление после сбоев. (рекомендации Jenkins по Agent и executor)
Вердикт: подходит для производственного запуска только тот Jenkins Mac-узел, который прошёл шесть проверок на реальном проекте и имеет сохранённые доказательства; если команда пока не может проверить ночное восстановление и пиковую очередь, безопаснее сначала провести ограниченное испытание на отдельном удалённом Mac.
Эта статья предназначена для платформенного инженера, который добавляет Apple Silicon Agent в Jenkins и формирует критерии допуска.
Она также пригодится IT-руководителю, проверяющему права, безопасность и удалённое восстановление, а также руководителю разработки, оценивающему число узлов для окна сборки и публикации.
00Почему статус «online» ещё не означает готовность к релизу
У Jenkins Mac Agent есть как минимум три разных состояния готовности:
- Соединение установлено. Controller видит Agent, процесс отвечает, узел отображается в интерфейсе.
- Тестовая сборка выполняется. Простая Pipeline действительно запускается на нужном узле.
- Производственная эксплуатация разрешена. Реальный проект собирается с нужными зависимостями, сертификатами, ограничениями доступа и ожидаемой параллельностью, а после сбоя узел возвращается в рабочее состояние без незапланированной ручной процедуры.
Ошибка приёмки обычно возникает между вторым и третьим уровнями. Например, Agent подключается, команда xcodebuild -version возвращает ожидаемый результат, но релизная Pipeline затем использует другой Xcode, не может получить приватный Swift Package, видит заблокированную связку ключей или попадает на узел с неправильной архитектурой.
Для каждой проверки следует вести отдельную строку в журнале приёмки. Минимальная форма доказательства выглядит так:
| Объект проверки | Действие | Ожидаемый результат | Доказательство | Если тест не пройден |
|---|---|---|---|---|
| Agent и соединение | Перезапустить процесс Agent и проверить повторное подключение | Узел снова доступен с теми же метками | Лог Agent, состояние узла | Исправить способ запуска или отложить допуск |
| Планирование | Запустить Pipeline с обязательной меткой | Задание выполнено только на нужном Mac | Лог Pipeline, NODE_NAME |
Уточнить метки и правила stage |
| Xcode и зависимости | Собрать реальный проект в чистой рабочей области | Результат совпадает с эталоном команды | xcodebuild-лог, lock-файлы |
Зафиксировать toolchain и повторить тест |
| Подписи | Выполнить тестовую архивную сборку | Используется только разрешённый сертификат | Лог подписи, настройки credentials | Изолировать секреты или узел |
| Восстановление | Перезапустить Mac и Agent, имитировать сбой сети | Узел возвращается и принимает тестовую задачу | Временные отметки и журналы | Запретить ночную эксплуатацию |
Порог «успешно» должен задаваться не примерным проектом, а реальной целью сервиса: допустимым временем ожидания, максимальным числом параллельных сборок, требованиями к выпуску и допустимым количеством ручных действий.
01Первый шаг: проверить подключение, метки и границы controller
Jenkins распределяет работу между controller и Agent. Agent предоставляет executor, а метки позволяют направлять задания на узлы с конкретной архитектурой, операционной системой или инструментами. Для компьютера на Arm64 Jenkins приводит вариант отдельной метки aarch64; аналогично можно разделить узлы по xcode-release, code-signing, ios-simulator и другим признакам. (документация Jenkins о метках и Agent)
Перед утверждением конфигурации необходимо проверить:
- способ запуска Agent — SSH, inbound-подключение или иной согласованный механизм;
- поведение при кратковременном разрыве сети;
- наличие Java и сетевого маршрута до controller;
- имя узла, рабочий каталог и владельца процесса;
- обязательные метки, включая Apple Silicon и назначение узла;
- состояние диска, временного пространства, синхронизации часов и времени ответа;
- отсутствие производственных заданий на controller.
В Jenkins Pipeline конкретный stage можно направить на нужную группу через agent { label '...' }. Если оставить agent any, задание может попасть на любой доступный узел, удовлетворяющий общей политике, а не обязательно на Mac с нужной версией Xcode. Jenkins также поддерживает логические выражения меток, например сочетание нескольких требований через &&. (синтаксис Jenkins Pipeline для выбора Agent)
Пример минимального правила для iOS-релиза:
pipeline {
agent none
stages {
stage('Сборка iOS') {
agent {
label 'macos && apple-silicon && xcode-release'
}
steps {
sh 'echo "Node: $NODE_NAME"'
sh 'xcodebuild -workspace App.xcworkspace -scheme App -configuration Release build'
}
}
}
}
После запуска нужно проверить не только зелёный статус, но и консольный журнал: какая метка была выбрана, какое имя узла выведено, в каком каталоге работала команда и не выполнялась ли часть Pipeline на другом Agent.
Jenkins рекомендует не использовать встроенный controller для сборок, поскольку это ухудшает изоляцию, стабильность и масштабирование. В практической приёмке это означает отдельную проверку: число executor на controller равно нулю, а рабочие задания исполняются только на подготовленных Agent.
02Второй шаг: подтвердить Xcode, SDK и зависимости на реальном проекте
Проверка одной команды xcodebuild -version недостаточна. Она показывает наличие инструмента, но не доказывает, что конкретный проект использует тот же Xcode, доступные SDK, нужные плагины, Swift Package и скрипты сборки.
Apple указывает, что xcodebuild, simctl и другие инструменты входят в состав Xcode, а перед их использованием необходимо установить Xcode и выбрать активный developer directory. (справочник Apple по инструментам командной строки Xcode)
Для приёмки следует выполнить три варианта сборки:
- чистая рабочая область без заранее подготовленного DerivedData;
- повторная сборка с обычным командным кэшем;
- сборка после очистки кэша и временных каталогов.
Во всех трёх случаях фиксируются:
- путь к активному Xcode;
- целевая схема и конфигурация;
- версия SDK, реально выбранная процессом;
- состояние
Package.resolved; - журналы
xcodebuild; - результат тестов и архивирования;
- сетевой доступ к приватным зависимостям.
Для Swift Package Apple рекомендует хранить Package.resolved в репозитории, а при прямом вызове xcodebuild использовать -disableAutomaticPackageResolution, чтобы CI применял зафиксированные версии, а не разрешал зависимости заново во время каждой сборки. (рекомендации Apple для CI со Swift Package)
| Сценарий | Что выявляет | Минимальное доказательство |
|---|---|---|
| Чистая сборка | Отсутствующие SDK, инструменты и зависимости | Полный журнал xcodebuild |
| Повторная сборка | Ошибки кэша и нестабильность скриптов | Два последовательных результата |
| После очистки кэша | Скрытую зависимость от DerivedData или временных файлов | Команда очистки и новый лог |
| Архивирование | Проблемы signing, entitlements и export options | .xcarchive, журнал и параметры экспорта |
Отдельно требуется определить владельца изменений: кто утверждает обновление Xcode, где хранится предыдущая среда, как параллельно проверяется новая версия и как выполняется откат. Если после ручного обновления Mac продолжает принимать задачи с непроверенным toolchain, узел нельзя считать воспроизводимым.
03Третий шаг: изолировать credentials, сертификаты и доступ к коду
Для iOS CI/CD критичнее всего не сам факт наличия сертификата, а область его доступности. Jenkins рекомендует ограничивать credentials на минимальном уровне: глобальные секреты доступны более широкому кругу Pipeline, а credentials, заданные на уровне папки или проекта, позволяют сузить область доступа. (документация Jenkins о credentials и области доступа)
На этапе приёмки проверяются:
- credentials для подключения к Git-репозиторию;
- сертификаты и provisioning profiles;
- ключи публикации;
- доступ к приватным Swift Package;
- права пользователя, запускающего Agent;
- содержимое логов после маскирования секретов;
- доступность связки ключей в автоматическом режиме;
- возможность обычной задачи прочитать секрет другого проекта.
Нужен отдельный низкоправный тест. Он не должен собирать релиз, а должен попытаться:
- обратиться к переменной, принадлежащей другой Pipeline;
- прочитать файл с чужим профилем;
- найти сертификат, который не относится к тестовому приложению;
- вывести окружение и проверить, не попали ли в журнал токены;
- получить доступ к рабочему каталогу соседнего проекта.
Результат должен быть отрицательным. Если обычная задача может увидеть секреты релизного проекта, проблема не решается одной записью в документации — требуются новые credentials, отдельная папка, отдельный пользователь или физически изолированный Agent.
Apple указывает, что действующий сертификат подписи должен находиться в связке ключей, иначе сборка завершится ошибкой. Поэтому проверяется не только наличие файла сертификата, но и полный путь: импорт, разблокировка keychain, выбор identity, provisioning profile и фактическая команда архивирования. (руководство Apple по проверке подписи кода)
Разделение development и production на одном Mac допустимо только при доказуемой изоляции. Если политики компании не позволяют убедительно отделить ключи, рабочие области и пользователей, релизный Agent следует вынести на отдельный узел.
04Четвёртый шаг: проверить параллельные сборки и загрязнение рабочих областей
Число executor не следует выводить только из названия чипа или объёма памяти. Jenkins определяет executor как слот для одновременной задачи, но реальная iOS-сборка дополнительно потребляет CPU, память, диск, временное пространство, DerivedData, симуляторы и операции ввода-вывода. Официальная документация называет один executor на узел наиболее безопасным вариантом и допускает увеличение только при внимательном контроле нагрузки. (документация Jenkins о настройке executor)
Пиковый тест должен воспроизводить реальную очередь команды:
- несколько веток или проектов;
- обычная Debug-сборка;
- Release-архивирование;
- тесты на симуляторе;
- загрузка артефактов;
- параллельное обращение к приватным зависимостям;
- очистка и повторное использование рабочих каталогов.
Во время теста записываются состояние executor, время ожидания в очереди, загрузка CPU, потребление памяти, свободное место, заполнение временного каталога и ошибки доступа к симулятору. Jenkins сам отслеживает состояние диска, временного пространства, часов и времени ответа узла, поэтому эти показатели должны присутствовать в приёмочном журнале, а не оставаться только в интерфейсе мониторинга.
Проверка считается неудачной, если:
- одна задача видит DerivedData другой;
- параллельные процессы используют один конфликтующий симулятор;
- ключевая цепочка подписи остаётся разблокированной после завершения;
- рабочая область содержит артефакты предыдущей ветки;
- очередь растёт быстрее, чем команда успевает получать результаты;
- увеличение executor приводит к нестабильным тестам или ошибкам диска.
Варианты решения — уменьшить параллельность, разделить типы задач по меткам, добавить второй Mac-узел или использовать комбинацию фиксированного узла для регулярной нагрузки и временного узла для пиков. Если задания могут работать на любом совместимом Agent, метка пула лучше жёсткой привязки к одному имени узла: это снижает риск остановки всей очереди при недоступности одного компьютера.
05Пятый шаг: провести тест перезапуска и ночного восстановления
Удалённый Mac нельзя объявлять пригодным для безнадзорной работы только потому, что к нему открывается SSH. Apple подтверждает, что Remote Login позволяет подключаться к Mac через SSH или SFTP, однако сама возможность удалённого входа не доказывает автоматический запуск Jenkins Agent и доступность подписей после перезапуска. (документация Apple о Remote Login)
Проверку следует выполнять по отдельным сценариям:
- плановый перезапуск macOS;
- принудительное завершение процесса Agent;
- кратковременный разрыв сети;
- недоступность controller;
- предупреждение о нехватке дискового пространства;
- повторное подключение после восстановления маршрута;
- запуск тестовой Pipeline после возвращения узла online.
Для каждого сценария фиксируются:
- время начала отказа;
- что произошло автоматически;
- какая команда или служба вернула Agent;
- какие права потребовались;
- появилась ли исходная метка;
- был ли рабочий каталог очищен;
- потребовалась ли разблокировка FileVault или keychain;
- кто и когда подтвердил готовность узла.
FileVault требует отдельного решения для startup disk: Apple указывает, что зашифрованные данные недоступны до разблокировки диска паролем, Apple Account или recovery key, в зависимости от настроенной политики. Следовательно, ночной перезапуск может остановиться ещё до запуска пользовательских служб, если корпоративная процедура разблокировки загрузочного диска не определена. (документация Apple о восстановлении FileVault)
Также нужно проверить автоматический старт Agent после входа или загрузки системы, повторное подключение к controller и защиту секретов от вывода в служебный журнал. Возможность войти по SSH не заменяет проверку полного пути восстановления: после перезапуска должны вернуться процесс Agent, нужные метки, рабочий каталог и доступ к разрешённым credentials.
06Шестой шаг: вынести решение в формальную категорию допуска
После тестов не следует писать расплывчатое «узел в целом работает». Используйте одну из четырёх категорий:
| Категория | Условие | Ответственный шаг |
|---|---|---|
| Допущен | Все шесть зон пройдены, доказательства сохранены | Владелец CI утверждает эксплуатацию |
| Ограниченный запуск | Основные сборки проходят, но не завершены пик или восстановление | Владелец платформы задаёт срок и запрет на релизные задачи |
| Повторная приёмка | Найдены исправимые ошибки в метках, toolchain или правах | Инженер устраняет причину и повторяет затронутые тесты |
| Отклонён | Нет изоляции подписей, нет восстановления или не выдерживается реальная очередь | Закупается другой узел либо меняется архитектура |
Решение должно содержать не только статус, но и срок пересмотра, владельца, оставшиеся риски, разрешённые типы Pipeline и условия расширения ёмкости. Для новых Mac-узлов полезно хранить экспорт конфигурации Jenkins, список плагинов, параметры запуска Agent, lock-файлы зависимостей и эталонные логи.
Проверка должна быть повторена после изменения Xcode, macOS, Jenkins LTS, плагинов, сертификатов, способа подключения или правил сетевого доступа. Версия, которая успешно прошла приёмку, не является постоянной гарантией после изменения toolchain.
07Чек-лист перед разрешением производственных сборок
- [ ] Controller не выполняет производственные задания и не имеет выделенного executor для основной нагрузки.
- [ ] Jenkins Mac Agent подключается после штатного запуска и кратковременного сетевого сбоя.
- [ ] Обязательные метки отражают архитектуру Apple Silicon, назначение узла и установленный Xcode.
- [ ] Реальная Pipeline выводит фактическое имя узла и подтверждает ожидаемое распределение stage.
- [ ] Проверены диск, временное пространство, синхронизация часов и время ответа узла.
- [ ] Сборка выполнена в чистой рабочей области, с кэшем и после очистки кэша.
- [ ] В репозитории зафиксированы зависимости, включая
Package.resolved, если проект использует Swift Package. - [ ] Архивирование проверяет сертификат, provisioning profile, entitlements и параметры экспорта.
- [ ] Низкоправная задача не может прочитать credentials другого проекта.
- [ ] Логи не содержат токены, приватные ключи и значения секретных переменных.
- [ ] Пиковая очередь воспроизведена с реальным числом и типами Pipeline.
- [ ] Проверены executor, время ожидания, CPU, память, диск, DerivedData и симуляторы.
- [ ] После перезапуска Mac Agent возвращается с исходными метками.
- [ ] Зафиксированы условия FileVault, keychain и автоматического запуска служб.
- [ ] Для каждого отказа назначены владелец, срок исправления и повторный тест.
- [ ] Итог отнесён к категории «допущен», «ограниченный запуск», «повторная приёмка» или «отклонён».
08Частые вопросы для корпоративной приёмки
Что проверить перед вводом Jenkins Mac Agent в эксплуатацию?
Проверяйте не только статус «online». Выполните реальную сборку проекта, проверьте назначение по меткам, архитектуру Apple Silicon, установленный Xcode, доступ к зависимостям, подписи, права Jenkins credentials, параллельные задания, заполнение диска и восстановление после перезапуска. Для каждого теста сохраните команду, ожидаемый результат, журнал и решение при отказе.
Как закрепить iOS-сборку за нужным Mac-узлом Jenkins?
Назначьте узлу отдельные метки, например macos, apple-silicon и xcode-release, а в Pipeline используйте agent с label либо stage-level agent. Затем проверьте журнал Pipeline и фактическое значение NODE_NAME. Простая запись agent any не гарантирует, что задача попадёт на Mac с нужной архитектурой или версией Xcode.
Можно ли запускать несколько iOS Pipeline на одном Jenkins Mac Agent?
Да, но только после нагрузочного теста. Executor определяет число одновременно выполняемых задач, однако одна iOS-сборка может конкурировать с другой за CPU, память, диск, DerivedData, симуляторы и ключи подписи. Начинайте с консервативного значения, повторите реальную пиковую очередь и увеличивайте параллельность только при приемлемом времени ожидания и отсутствии загрязнения рабочих областей.
Как Jenkins Agent должен восстановиться после перезапуска удалённого Mac?
Нужно проверить весь путь: запуск macOS, доступность сети, автоматический старт процесса Agent, повторное подключение к controller, появление нужных меток и запуск тестовой Pipeline. Если включён FileVault, отдельно фиксируйте условие разблокировки загрузочного диска. Возможность войти по SSH не доказывает, что узел готов к ночной сборке без ручного вмешательства.
Сколько executor назначать Jenkins Mac-узлу для iOS-сборок?
Универсального числа нет. Один executor является безопасной отправной точкой, а увеличение требует наблюдения за CPU, памятью и операциями ввода-вывода. Решение принимайте по журналам реальной очереди: если растёт ожидание или появляются взаимные ошибки, добавляйте узел либо снижайте параллельность, а не ориентируйтесь только на модель чипа.
09Что выбрать после приёмки: фиксированный Mac или временный ресурс
Если текущая схема опирается на один физический Mac в офисе, у неё обычно проявляются четыре ограничения: закупка занимает время, простой требует локального доступа, масштабирование привязано к заранее купленному железу, а ночное восстановление зависит от питания и ручного вмешательства. Если компания использует неподготовленную виртуальную среду, добавляются ограничения совместимости с Apple toolchain и неопределённость поведения подписей.
Поэтому после заполнения чек-листа разумно разделить решения. Постоянный собственный Mac подходит для стабильной круглосуточной нагрузки, строгого требования к физическим интерфейсам и команды, готовой самостоятельно обслуживать запасной узел. Периодическая аренда удалённого Mac подходит для ограниченного испытания, миграции, проверки пикового спроса или временного расширения пула, когда ещё неизвестно, сколько executor действительно требуется.
Если у команды пока нет отдельного окружения для проверки восстановления, параллельных сборок и релизной подписи, можно использовать условия аренды удалённого Mac в NUKCLOUD как временную основу для реальной Jenkins Pipeline. Сначала следует собрать собственные логи и измерения, затем сравнить стоимость постоянного узла, обслуживания и резервирования с периодическим ресурсом. Информация о порядке доступа и рабочих ограничениях доступна в справочном разделе NUKCLOUD, а требования к обращению с данными — в политике конфиденциальности NUKCLOUD.
Главное правило приёмки остаётся неизменным: не считать зелёный статус Agent доказательством производственной готовности. Разрешение должно опираться на журналы реального проекта, результаты нагрузочного теста и подтверждённое восстановление после перезапуска.