После перезагрузки macOS нужно проверить четыре разных состояния: питание хоста, разблокировку диска, вход CI-пользователя и запуск пользовательского агента. Именно такую границу задаёт модель запуска macOS Runner в официальной инструкции GitLab для macOS. Поэтому наш вывод простой: не заменяйте LaunchAgent на LaunchDaemon только ради автозапуска. Сначала восстановите отдельную CI-учётную запись, контролируемый путь разблокировки FileVault, пользовательскую сессию, доступ к Keychain и послерестартовую проверку реальной сборкой.
Эта статья предназначена:
- руководителям IT, которым нужно вернуть удалённый Mac в работу без ожидания входа оператора на месте;
- руководителям инженерной эффективности, которым нужно отличить сбой Runner от ошибки маршрутизации или пользовательской сессии;
- ответственным за безопасность и выпуск, которым требуется проверяемая граница между автоматическим восстановлением, FileVault и ключами подписи.
Сначала разделите «хост доступен» и «Runner принимает задания»
Типичная ошибка выглядит так: Mac снова отвечает по сети, SSH подключается, но в GitLab Runner остаётся offline. Это не один сбой, а рассогласование состояний.
Мы фиксируем их в таком порядке:
- Хост загружен. Система получила питание и завершила запуск macOS.
- Сеть доступна. Есть маршрут до нужных внутренних сервисов и адресов GitLab.
- Загрузочный том разблокирован. FileVault не оставляет систему на экране разблокировки.
- CI-пользователь вошёл в сессию. Его домашний каталог, окружение и пользовательские службы доступны.
- LaunchAgent загружен. Процесс Runner работает от ожидаемого пользователя.
- Runner зарегистрирован и принимает задания. Теги, область проекта и защищённые ветки допускают конкретную работу.
- Среда выполняет сборку. 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 запускается из другого каталога или другой установки, не меняйте конфигурацию вслепую.
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. Если после очистки остаётся потребность в системной службе, это уже отдельная архитектура с собственной моделью прав и тестами, а не быстрая починка перезагрузки.
FileVault и автоматический вход требуют отдельного решения
FileVault меняет порядок восстановления. Компьютер может физически работать, но загрузочный том ещё не разблокирован. Пока этого не произошло, пользовательский LaunchAgent и Runner не могут перейти в обычный рабочий контекст.
Apple прямо указывает, что автоматический вход и FileVault нельзя рассматривать как безусловно совместимую пару. В описании автоматического входа Apple и руководстве по управлению FileVault необходимо проверить ограничения конкретной конфигурации, политики управления устройствами и способ разблокировки.
Для каждого узла зафиксируйте выбранную модель:
- Автоматическое восстановление. Приоритет — минимальное время вмешательства. Риск — более сложная защита ключей и входа.
- Защищённая ручная разблокировка. Приоритет — контроль ключа FileVault. Риск — Runner не вернётся в работу без уполномоченного оператора.
- Отдельный резервный узел. Основной Mac сохраняет строгую защиту, а выпуск переключается на заранее подготовленную мощность.
- Ограниченное удалённое восстановление. Доступ разрешён только с администрируемого канала и с журналированием действий.
Не обещайте команде автоматическое восстановление, пока не проверены:
- Apple Silicon или другая аппаратная архитектура;
- версия macOS и её экран разблокировки;
- политика управления устройством;
- наличие Remote Login;
- маршрутизация до узла;
- права восстановительной учётной записи;
- журнал действий и отзыв доступа после инцидента.
Для проверки сетевого слоя используйте официальное описание Remote Login в macOS. Оно подтверждает, что SSH-доступ нужно рассматривать отдельно от входа в графическую пользовательскую сессию.
Онлайн Runner не равен готовой сборочной среде
После восстановления LaunchAgent сначала проверьте дешёвые операции, затем расширяйте тест. Полный релизный pipeline не подходит для первой диагностики: он смешивает службу, зависимости, Keychain, Xcode, симулятор, подпись и публикацию.
Минимальная последовательность проверки
- Обычная команда. Запустите короткий job без Xcode и без секрета. Он показывает, принимает ли Runner задания.
- Проверка пользователя. Запишите
whoami, домашний каталог и рабочую директорию. Они должны соответствовать выделенному CI-аккаунту. - Доступ к Keychain. Проверьте, разблокирован ли нужный пользовательский Keychain и видит ли его процесс задания.
- Запуск Xcode-инструмента. Выполните минимальную проверку выбранной версии Xcode без публикации результата.
- Симулятор. Проверьте старт нужного runtime и завершение простого теста.
- Подпись. Выполните тестовый signing на непубликуемом артефакте.
- Релизный job. Только после предыдущих шагов допускайте сборку, требующую сертификатов, профилей и публикации.
Разделяйте:
- login Keychain и системный Keychain;
- CI-пользователя и локального администратора;
- процесс Runner и shell, который запускает job;
- наличие сертификата и право использовать закрытый ключ;
- доступ к симулятору и доступ к физическому устройству;
- переменную CI и фактическое наличие секрета в окружении.
Если Runner online, но подпись не работает, не меняйте сразу разрешения всей системы. Сначала определите, какой именно пользователь выполняет команду и какой Keychain вызывает инструмент. Данные подписи должны оставаться доступными только нужному проекту и узлу.
Ошибочный аккаунт, остаточные службы и маршрутизация
Повторная установка под разными пользователями создаёт правдоподобную, но опасную картину. Один процесс может быть активен, второй — зарегистрирован в 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, сертификатов и команд с секретами в централизованный журнал.
Пошаговый 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» является промежуточным сигналом, а не производственным допуском.
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 оставьте последним шагом, иначе ошибка одного слоя скроет остальные.
Производственный допуск и выбор резервного узла
После исправления проведите три разных испытания: плановую перезагрузку, восстановление после неожиданного отключения и отзыв доступа у оператора. Для каждого сценария нужны начальное состояние, ожидаемый результат, журнал команд и решение при отказе.
Если единственный Mac требует физического присутствия для разблокировки или входа, это не обязательно дефект Runner. Это ограничение выбранной модели восстановления. Но для выпуска оно становится инфраструктурным риском. В таком случае сравните:
- один узел с ручным восстановлением;
- основной и резервный Mac с независимыми профилями;
- временную аренду удалённого Mac для аварийной ёмкости;
- постоянную закупку оборудования для стабильной длительной нагрузки.
При планировании можно изучить варианты аренды Mac для корпоративной команды и отдельно оформление Mac mini для удалённой работы. Эти материалы не заменяют проверку CI: перед допуском нужно подтвердить удалённый доступ, учётную запись, перезагрузку, Keychain и реальную Xcode-задачу.
Текущий одиночный Mac обычно проигрывает не из-за самого железа, а из-за операционной зависимости: один узел требует ручной разблокировки, его состояние трудно доказать после рестарта, а отказ оставляет очередь без альтернативы. Покупка нескольких устройств устраняет часть риска, но добавляет закупку, доставку, обслуживание, замену и контроль конфигураций. Если нужен временный или резервный контур без немедленного расширения собственного парка, аренда Mac через MESHLAUNCH может дать более управляемый путь — при условии, что в договорённости заранее зафиксированы доступ, восстановление и сценарий замены.
Перед передачей нового узла в производство мы рекомендуем получить не обещание «Runner будет online», а набор доказательств: пользовательская сессия восстановилась, LaunchAgent загрузился, FileVault-процесс понятен, Keychain доступен, минимальная Xcode-сборка прошла, а резервный путь проверен. Только после этого Mac следует считать частью корпоративного CI/CD.