Статус Agent уже отображается как Online, но первая реальная сборка всё равно может зависеть от SSH-сеанса, неправильной версии Xcode или общего ключа подписи.
Быстрое решение: обычному проекту сначала следует проверить Microsoft-hosted macOS Agent; отдельный удалённый Mac стоит подключать как self-hosted Agent только при необходимости постоянного кэша, фиксированного Xcode, доступа к внутренним ресурсам или контролируемой связки ключей. Статус Online означает регистрацию, а не готовность к эксплуатации: производственная приёмка начинается после сборки, перезагрузки и проверки очистки секретов.
Эта инструкция предназначена:
- разработчикам, которые запускают в Azure Pipelines сборку и тестирование iOS или macOS-приложений;
- DevOps-инженерам, которым нужно держать удалённый Mac в общем или отдельном Agent Pool;
- владельцам мобильной платформы, отвечающим за сертификаты, provisioning profiles, права публикации и изоляцию рабочих узлов.
Сначала определите, нужен ли команде отдельный Mac Agent
Microsoft-hosted Agent подходит для многих независимых сборок: среда создаётся для задания, а проект не получает постоянный доступ к файловой системе или внутренней сети организации. В документации Microsoft описаны типы Azure Pipelines Agent и различия между размещёнными и self-hosted-узлами; именно от этих ограничений следует отталкиваться до установки программного обеспечения на Mac.
Если проект не требует фиксированного состояния машины, выберите hosted Agent. Если ему нужны постоянные инструменты, внутренний доступ или управляемое хранилище подписи, переходите к self-hosted удалённому Mac.
Такое решение обычно определяется не удобством подключения, а четырьмя техническими ограничениями:
- Фиксированный набор инструментов. Hosted-образ может измениться вместе с обновлением образа. Self-hosted Mac позволяет самостоятельно контролировать Xcode, Ruby, CocoaPods, Swift Package Manager и дополнительные SDK, но ответственность за обновления переходит к команде.
- Постоянный кэш. Локальные зависимости, DerivedData и другие кэшируемые артефакты могут уменьшать повторную загрузку, однако одновременно создают риск устаревших или повреждённых данных. Кэш нельзя считать доказательством воспроизводимости.
- Внутренняя сеть. Если сборке требуется приватный Git-сервер, тестовый API, закрытый реестр или корпоративный VPN, hosted-узел может не иметь нужного маршрута. Удалённый Mac должен получить только необходимые сетевые разрешения, а не полный доступ ко всей сети.
- Чувствительная подпись. Сертификаты, закрытые ключи и профили распространения нуждаются в отдельной процедуре хранения и удаления. Постоянный Agent удобен для подписи, но при слабой изоляции превращается в место накопления секретов.
Есть и дополнительная граница безопасности. Непроверенный код из внешнего pull request не следует запускать на постоянном узле с ключами публикации. В рекомендациях Microsoft по безопасности Azure Pipelines отдельно рассматриваются доверие к коду, разрешения и защита ресурсов. Для недоверенных изменений безопаснее использовать изолированную hosted-среду либо отдельный self-hosted узел без секретов.
Решение можно принять до регистрации:
- Если нужен только чистый запуск
xcodebuildбез внутренней сети — оставайтесь на hosted Agent. - Если необходимы одинаковая версия Xcode и локальные инструменты между запусками — рассматривайте отдельный Mac.
- Если требуется постоянное соединение с закрытыми сервисами — выделяйте отдельный пул и ограничивайте маршруты.
- Если узел будет подписывать приложения нескольких проектов — не объединяйте все проекты в один рабочий контур без доказанной изоляции.
- Если команда не готова отвечать за обновления macOS, Xcode, дисковое пространство и восстановление — вернитесь к hosted Agent.
Первый этап: подготовьте отдельный контур регистрации
Самостоятельная регистрация Azure DevOps macOS Agent начинается не с копирования команды из старой инструкции, а с создания изолированной структуры в Azure DevOps.
Создайте отдельный Agent Pool для Mac-узлов. Название пула, имя организации, имя проекта и имя агента должны быть собственными значениями команды, а не примерами из этой статьи. Разделение особенно важно, когда один проект подписывает релиз, а другой выполняет только тесты.
На самом Mac подготовьте отдельную системную учётную запись без административных прав для обычного запуска Agent. Полные права администратора понадобятся только для операций, которые действительно требуют изменения системы. Рабочий каталог также должен принадлежать этой учётной записи:
sudo mkdir -p /Users/<agent-user>/azure-agent
sudo chown -R <agent-user>:staff /Users/<agent-user>/azure-agent
Команды выше задают только пример пути и владельца. Имена пользователя, каталог, пул, агент и токен необходимо заменить значениями организации. Нельзя вставлять в статью, скрипт или репозиторий долгоживущий токен.
Скачайте пакет Agent из текущей инструкции Microsoft для macOS и распакуйте его под подготовленной учётной записью. В официальных вариантах аутентификации self-hosted Agent перечислены доступные способы входа. Выбор зависит от политики организации и не должен фиксироваться по старому примеру: Microsoft может менять доступные параметры и требования.
При регистрации консоль предложит URL организации, тип аутентификации, Agent Pool, имя узла и рабочую папку. Команда регистрации должна быть взята из текущей панели Azure DevOps, а не переписана из блога:
./config.sh \
--url https://dev.azure.com/<organization> \
--auth <authentication-mode> \
--pool "<pool-name>" \
--agent "<agent-name>" \
--work "_work"
Здесь <authentication-mode> и связанные с ним параметры являются заполнителями. Реальные аргументы и секрет вводятся только интерактивно или через защищённый механизм, предусмотренный выбранной схемой аутентификации.
Начальная проверка считается выполненной, если:
- узел появился в правильном Agent Pool;
- в интерфейсе отображается ожидаемое имя Agent;
- версия Agent соответствует актуальной версии, указанной в официальной документации;
- список capabilities содержит базовые свойства операционной системы и обнаруженные инструменты;
- тестовое задание действительно забирается именно этим узлом.
Документация Microsoft о macOS Agent описывает установку, настройку и запуск службы. Статус Online после регистрации следует записать как промежуточное свидетельство, но не как результат производственной приёмки.
Как добавить self-hosted macOS Agent в Azure DevOps?
Сначала создаётся отдельный Agent Pool, затем на Mac подготавливается низкоправная системная учётная запись, после чего Agent регистрируется через актуальные параметры из консоли Azure DevOps. После регистрации необходимо запустить тестовый pipeline и проверить фактическое выполнение, а не только наличие зелёного статуса в интерфейсе.
Второй этап: разделите фоновую сборку и графические тесты
Командная сборка и тест, которому нужен Simulator или пользовательская сессия macOS, имеют разные требования к постоянной работе.
Для чистого CLI-процесса Agent может работать как служба без постоянного подключения по SSH. Это типичный вариант для xcodebuild, статического анализа, генерации архива и публикации артефактов. SSH нужен для администрирования, но задача не должна исчезать после закрытия терминала.
Графический тест сложнее. Simulator, UI-тесты, доступ к пользовательской связке ключей и некоторые инструменты разработки могут зависеть от активного входа в macOS. Поэтому нельзя автоматически считать службу, запущенную в фоне, эквивалентом полноценной интерактивной сессии.
На практике используются разные режимы:
- служба Agent — предпочтительна для постоянного CLI-сборщика;
- LaunchAgent — привязан к пользовательской сессии и может быть нужен для процессов, которым требуется вход пользователя;
- ручной запуск через SSH — годится только для диагностики, но не для надёжного CI;
- LaunchDaemon или иной системный механизм — требует отдельной проверки прав и не решает автоматически проблему графической сессии.
Следует использовать официальный сценарий svc.sh, если текущая версия Agent его предоставляет:
./svc.sh status
./svc.sh stop
./svc.sh start
Точные действия и доступность отдельных команд необходимо сверять с руководством Microsoft по службе Agent на macOS. После включения постоянного запуска проведите проверку в таком порядке:
- Запустите простой pipeline через Agent Pool.
- Отключите SSH-соединение, не останавливая Mac.
- Убедитесь, что задание продолжает выполняться или корректно завершается.
- Выйдите из пользовательской сессии и отдельно повторите CLI-сценарий.
- Перезагрузите Mac.
- Дождитесь восстановления службы и повторите pipeline.
- Отдельно проверьте Simulator или UI-тест в том режиме сессии, который требуется проекту.
Как обеспечить автоматическое возвращение macOS Agent после перезагрузки?
Нужно зарегистрировать Agent как поддерживаемую службу и проверить её состояние после перезапуска системы, отключения SSH и выхода пользователя. Для UI-тестов дополнительно проверяется вход в macOS и доступность графической сессии; один только успешный запуск службы не доказывает готовность Simulator.
Третий этап: привяжите Azure Pipelines к нужному Xcode
Даже доступный Mac может быть выбран неправильно. Azure Pipelines сопоставляет требования задания с capabilities Agent, поэтому задача должна явно требовать нужные свойства. Общий принцип сопоставления описан в документации Microsoft о выполнении pipeline.
Сначала проверьте инструменты непосредственно на узле:
xcode-select --print-path
xcodebuild -version
xcodebuild -showsdks
Команда xcode-select должна указывать на ожидаемую установку Xcode, а xcodebuild — запускаться от имени той же учётной записи, под которой работает Agent. Справочные сведения о командах Xcode доступны в документации Apple по Xcode Command Line Tools.
Затем создайте минимальный проект, который проверяет не только компиляцию, но и весь путь результата:
- проект открывается без интерактивного подтверждения;
- схема доступна для командной сборки и помечена как shared;
- выбран правильный workspace или project;
xcodebuildвыполняет сборку с ожидаемым SDK;- тестовый результат сохраняется в артефакт;
- архив или другой выходной файл появляется в заранее определённом каталоге.
Для маршрутизации используйте demands, соответствующие фактическим capabilities. Названия capability нельзя придумывать по аналогии с другим узлом: их следует посмотреть в карточке Agent и затем сопоставить с требованиями задачи. Если несколько Mac имеют разные версии Xcode, каждому понадобится различимое свойство, чтобы pipeline не отправил задачу на неподходящий узел.
Почему Azure Pipelines не находит Agent с возможностью Xcode?
Чаще всего задача направляется в неправильный пул, demand не совпадает с фактическим названием capability или Agent не был перезапущен после установки Xcode. После добавления либо смены Xcode перезапустите Agent, обновите сведения о capabilities и повторите минимальную сборку с явным требованием к нужному узлу.
Если команда устанавливает несколько версий Xcode, не следует менять системный выбор во время параллельных задач. Такой подход создаёт гонку: одна сборка может переключить xcode-select, пока другая использует тот же Mac. Безопаснее разделить версии по Agent, по пулу или по последовательной политике выполнения; конкретный вариант зависит от числа проектов и допустимого времени ожидания.
Четвёртый этап: изолируйте подпись и публикацию
Подписание Apple-приложения нельзя проверять только успешным появлением .ipa. Нужно доказать, что сертификат был доступен нужной задаче, применён к ожидаемой конфигурации, а после выполнения секреты не остались в рабочем каталоге или логах.
В Azure Pipelines для этого применяются Secure Files и контролируемые разрешения. Официальное описание Secure Files объясняет, как защищённые файлы выдаются задачам pipeline. Для Apple-сценариев также полезно сверяться с руководством Microsoft по подписанию мобильных приложений.
Рабочая схема должна разделять:
- сертификат и закрытый ключ;
- provisioning profile;
- разрешение pipeline на использование Secure File;
- пароль или секретную переменную;
- права системной связки ключей;
- учётные данные для публикации.
Долгосрочные ключи нельзя хранить в репозитории, YAML-файле или обычной переменной проекта. Даже если значение скрывается в интерфейсе, оно может попасть в файл, временный каталог или диагностический вывод через неправильно настроенную команду.
Проведите приёмку в трёх независимых режимах:
- Сборка без подписи. Она подтверждает, что исходный код, зависимости, SDK и Xcode работают независимо от секретов.
- Контролируемая архивная сборка. Secure File разрешается только конкретному pipeline, а результат проверяется на соответствующую команду и профиль.
- Очистка. После завершения проверяются рабочая папка, временные каталоги, логи и доступ к связке ключей.
Для общего узла стоит разделить несекретные и подписывающие задачи по Agent Pool. Если несколько проектов используют одну машину, минимально необходимы отдельные разрешения pipeline, отдельные рабочие каталоги и понятная процедура очистки. При невозможности доказать разделение лучше вынести релизную подпись на отдельный Mac, а тестовую сборку оставить в менее доверенном контуре.
Проверьте рабочую область, кэш и восстановление
Постоянный удалённый Mac приносит пользу только тогда, когда его состояние предсказуемо. Самая частая ошибка — считать сохранённый кэш преимуществом без проверки того, кто его создал и когда он был обновлён.
Перед вводом узла в эксплуатацию зафиксируйте правила:
- какие каталоги могут сохраняться между задачами;
- какие каталоги удаляются после каждого запуска;
- где лежат временные архивы и логи;
- кто контролирует рост диска;
- кто обновляет Agent, macOS и Xcode;
- что происходит после прерванной сборки;
- как отзывать доступ при увольнении сотрудника или смене проекта.
Рабочая директория не должна использоваться как долговременное хранилище артефактов. Результаты следует публиковать в предусмотренное хранилище pipeline, а локальные копии удалять по установленному правилу. Кэш зависимостей можно сохранять только после определения ключа, учитывающего проект и версию инструмента; иначе одна ветка способна отдать другой несовместимый результат.
Проверка готовности должна включать реальные сценарии:
- несколько последовательных задач;
- намеренно неуспешную задачу и повторный запуск;
- отмену задания;
- перезагрузку Mac во время простоя;
- обновление Agent с последующим тестом;
- изменение выбранного Xcode;
- попытку задачи из проекта без разрешения на секреты;
- проверку очистки после подписывающей сборки.
Если после перезапуска Agent возвращается Online, но рабочая папка заблокирована, Xcode не выбран или связка ключей недоступна, узел нельзя выпускать в production. Его следует либо изолировать для диагностики, либо вернуть задачу на hosted Agent.
Итоговый список приёмки
- [ ] Выбран отдельный Agent Pool, а не общий пул без понятных правил.
- [ ] Agent работает под выделенной низкоправной учётной записью.
- [ ] Команда регистрации и способ аутентификации взяты из актуальной консоли.
- [ ] Online подтверждён тестовым запуском, а не только интерфейсом.
- [ ] CLI-сборка не зависит от открытого SSH-терминала.
- [ ] После перезагрузки Mac служба восстанавливается.
- [ ] Для Simulator и UI-тестов проверена активная macOS-сессия.
- [ ]
xcode-select,xcodebuildи SDK соответствуют требованиям pipeline. - [ ] Demands направляют задачу на нужный Agent.
- [ ] Несколько версий Xcode не переключаются конкурентными задачами.
- [ ] Сборка без подписи и подписывающая сборка проверены раздельно.
- [ ] Secure Files и разрешения pipeline ограничены необходимым минимумом.
- [ ] Рабочие каталоги очищаются после выполнения.
- [ ] Проверены повторный запуск, отмена, перезагрузка и обновление Agent.
Когда удалённый Mac оправдан, а когда лучше не переходить на него
Если команде нужен фиксированный Xcode, постоянный доступ к внутреннему API, собственный кэш или изолированная связка ключей, удалённый Mac может быть более управляемым вариантом, чем попытка подстроить hosted-среду под нестандартный процесс. Для временного проекта можно сначала проверить условия аренды в каталоге доступных вариантов RUVCLOUD и сопоставить их с требуемым пулом, способом доступа и сроком работы узла.
При этом self-hosted Agent не является универсальной заменой hosted Agent. Он требует регулярного обслуживания, контроля диска, обновления Xcode, восстановления после сбоев и расследования загрязнённых рабочих каталогов. Если проект запускает непроверенный внешний код, не использует постоянные инструменты и не нуждается во внутренней сети, hosted-вариант обычно оставляет меньше опасных состояний.
Для команды, которая уже выполнила минимальную сборку, проверку перезагрузки и изоляцию сертификатов, следующий выбор должен быть предметным:
- при кратком тестовом цикле — взять удалённый Mac на ограниченный срок;
- при постоянном Xcode CI — выбрать период аренды, соответствующий плану релизов;
- при нескольких проектах — заранее разделить пул для подписи и пул для обычных тестов;
- при длительной стабильной нагрузке — сравнить аренду с покупкой собственного Mac и учесть ответственность за физическое оборудование.
Аренда через RUVCLOUD удобнее текущей схеме с личным Mac разработчика или случайной виртуальной средой, если команде мешают отсутствие постоянной доступности, ограниченные права, нестабильный графический сеанс и необходимость самостоятельно держать машину включённой. Подход разумно проверять не рекламным обещанием, а тем же тестовым pipeline: после получения узла зарегистрировать Agent, выполнить сборку, перезагрузить Mac и подтвердить безопасное удаление временных данных. Условия и доступные варианты можно сопоставить на странице аренды удалённого Mac, а стоимость периода — на странице тарифов RUVCLOUD.