Развёртывание Buildkite Agent на удалённом Mac возможно, но узел с Xcode 27 следует держать отдельно от стабильной производственной среды и принимать только после реальных проверок. Начните с командной сборки, затем добавляйте Simulator, подпись и восстановление после перезапуска; одного статуса «Agent online» недостаточно.
Эта инструкция предназначена разработчикам iOS и macOS, которые переносят сборку с локального компьютера в Buildkite, DevOps-инженерам, поддерживающим постоянно доступный Mac, и руководителям платформ, тестирующим Xcode 27 Beta параллельно со стабильным pipeline. Если вам нужен только обычный Linux-узел или физический интерфейс iPhone, этот сценарий не закрывает задачу полностью.
Важно: на дату последней проверки, 31 августа 2026 года, Xcode 27 следует рассматривать как тестовую версию. Его совместимость, известные ограничения и требования нужно сверять с актуальными заметками к выпуску Xcode 27 Beta, а не с предположениями из форумов.
Последнее обновление: 31 августа 2026 года; сведения проверены по документации Apple и Buildkite, перечисленной в статье.
SECTION 01 До начала: какой узел вы действительно собираетесь развернуть?
Первое решение — не установка агента, а границы эксперимента. Для Xcode 27 выделите отдельный физический Apple Silicon Mac, на котором не выполняются критичные производственные сборки. Официальные требования к поддерживаемой версии macOS, SDK и Xcode проверяйте на странице системных требований Xcode. Если чип, система или установленный runtime не соответствуют требованиям, остановите настройку: агент не исправит несовместимость инструментария.
У удалённой схемы есть три независимых компонента:
- управляющая плоскость Buildkite распределяет задания;
- Buildkite self-hosted agent получает задания и запускает команды;
- удалённый Mac предоставляет macOS, Xcode, рабочий каталог, Simulator и, при необходимости, ключи подписи.
Агенту не требуется произвольно открытый входящий порт для получения заданий: он устанавливает исходящее соединение с управляющей плоскостью. Это не означает, что сервер можно оставить без контроля. Вам всё равно нужны защищённый SSH-доступ, ограничение административных прав, сетевые правила исходящего трафика и понятная процедура восстановления. Рекомендации по модели работы описаны в официальной документации Buildkite для self-hosted Agent.
Сразу разделите нагрузку на три профиля:
- Командная сборка — разрешение зависимостей, компиляция, unit-тесты и создание результата.
- Графическая проверка — запуск iOS Simulator, UI-тесты и сбор диагностических файлов.
- Публикация — подпись, упаковка и передача релизного артефакта.
Первый профиль подходит для базового узла. Второй добавляет требования к пользовательской сессии и runtime Simulator. Третий требует отдельной модели секретов. Не смешивайте их только потому, что один Mac технически способен выполнить все команды.
Критерий остановки до установки
Не продолжайте, если у вас нет:
- отдельного Apple Silicon Mac, соответствующего требованиям Xcode 27;
- способа получить удалённый доступ после перезапуска;
- отдельного аккаунта для Agent;
- изолированной очереди для экспериментального инструментария;
- плана удаления рабочей директории и отзыва ключей;
- стабильного узла, куда можно вернуть производственные задачи.
Если нужен временный изолированный узел, заранее сравните условия аренды удалённого Mac VPSNIX с покупкой и самостоятельным размещением оборудования. Но сначала определите, какие проверки вы будете считать успешными.
SECTION 02 Первый час: отдельный пользователь, Queue и регистрация Agent
Шаг 1. Создайте операционный контур
Используйте специальную локальную учётную запись macOS без повседневных административных прав. Её имя в примерах обозначим как <CI_USER>. Не подставляйте в команды рабочее имя сотрудника: после увольнения, смены роли или удаления аккаунта это усложнит аудит и восстановление.
Под этим пользователем проверьте:
- доступность домашнего каталога;
- права на рабочую директорию;
- запуск оболочки без интерактивных настроек;
- наличие Git, Homebrew и нужных языковых SDK;
- отсутствие секретов в
.zshrc,.bash_profileи аналогичных файлах.
Официальная инструкция по установке Agent на macOS должна быть источником для конкретной схемы установки, расположения конфигурации и запуска через launchd. Не угадывайте путь к файлу buildkite-agent.cfg: сначала найдите фактическую конфигурацию на вашем узле и зафиксируйте её в документации команды.
Шаг 2. Зарегистрируйте узел без утечки секрета
Создайте отдельный <AGENT_TOKEN> с минимально необходимой областью действия. В примере ниже все значения условные:
buildkite-agent start \
--token "<AGENT_TOKEN>" \
--name "<REMOTE_MAC_NAME>" \
--tags "xcode-27,apple-silicon,experimental"
Не записывайте настоящий токен в shell history, pipeline, скриншоты или журналы. Имя узла, Cluster и Queue также задавайте явно, чтобы диагностике не приходилось восстанавливать маршрут по косвенным признакам. Правила создания и назначения очередей сверяйте с документацией Buildkite по Queue.
Ваша цель на этом этапе — не «запустить CI», а доказать четыре факта:
- Agent зарегистрирован в правильном Cluster.
- Он виден в нужной Queue.
- Метки узла не совпадают случайно с производственными.
- Задание с тестовыми требованиями не может попасть на другой Mac.
Отправьте минимальную задачу, которая выводит только систему, архитектуру и путь к инструментам:
sw_vers
uname -m
xcode-select -p
xcodebuild -version
В выводе не должно быть токенов, паролей, содержимого переменных окружения или списка ключей. Если задача не выполняется, сначала исправьте маршрутизацию и права, а не добавляйте новые процессы Agent.
SECTION 03 После регистрации: закрепите Xcode 27 и проведите командную сборку
Статус «online» сообщает только о связи процесса с Buildkite. Он не подтверждает доступ к репозиторию, корректность Xcode, работу зависимостей или возможность сформировать пригодный артефакт.
Шаг 3. Зафиксируйте путь к инструментарию
Проверьте установленные приложения и выберите Xcode 27 явно:
sudo xcode-select --switch "/Applications/<XCODE_27_APP>.app/Contents/Developer"
xcodebuild -version
xcrun --find xcodebuild
Используйте фактическое имя каталога, а не предположение о том, как Beta-версия названа на диске. Если производственный Xcode установлен рядом, не меняйте глобальный выбор без понимания последствий для других задач. Надёжнее передавать путь на уровне конкретного шага или Agent и записывать результат проверки в лог.
На этом узле не следует автоматически обновлять Xcode. Для экспериментального pipeline зафиксируйте версию и дату проверки; для производственного — оставьте стабильный инструментальный контур. Если Apple меняет требования или известные ограничения, повторите матрицу приёмки, а не объявляйте обновление безопасным по факту успешной установки.
Шаг 4. Дайте доступ к коду с минимальными правами
Учётной записи <CI_USER> нужен доступ только к тем репозиториям и веткам, которые требуются этому pipeline. Используйте машинную идентичность с возможностью ротации или управляемое хранилище секретов. Не копируйте личный SSH-ключ разработчика на постоянный CI-узел.
В правилах доступа к коду для self-hosted Agent проверьте, как именно ваш способ аутентификации передаёт ключ процессу, запущенному через launchd. Интерактивный терминал и фоновый сервис могут иметь разные переменные окружения, домашний каталог и доступ к связке ключей.
Для первой задачи зафиксируйте:
- идентификатор коммита;
- версию Xcode;
- версию SDK;
- используемый путь к рабочей директории;
- команды установки зависимостей;
- exit code каждого этапа;
- расположение результата.
Шаг 5. Пройдите полный командный цикл
Возьмите небольшой реальный проект, а не пустую команду. Последовательность должна быть воспроизводимой:
set -o errexit
set -o pipefail
xcodebuild \
-workspace "<WORKSPACE_PATH>" \
-scheme "<SCHEME_NAME>" \
-configuration Release \
-sdk "<SDK_NAME>" \
-destination "generic/platform=iOS" \
clean build \
| tee "<BUILD_LOG_PATH>"
Сначала проверьте разрешение зависимостей, затем компиляцию, unit-тесты и появление ожидаемого результата. Не считайте pipeline успешным, если команда завершилась без ошибки, но артефакт отсутствует или лежит в непредсказуемом каталоге.
На этом этапе также выявляются скрытые зависимости: переменные из интерактивного профиля, локальный кэш разработчика, незаписанный путь к сертификату или ручное подтверждение системного диалога. Каждую такую зависимость либо объявите в конфигурации, либо удалите. Если воспроизводимость невозможна, остановите расширение узла до Simulator и подписи.
Опыт эксплуатации: рабочая сборка из SSH не доказывает, что та же команда сработает через launchd. Сравнивайте пользователя,
PATH, домашний каталог, права на рабочую директорию и доступ к связке ключей в обоих режимах.
SECTION 04 Нужен ли Simulator: графическая сессия и первый тест
Не добавляйте Simulator на каждый узел автоматически. Для чистой компиляции он не нужен, а лишняя графическая зависимость увеличивает число состояний, которые придётся восстанавливать после перезапуска.
Шаг 6. Проверьте runtime и пользовательскую сессию
Если pipeline содержит UI-тесты, убедитесь, что:
- нужный runtime Simulator установлен и совместим с выбранным Xcode;
- процесс Agent принадлежит ожидаемому пользователю;
- пользовательская графическая сессия действительно доступна;
- виртуальное устройство видно через
xcrun simctl; - рабочий каталог не конфликтует с другой задачей.
Минимальная проверка может выглядеть так:
xcrun simctl list devices available
xcrun simctl boot "<SIMULATOR_UDID>" || true
xcrun simctl bootstatus "<SIMULATOR_UDID>" -b
Затем выполните один небольшой тестовый набор, соберите результат и удалите или сбросьте временное устройство по правилам вашей команды. Укажите в логе UDID, версию runtime и результат очистки, но не выводите секреты проекта.
Успешный запуск Simulator отвечает только на вопрос о симулированной среде. Он не заменяет тест на физическом устройстве, проверку push-уведомлений, камеры, Bluetooth или публикации. Если сессия недоступна после перезапуска, вернитесь к чистому командному узлу и не маскируйте проблему увеличением таймаутов.
SECTION 05 Публикация: как не отдать ключи обычной сборке
Шаг 7. Разделите очереди, аккаунты и рабочие каталоги
Обычная проверка изменений не должна автоматически получать доступ к производственным сертификатам. Разумная схема выглядит так:
- очередь
<QUEUE_BUILD>— компиляция и тесты без закрытых ключей; - очередь
<QUEUE_SIGNING>— ограниченный набор доверенных задач; - отдельная учётная запись или контролируемый шаг для подписи;
- отдельный рабочий каталог для релизного процесса;
- запрет параллельного доступа к одной связке ключей и одному набору DerivedData.
Перед первым релизным запуском проверьте соответствие сертификата, профиля и Team ID, но в документации и примерах оставляйте <CERTIFICATE_NAME>, <TEAM_ID>, <KEYCHAIN_PASSWORD> и <PROFILE_NAME>. Пароль не должен находиться в pipeline-файле или аргументах процесса, доступных диагностике.
Практические рекомендации по проблемам подписания и управлению ключами сверяйте с материалами Apple о code signing. Секреты лучше выдавать непосредственно ограниченному шагу и отзывать после завершения эксперимента, если это допускает ваша модель поставки.
Если один Agent выполняет несколько задач одновременно, тестируйте конкуренцию отдельно. DerivedData, Simulator, временные файлы и связка ключей могут стать общими точками конфликта. Без доказательства безопасной изоляции оставьте один процесс и последовательное выполнение. Масштабирование количеством Agent не является заменой раздельным каталогам и очередям.
SECTION 06 Перезапуск и первая неделя: когда узел можно считать готовым
Шаг 8. Настройте постоянный запуск через launchd
Для постоянного Agent используйте launchd, а не процесс, запущенный вручную в SSH-сессии. Файл задания должен ссылаться на фактические пути к исполняемому файлу, конфигурации, журналам и рабочему каталогу, а также явно задавать пользователя и окружение.
Синтаксис и ограничения фоновых заданий сверяйте с документацией Apple по созданию launchd-задач. До загрузки задания сохраните копию исходного файла и запишите команду отката. Если при изменении launchd или связки ключей вы потеряете удалённый доступ, восстановление должно выполняться через заранее согласованный консольный или административный канал.
Проверяйте не только существование процесса:
launchctl print "system/<SERVICE_LABEL>"
ps aux | grep "[b]uildkite-agent"
После этого отправьте тестовую задачу в нужную Queue. Процесс может быть жив, но не иметь доступа к конфигурации, сети, пользовательской сессии или Xcode.
Шаг 9. Выполните контролируемую перезагрузку
Перед перезапуском:
- остановите активные задачи;
- сохраните журналы;
- отметьте текущий коммит и версию Xcode;
- убедитесь, что есть удалённый путь возврата;
- предупредите владельцев pipeline.
После перезапуска последовательно проверьте удалённый доступ, состояние пользовательской сессии, загрузку launchd-задачи, появление Agent в Queue и выполнение настоящей командной сборки. Затем отдельно повторите Simulator и подпись, если эти функции входят в назначение узла.
На первой неделе наблюдайте за ростом диска, очисткой рабочих каталогов, ротацией журналов, зависшими Simulator и правилами обновления Agent. Не удаляйте рабочие данные массовой командой, пока не определены каталоги, исключения и способ восстановления. В центре помощи VPSNIX можно сверить общие процедуры доступа и обслуживания удалённой Mac-среды, но проектную приёмку всё равно выполняйте на собственном pipeline.
SECTION 07 Контрольная точка перед добавлением в production
Отметьте каждый пункт только после получения наблюдаемого результата:
- [ ] Узел использует Apple Silicon Mac и систему, совместимые с Xcode 27 по актуальным материалам Apple.
- [ ] Xcode 27 установлен отдельно от стабильного производственного инструментария и выбран явно.
- [ ] Agent работает от специальной низкопривилегированной учётной записи.
- [ ] Токен хранится вне репозитория, командной строки в журналах и примеров документации.
- [ ] Cluster, Queue и метки направляют тестовые задания только на нужный узел.
- [ ] Минимальная задача выводит систему, архитектуру и путь к Xcode без секретов.
- [ ] Реальный проект проходит разрешение зависимостей, сборку, unit-тесты и создаёт ожидаемый результат.
- [ ] Simulator проверен только в том случае, если он входит в назначение узла.
- [ ] Подпись вынесена в отдельную очередь, аккаунт или ограниченный шаг.
- [ ] Нет доказанного конфликта DerivedData, Simulator, рабочих каталогов и связки ключей.
- [ ] После перезапуска Agent появляется в нужной Queue и выполняет реальную задачу.
- [ ] Есть стабильный узел или понятный маршрут отката для производственной сборки.
SECTION 08 Какой вариант размещения выбрать для Xcode 27 CI?
| Вариант | Когда подходит | Главный риск | Решение для Xcode 27 |
|---|---|---|---|
| Локальный Mac разработчика | Нерегулярные ручные проверки и отладка | Сборка зависит от занятости и состояния рабочего компьютера | Не использовать как единственный CI-узел |
| Собственный Mac mini в офисе | Долгий стабильный проект при наличии администрирования | Электропитание, сеть, удалённое восстановление и обслуживание ложатся на команду | Подходит после теста перезапуска и доступа |
| Удалённый Mac в аренду | Временная Beta-проверка, изолированный pipeline, отсутствие собственного Apple Silicon Mac | Нужно проверить задержку, доступность сессии, дисковое пространство и правила обслуживания | Хороший кандидат для отдельной Queue и поэтапной приёмки |
| Виртуальная или неподходящая среда | Эксперименты, не требующие полного macOS-инструментария | Нельзя заранее считать совместимость Xcode, Simulator и подписи доказанной | Не выбирать для обязательной публикации без реальной проверки |
Таблица не заменяет тестирование: совместимость проекта, время сборки, стабильность Simulator и восстановление после перезапуска должны быть подтверждены именно на том узле, который попадёт в pipeline. Производительность без привязки к модели Mac, версии macOS, проекту и дате измерения нельзя считать универсальным показателем.
SECTION 09 Частые вопросы
Можно ли использовать удалённый Mac как Buildkite Agent?
Да, если это реальный Mac с совместимыми macOS и Xcode, доступом к сети и отдельной учётной записью. Для получения заданий Agent использует исходящее соединение, но SSH-доступ, графическая сессия и восстановление после перезапуска требуют самостоятельной проверки.
Как указать Xcode 27 для конкретной сборки?
Назначьте узлу отдельные метки и Queue, а в шаге явно выберите каталог Xcode 27. Затем проверьте xcodebuild -version внутри задания. Если путь задан только в профиле интерактивного shell, фоновый Agent может использовать другой Xcode.
Может ли macOS CI продолжить работу после перезапуска Mac?
Может, если Agent зарегистрирован как launchd-служба, конфигурация доступна нужному пользователю, а сеть и сессия восстанавливаются без ручного входа. Проверяйте полный тестовый pipeline, а не только процесс иконки или строку «online» в интерфейсе.
Достаточно ли Simulator для приёмки iOS-приложения?
Нет. Simulator подтверждает работоспособность конкретного симулированного runtime и сценария теста. Он не заменяет проверку на физическом устройстве, аппаратных функций, поведения подписанного приложения и финальной процедуры публикации.
Как защитить сертификаты на self-hosted Mac?
Разделите сборочные и подписывающие очереди, используйте отдельную связку ключей и минимальные права, а секреты передавайте только ограниченному шагу. После эксперимента проверьте журналы и историю shell: в них не должны появиться токены, пароли, Team ID или закрытые ключи.
Если текущая схема основана на личном Mac разработчика, офисном мини-компьютере или нестабильной виртуальной среде, у неё обычно обнаруживаются три слабых места: непредсказуемая доступность, ручное восстановление после перезапуска и смешение экспериментальных сертификатов со стабильной сборкой. Для краткого теста Xcode 27 практичнее взять отдельный удалённый Apple Silicon Mac в аренду у VPSNIX, выполнить описанную приёмку и только затем решать, нужен ли вам собственный постоянно обслуживаемый узел. Условия можно проверить на странице тарифов VPSNIX; долгую тяжёлую эксплуатацию и сценарии с обязательным физическим устройством следует заранее сравнить с покупкой собственного оборудования.
SECTION 10 Часто задаваемые вопросы
Можно ли установить Buildkite Agent на удалённый Mac в дата-центре?
Да, Buildkite Agent поддерживает установку на macOS, включая удалённый физический Mac. Агент обычно сам устанавливает исходящее соединение с управляющей плоскостью и получает задания из назначенной очереди, поэтому для базовой работы не требуется открывать произвольные входящие порты. Однако удалённый доступ, учётная запись, хранилище ключей и восстановление после перезапуска проверяются отдельно.
Как направить сборку на узел с Xcode 27?
Назначьте изолированному Agent отдельные Cluster и Queue, добавьте проверяемые метки и в pipeline явно укажите требуемую очередь. На самом Mac зафиксируйте путь к Xcode 27 через xcode-select или переменную, заданную в конфигурации агента. Перед публикацией проверьте, что задача действительно попала на нужный узел, а не только отображается как ожидающая.
Что нужно настроить, чтобы macOS Agent снова появился после перезагрузки?
Запускайте Agent через launchd от специальной учётной записи и проверьте, что конфигурация, рабочий каталог и права доступа доступны без интерактивного входа. После контролируемой перезагрузки нужно проверить не только процесс, но и подключение к очереди, получение тестового задания, состояние пользовательской сессии и доступность инструментов Xcode. Только такая проверка подтверждает автоматическое восстановление.
Поддерживает ли self-hosted Mac Agent тесты iOS Simulator?
Да, удалённый Mac может выполнять задачи с iOS Simulator, если на нём установлены совместимые Xcode и runtime, а процесс запускается в пригодной графической пользовательской сессии. Для этого нужна отдельная проверка запуска устройства, выполнения теста, сбора результата и очистки. Успешный Simulator не доказывает работоспособность тестов на физическом iPhone или готовность к публикации.
Как отделить сертификаты подписи от обычных Buildkite задач?
Разделите очереди или учётные записи для обычных Pull Request-сборок и публикации, а доступ к закрытым ключам предоставляйте только контролируемому шагу. Используйте отдельную связку ключей, минимальные права, временные секреты и явную проверку профилей. Не помещайте сертификаты, пароли, Team ID и токены в pipeline, репозиторий или диагностический вывод.