После перезагрузки macOS нужно проверить четыре разных состояния: питание хоста, разблокировку диска, вход CI-пользователя и запуск пользовательского агента. Именно такую границу задаёт модель запуска macOS Runner в официальной инструкции GitLab для macOS. Поэтому наш вывод простой: не заменяйте LaunchAgent на LaunchDaemon только ради автозапуска. Сначала восстановите отдельную CI-учётную запись, контролируемый путь разблокировки FileVault, пользовательскую сессию, доступ к Keychain и послерестартовую проверку реальной сборкой.

Эта статья предназначена:

  • руководителям IT, которым нужно вернуть удалённый Mac в работу без ожидания входа оператора на месте;
  • руководителям инженерной эффективности, которым нужно отличить сбой Runner от ошибки маршрутизации или пользовательской сессии;
  • ответственным за безопасность и выпуск, которым требуется проверяемая граница между автоматическим восстановлением, FileVault и ключами подписи.
01

Сначала разделите «хост доступен» и «Runner принимает задания»

Типичная ошибка выглядит так: Mac снова отвечает по сети, SSH подключается, но в GitLab Runner остаётся offline. Это не один сбой, а рассогласование состояний.

Мы фиксируем их в таком порядке:

  1. Хост загружен. Система получила питание и завершила запуск macOS.
  2. Сеть доступна. Есть маршрут до нужных внутренних сервисов и адресов GitLab.
  3. Загрузочный том разблокирован. FileVault не оставляет систему на экране разблокировки.
  4. CI-пользователь вошёл в сессию. Его домашний каталог, окружение и пользовательские службы доступны.
  5. LaunchAgent загружен. Процесс Runner работает от ожидаемого пользователя.
  6. Runner зарегистрирован и принимает задания. Теги, область проекта и защищённые ветки допускают конкретную работу.
  7. Среда выполняет сборку. Keychain, Xcode, симулятор и подпись доступны не только процессу Runner, но и заданию.

GitLab описывает установку macOS Runner через пользовательский контекст. Apple, в свою очередь, разделяет пользовательские агенты и системные демоны в документации о запуске служб. Это значит, что успешный ping, доступный SSH или открытая страница Mac не доказывают готовность CI.

До переустановки сохраните три факта:

whoami
launchctl print-disabled gui/$(id -u)
gitlab-runner status

Команды выполняйте в нужной пользовательской сессии. Если whoami показывает администратора вместо выделенного CI-пользователя, это уже важная улика. Если gitlab-runner status запускается из другого каталога или другой установки, не меняйте конфигурацию вслепую.

02

LaunchAgent и LaunchDaemon: одинаковый автозапуск только на словах

Почему пользовательский контекст важнее самого процесса

LaunchAgent загружается в контексте пользователя. Для Runner это принципиально: рабочий каталог, переменные среды, пользовательский Keychain, доступ к графической сессии и инструменты Xcode должны принадлежать одному предсказуемому CI-аккаунту.

Проверьте:

  • под каким пользователем был установлен GitLab Runner;
  • существует ли домашний каталог этой учётной записи;
  • лежит ли конфигурация в ожидаемом пользовательском пути;
  • загружен ли агент именно в gui/<uid>, а не только виден в системном списке;
  • не установил ли оператор второй Runner под личным аккаунтом;
  • совпадает ли system_id с тем экземпляром, который виден в GitLab.

В документации GitLab о macOS Runner пользовательская служба рассматривается как штатный способ запуска. Apple объясняет различия между агентами и демонами в материалах о создании заданий launchd и проектировании системных служб.

Почему перенос в LaunchDaemon часто маскирует проблему

LaunchDaemon может стартовать в системном контексте, но это не делает пользовательские ресурсы доступными. Процесс может появиться в списке, а затем не получить:

  • разблокированный пользовательский Keychain;
  • графическую сессию для симулятора;
  • переменные среды CI-аккаунта;
  • права на сертификат и профиль подписи;
  • ожидаемый домашний каталог;
  • доступ к установленной версии Xcode.

В результате страница GitLab может показывать online, тогда как сборка падает на первом обращении к подписи. Это опаснее явного offline: оператор считает узел исправным и направляет на него релизные задания.

Не создавайте системный обход, пока не исключены неправильный аккаунт, дублирующий plist, старый процесс и не тот config.toml. Если после очистки остаётся потребность в системной службе, это уже отдельная архитектура с собственной моделью прав и тестами, а не быстрая починка перезагрузки.

03

FileVault и автоматический вход требуют отдельного решения

FileVault меняет порядок восстановления. Компьютер может физически работать, но загрузочный том ещё не разблокирован. Пока этого не произошло, пользовательский LaunchAgent и Runner не могут перейти в обычный рабочий контекст.

Apple прямо указывает, что автоматический вход и FileVault нельзя рассматривать как безусловно совместимую пару. В описании автоматического входа Apple и руководстве по управлению FileVault необходимо проверить ограничения конкретной конфигурации, политики управления устройствами и способ разблокировки.

Для каждого узла зафиксируйте выбранную модель:

  • Автоматическое восстановление. Приоритет — минимальное время вмешательства. Риск — более сложная защита ключей и входа.
  • Защищённая ручная разблокировка. Приоритет — контроль ключа FileVault. Риск — Runner не вернётся в работу без уполномоченного оператора.
  • Отдельный резервный узел. Основной Mac сохраняет строгую защиту, а выпуск переключается на заранее подготовленную мощность.
  • Ограниченное удалённое восстановление. Доступ разрешён только с администрируемого канала и с журналированием действий.

Не обещайте команде автоматическое восстановление, пока не проверены:

  • Apple Silicon или другая аппаратная архитектура;
  • версия macOS и её экран разблокировки;
  • политика управления устройством;
  • наличие Remote Login;
  • маршрутизация до узла;
  • права восстановительной учётной записи;
  • журнал действий и отзыв доступа после инцидента.

Для проверки сетевого слоя используйте официальное описание Remote Login в macOS. Оно подтверждает, что SSH-доступ нужно рассматривать отдельно от входа в графическую пользовательскую сессию.

04

Онлайн Runner не равен готовой сборочной среде

После восстановления LaunchAgent сначала проверьте дешёвые операции, затем расширяйте тест. Полный релизный pipeline не подходит для первой диагностики: он смешивает службу, зависимости, Keychain, Xcode, симулятор, подпись и публикацию.

Минимальная последовательность проверки

  1. Обычная команда. Запустите короткий job без Xcode и без секрета. Он показывает, принимает ли Runner задания.
  2. Проверка пользователя. Запишите whoami, домашний каталог и рабочую директорию. Они должны соответствовать выделенному CI-аккаунту.
  3. Доступ к Keychain. Проверьте, разблокирован ли нужный пользовательский Keychain и видит ли его процесс задания.
  4. Запуск Xcode-инструмента. Выполните минимальную проверку выбранной версии Xcode без публикации результата.
  5. Симулятор. Проверьте старт нужного runtime и завершение простого теста.
  6. Подпись. Выполните тестовый signing на непубликуемом артефакте.
  7. Релизный job. Только после предыдущих шагов допускайте сборку, требующую сертификатов, профилей и публикации.

Разделяйте:

  • login Keychain и системный Keychain;
  • CI-пользователя и локального администратора;
  • процесс Runner и shell, который запускает job;
  • наличие сертификата и право использовать закрытый ключ;
  • доступ к симулятору и доступ к физическому устройству;
  • переменную CI и фактическое наличие секрета в окружении.

Если Runner online, но подпись не работает, не меняйте сразу разрешения всей системы. Сначала определите, какой именно пользователь выполняет команду и какой Keychain вызывает инструмент. Данные подписи должны оставаться доступными только нужному проекту и узлу.

05

Ошибочный аккаунт, остаточные службы и маршрутизация

Повторная установка под разными пользователями создаёт правдоподобную, но опасную картину. Один процесс может быть активен, второй — зарегистрирован в GitLab, а третий plist — загружаться после входа администратора.

Проверьте локально:

ps aux | grep -i gitlab-runner
launchctl list | grep -i gitlab
find "$HOME/Library/LaunchAgents" -maxdepth 1 -iname '*gitlab*' -print

Команды показывают направление проверки, но не заменяют анализ владельца процесса и конфигурационного файла. Не удаляйте plist, пока не сохранены путь, владелец и связанный system_id.

Затем сверяйте серверную маршрутизацию:

  • совпадает ли тег Runner с тегом job;
  • разрешён ли Runner для нужного проекта или группы;
  • допускает ли он защищённую ветку;
  • не зарегистрирован ли узел с устаревшим токеном;
  • не направляется ли задача на другой Runner;
  • не запрещена ли нужная архитектура или версия инструмента политикой проекта.

Правила тегов и область использования описаны в документации GitLab по настройке Runner. Это отдельный слой причины. Job может оставаться в очереди из-за маршрутизации, хотя macOS Runner полностью исправен.

Отладочные журналы включайте только на согласованное время. В FAQ GitLab Runner отдельно учитываются риски диагностических данных. Не допускайте попадания токенов, переменных CI, сертификатов и команд с секретами в централизованный журнал.

06

Пошаговый runbook восстановления

Используйте этот порядок как рабочую процедуру. Каждый пункт должен иметь владельца и доказательство выполнения.

  • [ ] Зафиксировать время перезагрузки, причину и последний известный статус Runner.
  • [ ] Проверить доступность Mac по согласованному каналу, не считая это доказательством готовности CI.
  • [ ] Определить, разблокирован ли FileVault, и записать способ восстановления без публикации секретного ключа.
  • [ ] Проверить вход именно выделенного CI-пользователя.
  • [ ] Выполнить whoami и сопоставить UID с ожидаемой учётной записью.
  • [ ] Найти пользовательский plist Runner и проверить его владельца.
  • [ ] Сопоставить config.toml, токен, system_id и запись Runner в GitLab.
  • [ ] Проверить LaunchAgent в контексте gui/<uid>.
  • [ ] Убедиться, что не осталось второго процесса или старой установки.
  • [ ] Выполнить простой job без Xcode и секретов.
  • [ ] Проверить доступ к требуемому Keychain от имени CI-пользователя.
  • [ ] Выполнить короткую Xcode-сборку без публикации.
  • [ ] Проверить симулятор, если он используется в производственном pipeline.
  • [ ] Выполнить тест подписи на непубликуемом артефакте.
  • [ ] Проверить теги, область проекта и защищённые ветки.
  • [ ] Провести контролируемую повторную перезагрузку.
  • [ ] Повторить проверку после перезагрузки, а не только наблюдать статус online.
  • [ ] Сохранить результат, время и ответственного в журнале изменений.
  • [ ] Повторить сценарий после отзыва доступа у восстановительной учётной записи.

Если узел не проходит один из пунктов, не переводите его в пул релизных Runner. Статус «online» является промежуточным сигналом, а не производственным допуском.

07

FAQ для владельца корпоративного CI

Почему GitLab Runner не запускается после перезагрузки?

Главная причина — расхождение между загрузкой macOS и входом пользователя. Проверьте, вошёл ли выделенный CI-аккаунт, загружен ли его LaunchAgent и используется ли правильный конфигурационный файл. Переустановка без проверки владельца часто оставляет прежнюю проблему и добавляет второй процесс.

Обязательно ли входить в систему пользователю macOS?

Для поддерживаемого пользовательского режима — да, соответствующая сессия нужна. Это особенно заметно при использовании Xcode, симулятора и подписания. Доступный SSH не заменяет графическую сессию и не гарантирует открытый Keychain.

Допустимо ли запускать Runner как LaunchDaemon?

Как универсальное исправление — нет. Системный демон изменяет контекст прав и может потерять пользовательские ресурсы. Сначала восстановите LaunchAgent, выделенный аккаунт и послерестартовую проверку. Любое отклонение оформляйте как отдельное решение с анализом рисков.

Что делать с FileVault на удалённом узле?

Сначала выберите приоритет: автоматическое восстановление или более строгий контроль ключа разблокировки. Затем проверьте Remote Login, политику управления устройствами и аудит. Не рассчитывайте, что включённый Mac автоматически дойдёт до пользовательской сессии.

Как диагностировать Keychain при online Runner?

Проверяйте его от имени того же CI-пользователя, который выполняет job. Отдельно протестируйте обычный shell, доступ к Keychain, Xcode, симулятор и signing. Полный релизный pipeline оставьте последним шагом, иначе ошибка одного слоя скроет остальные.

08

Производственный допуск и выбор резервного узла

После исправления проведите три разных испытания: плановую перезагрузку, восстановление после неожиданного отключения и отзыв доступа у оператора. Для каждого сценария нужны начальное состояние, ожидаемый результат, журнал команд и решение при отказе.

Если единственный Mac требует физического присутствия для разблокировки или входа, это не обязательно дефект Runner. Это ограничение выбранной модели восстановления. Но для выпуска оно становится инфраструктурным риском. В таком случае сравните:

  • один узел с ручным восстановлением;
  • основной и резервный Mac с независимыми профилями;
  • временную аренду удалённого Mac для аварийной ёмкости;
  • постоянную закупку оборудования для стабильной длительной нагрузки.

При планировании можно изучить варианты аренды Mac для корпоративной команды и отдельно оформление Mac mini для удалённой работы. Эти материалы не заменяют проверку CI: перед допуском нужно подтвердить удалённый доступ, учётную запись, перезагрузку, Keychain и реальную Xcode-задачу.

Текущий одиночный Mac обычно проигрывает не из-за самого железа, а из-за операционной зависимости: один узел требует ручной разблокировки, его состояние трудно доказать после рестарта, а отказ оставляет очередь без альтернативы. Покупка нескольких устройств устраняет часть риска, но добавляет закупку, доставку, обслуживание, замену и контроль конфигураций. Если нужен временный или резервный контур без немедленного расширения собственного парка, аренда Mac через MESHLAUNCH может дать более управляемый путь — при условии, что в договорённости заранее зафиксированы доступ, восстановление и сценарий замены.

Перед передачей нового узла в производство мы рекомендуем получить не обещание «Runner будет online», а набор доказательств: пользовательская сессия восстановилась, LaunchAgent загрузился, FileVault-процесс понятен, Keychain доступен, минимальная Xcode-сборка прошла, а резервный путь проверен. Только после этого Mac следует считать частью корпоративного CI/CD.