Agent в TeamCity показывает «Connected», но iOS-сборка не стартует или попадает на неподходящий Mac.
Быстрое решение: не принимайте узел по статусу подключения. Сначала подтвердите Java 21 для TeamCity 2026.1, затем настройте отдельный аккаунт без root, собственный Agent Pool, явную маршрутизацию Xcode, изоляцию рабочей области и проверку восстановления после перезапуска.
Кому полезна эта статья: платформенным инженерам, которые добавляют iOS- или macOS-сборки в TeamCity; руководителям IT, превращающим Mac mini в общий узел; техническим директорам, выбирающим несколько физических или удалённых Mac с контролем подписей, ёмкости и отказоустойчивости.
Последняя проверка выполнена 30 августа 2026 года. Версии и поведение сверены с официальными требованиями TeamCity, документацией по агентам и материалами разработчика Xcode. Для On-Premises используется документация TeamCity 2026.1; материалы TeamCity Cloud 2026.2 приведены только там, где они описывают механизм запуска агента, а не как доказательство возможностей On-Premises.
Развёртывание macOS Build Agent для TeamCity 2026.1: базовые блокеры
Главная ошибка при запуске — начинать с регистрации агента. Если на хосте неподходящий Java Runtime или неправильно задан JAVA_HOME, агент может не дойти до регистрации. Для TeamCity 2026.1 требование Java 21 относится к среде выполнения самого агента. Это не означает, что ваш проект обязан собираться на Java 21.
Например, сборочный сценарий может использовать другую версию JDK для отдельного инструмента, Gradle-задачи или серверного компонента. Поэтому в инвентарной записи фиксируйте два значения:
- JDK, на котором запускается TeamCity Agent;
- JDK, который требуется конкретному проекту во время сборки.
Требование Java 21 нужно проверять по официальным системным требованиям TeamCity, а не по версии Java, которая случайно установлена в пользовательском профиле.
Минимальная проверка на Mac:
java -version
echo "$JAVA_HOME"
uname -m
sw_vers
df -h /
Команда uname -m помогает определить архитектуру хоста. Для узла на Apple Silicon в документации и карточке актива указание архитектуры должно совпадать с фактическим выводом системы. df -h / нужен не для формального прохождения установки, а для контроля рабочего пространства, кэшей, архивов и симуляторов. Точный резерв диска зависит от проекта и набора Xcode, поэтому не подменяйте этот показатель произвольным нормативом.
Учётная запись и права
Производственный Agent не должен работать под root. У root-процесса слишком широкая область воздействия: ошибка в скрипте может изменить системные файлы, прочитать чужие каталоги или оставить подписывающий материал вне ожидаемой границы. Кроме того, рабочие файлы, созданные от root, часто ломают последующие очистки, выполняемые обычным пользователем.
Создайте отдельную техническую учётную запись, например teamcity-agent, с минимальным набором прав. Администратор временно выполняет только действия, для которых действительно нужны повышенные полномочия:
- установка требуемого JDK;
- установка полного Xcode и системных компонентов;
- создание каталогов агента и изменение их владельца;
- регистрация задания
launchd; - настройка сертификатов, профилей и временной связки ключей по утверждённой процедуре.
После инициализации проверьте владельца файлов:
id
whoami
ls -ld /путь/к/teamcity-agent
Запуск от пользователя, которому разрешён интерактивный вход, не равен безопасной автоматизации. Доступ к ключевой цепочке, переменным среды и каталогам подписи должен быть описан отдельно. Если команда не может объяснить, кто владеет каждым каталогом и кто удаляет временные файлы, узел пока не готов к публикации.
Внимание. Полный доступ к Mac не делает несколько сборок изолированными друг от друга. Официальные рекомендации по безопасности TeamCity прямо требуют учитывать, что задания на одном агенте могут влиять на общую среду. Непроверенные pull request не следует отправлять на тот же узел, где хранятся материалы для официальной подписи.
Регистрация, авторизация и сеть
Для On-Premises агенту нужны корректные параметры подключения к серверу. Обычно проверяются:
serverUrl;authorizationToken;- имя агента;
- конфигурационный файл;
- доступ к серверу через HTTPS или настроенный обратный прокси.
Руководство по быстрой настройке TeamCity описывает базовую последовательность подключения. Но успешное отображение узла в интерфейсе ещё не доказывает готовность к работе. Сверяйте три независимых источника:
- журнал Agent на Mac;
- статус авторизации на сервере;
- сетевую доступность через корпоративный прокси и обратный прокси.
Модель подключения важна для сетевой политики: Agent инициирует соединение с сервером. Поэтому обычно не требуется открывать входящий порт из интернета к Mac, но требуется разрешить устойчивое исходящее соединение к TeamCity Server. Если прокси разрывает долгие соединения, интерфейс может показывать устаревший статус или агент будет периодически исчезать из пула.
Используйте фиксированное имя агента, управляемый конфигурационный файл и HTTPS. Не копируйте конфигурацию вместе с секретами между машинами без процедуры ротации. После регистрации остановите агент, измените только один параметр, снова запустите его и убедитесь, что изменение отражено в журнале. Такой тест быстрее выявляет ситуацию, когда интерфейс показывает старую регистрацию.
Маршрутизация Xcode и возможности узла
Подключённый Mac не обязательно умеет выполнять iOS-сборку. Частая причина — на нём установлен только Command Line Tools, а полного Xcode нет. Документация разработчика Xcode по инструментам командной строки объясняет назначение этих компонентов, но наличие xcode-select само по себе не подтверждает наличие полного приложения Xcode.
Проверьте путь и фактический инструмент:
xcode-select -p
xcodebuild -version
xcrun simctl list devices
Эти команды нужно выполнять от того же пользователя, под которым работает Agent. Результат, полученный в интерактивном терминале администратора, может отличаться от результата в автоматическом задании из-за PATH, HOME, доступа к Keychain или выбранного developer directory.
Один или несколько вариантов Xcode
При одной установленной версии достаточно зафиксировать developer directory и проверить, что параметр не меняется после перезагрузки. При нескольких версиях нельзя ограничиваться переключением xcode-select вручную на хосте: параллельные или последующие сборки могут получить другой toolchain.
Разделяйте четыре уровня настройки:
- требование задачи — какая версия или семейство Xcode необходимо проекту;
- параметр агента — что конкретный Mac действительно предоставляет;
- Agent Requirement — условие, по которому TeamCity выбирает узел;
- фактический вывод
xcodebuild— доказательство того, что процесс использовал нужный путь.
В документации TeamCity по Xcode-проектам описан запуск Xcode-сборок, а материалы по Agent Requirements показывают принцип сопоставления требований задачи и параметров агента. Для On-Premises не переносите автоматически настройки из Cloud: проверяйте, поддерживает ли конкретное поле ваша версия сервера и установленного агента.
Для нескольких версий Xcode практичнее иметь отдельные параметры, например:
teamcity.agent.xcode.16;teamcity.agent.xcode.17;teamcity.agent.architecture=arm64.
Названия должны соответствовать вашей принятой схеме и фактическим значениям, а не быть декоративными метками. В журнале сборки сохраняйте путь к Xcode и вывод xcodebuild -version. Если задача требует Xcode одной версии, а агент сообщает другую, это не предупреждение, а отказ в производственной маршрутизации.
Таблица контрольных признаков
| Область | Что должно быть зафиксировано | Чем подтверждать |
|---|---|---|
| Runtime Agent | Java 21 и корректный JAVA_HOME |
java -version, журнал запуска, системные требования |
| Архитектура | Фактическая архитектура Mac и совместимость инструментов | uname -m, карточка актива |
| Xcode | Полный Xcode, выбранный developer directory, версия | xcode-select, xcodebuild -version |
| Маршрутизация | Требование задачи совпадает с параметром узла | настройки Build Configuration и Agent Requirements |
| Регистрация | Имя, URL, токен, авторизация | журнал агента и серверный статус |
| Автозапуск | Запуск без ручной сессии или документированное ограничение | журнал launchd, тест перезапуска |
| Подпись | Доступен только нужный набор ключей и профилей | список Keychain, лог очистки |
Изоляция проектов и подписывающих данных
Общая рабочая область — не нейтральная папка. Кэш зависимостей, продукты сборки, переменные окружения и временные файлы могут переносить состояние из одной задачи в другую. Даже если сборка завершилась успешно, это не доказывает, что после неё на диске не остались профили, архивы или логи с чувствительными данными.
Используйте отдельный checkout directory для каждого логического потока или применяйте строгую очистку перед задачей. В TeamCity настройте clean checkout там, где воспроизводимость важнее скорости. Кэшируйте только то, что разрешено политикой проекта: например, публичные зависимости и безопасные промежуточные артефакты. Материалы подписи не должны попадать в общий кэш.
Полезно разделить узлы по уровню доверия:
- непроверенные PR — отдельный Agent Pool без production-секретов;
- обычные тесты — пул с ограниченными правами;
- архивирование и официальная подпись — выделенный Mac или изолированный пул;
- аварийная замена — заранее подготовленный узел с теми же требованиями Xcode.
В официальной документации по Agent Pool описано распределение агентов по группам. Пул не заменяет операционную изоляцию Mac, но помогает не направлять неподходящие проекты на критичный узел.
Подпись и временная связка ключей
Для подписания создайте отдельную временную Keychain, если это совместимо с вашей процедурой. Перед сборкой импортируйте только нужные сертификаты и профили. После завершения:
- завершите процессы, использующие ключевую цепочку;
- удалите временные файлы профилей;
- удалите или заблокируйте временную Keychain;
- проверьте список оставшихся ключей;
- сохраните в лог только факт операции, а не секретное содержимое.
Не размещайте production-сертификаты на узле, который принимает внешний код без предварительной проверки. Если такой PR должен проходить тесты, разделите этапы: сначала сборка без подписи на недоверенном агенте, затем контролируемый этап подписи на выделенном узле.
Опыт эксплуатации. Приёмка должна сравнивать каталог до и после сборки, а не только проверять зелёный статус TeamCity. Разница каталогов и список ключей после очистки дают более сильное доказательство, чем сообщение «Build finished successfully».
Автозапуск, восстановление и производственная приёмка
Автозапуск TeamCity Agent после перезагрузки
Для macOS автозапуск обычно оформляют через launchd. Важно определить, от какого пользователя загружается задание, где находится рабочий каталог и кому принадлежат plist-файл, логи и конфигурация агента.
Пример проверки списка заданий:
launchctl print system
launchctl print gui/$(id -u)
Конкретный домен зависит от выбранного способа запуска. Системный демон и пользовательский агент — не одно и то же. В официальном руководстве по запуску агента описана логика стартовых свойств; для On-Premises сверяйте её с инструкцией вашей версии и проверяйте фактическое поведение на целевом Mac.
Если Agent запускается только после интерактивного входа пользователя, это не соответствует цели полностью безнадзорного производственного узла. Такой режим можно оставить для лабораторного пилота, но не включать Mac в пул официального релиза, пока не закрыты вход, Keychain, сетевое подключение и доступ к Xcode.
Минимальный тест восстановления
Проверяйте не только сам факт загрузки системы. Последовательность должна включать:
- удалённую или согласованную перезагрузку Mac;
- подтверждение запуска
launchd; - повторное подключение Agent к серверу;
- выполнение команды
xcodebuildот технического пользователя; - проверку доступа к временной Keychain;
- запуск тестовой сборки;
- проверку очистки после завершения;
- фиксацию времени, логов и результата.
Если какой-либо шаг требует ручного вмешательства, запишите это как ограничение, а не скрывайте в эксплуатационной инструкции. Для удалённого узла особенно опасна ситуация, когда он снова подключился к TeamCity, но не может открыть Xcode, получить нужную связку ключей или удалить старую рабочую область.
Приёмка реальным конвейером
Пустой проект не показывает производственную готовность. Возьмите представительскую цепочку:
- сборка pull request;
- тесты симулятора;
- сборка архива;
- контролируемый этап подписи;
- публикация или передача артефакта в следующий этап.
Сопоставьте требования проекта, параметры агента и фактический вывод инструментов. В журнале должны остаться версия Xcode, архитектура, имя агента, выбранный пул и результат очистки. Для оценки ёмкости используйте реальные очереди и типичные задачи, а не абстрактную скорость Mac.
Условия решения
Используйте следующие ветви при допуске:
- Если Java 21 подтверждена, Agent зарегистрирован, Xcode маршрутизируется по требованию, а перезапуск проходит без ручного входа, то можно переходить к испытанию в отдельном производственном пуле.
- Если Agent подключён, но версия Xcode не подтверждается в журнале, то оставьте узел вне iOS-релизов и исправьте параметры маршрутизации.
- Если один Mac принимает недоверенный код и хранит production-подпись, то разделите Agent Pool или перенесите подпись на выделенный узел.
- Если после перезагрузки требуется администратор, то используйте Mac только как пилотный или ручной узел до устранения зависимости.
- Если очередь растёт, а резервный узел не прошёл тот же тест, то не расширяйте пул по числу машин; сначала подготовьте процедуру переключения и критерии ёмкости.
- Если физический Mac уже куплен, но простаивает между релизами, то сравните его полную стоимость владения с временной арендой удалённого Mac KVMNODE на период пилота.
Удалённый Mac может быть производственным узлом TeamCity, если он предоставляет постоянную доступность, нужную архитектуру, управляемый доступ и предсказуемое восстановление. Сам факт удалённости не является ни преимуществом, ни недостатком: решение определяется журналами, тестом подписи и результатом перезапуска.
Итоговая схема допуска
После проверки оформите запись на каждый Agent:
- идентификатор и физическое расположение узла;
- архитектура и установленный полный Xcode;
- версия Java для Agent и отдельные JDK проекта;
serverUrl, имя, пул и статус авторизации;- владелец технической учётной записи;
- правила checkout и очистки;
- модель хранения подписывающих данных;
- результаты перезапуска;
- представительские задачи и их логи;
- причина допуска, временной блокировки или возврата в пилот.
Покупка Mac mini имеет смысл, когда нагрузка стабильна, устройство уже находится под вашим физическим контролем и команда готова обслуживать диски, питание, обновления, доступ и резервирование. Но локальная схема часто оставляет вам капитальные затраты, простой между релизами, замену вышедшего из строя оборудования и ручную организацию удалённого доступа. Облачная виртуальная машина не решает задачу автоматически, если сборке нужен настоящий Mac, определённая версия Xcode и доступ к подписывающей среде.
Если фиксированная ёмкость ещё не подтверждена, безопаснее начать с отдельного удалённого Mac KVMNODE и прогнать на нём тот же TeamCity-конвейер. После подтверждения маршрутизации, Xcode, очистки и восстановления вы сможете выбрать срок аренды по очереди и требуемому резерву, а не покупать оборудование до появления доказательств. Для сравнения конкретной конфигурации можно использовать страницу Mac mini для удалённой аренды, но окончательное решение принимайте только после теста реального проекта.