Источник данных: официальная документация Jenkins отдельно описывает несколько способов связи контроллера с Agent — через SSH, входящее подключение и WebSocket. Поэтому при отключении Jenkins macOS Agent не следует сразу переустанавливать узел: сначала определите, на каком уровне возник сбой. Практический порядок такой: планирование Jenkins, сеть и канал подключения, процесс Java Agent, постоянная сессия macOS, затем рабочий каталог и Xcode. Случайный сбой процесса можно исправить на месте. Повторяющиеся обрывы или дрейф окружения — основание изолировать узел и пересоздать его либо добавить отдельный удалённый Mac.
Эта статья предназначена для трёх групп:
- DevOps-инженеров, которым нужно быстрее возвращать Jenkins Agent в рабочее состояние.
- Разработчиков Apple-платформы, поддерживающих Xcode CI для сборки, тестов и подписи.
- Владельцев CI-платформы, которым нужны понятные критерии приёмки постоянно работающего macOS-узла.
Сначала отделите отключение от неисправной диспетчеризации
Одинаковая надпись в интерфейсе Jenkins может скрывать разные проблемы. Узел действительно мог потерять соединение. Контроллер мог сам пометить его офлайн. Задание может стоять в очереди из-за несовпадения метки или отсутствия свободного исполнителя, хотя Agent остаётся подключённым.
Начните с фиксации пяти элементов:
- времени последнего успешного задания;
- времени, когда узел впервые стал офлайн;
- текста причины в карточке узла;
- причины ожидания конкретного задания;
- последних строк лога контроллера и лога Agent.
Сопоставьте эти данные с состоянием удалённого Mac. Если SSH работает, это подтверждает только доступность операционной системы и системного SSH. Это не доказывает, что Jenkins Agent жив, Java запущена, секрет актуален, а рабочий пользователь видит тот же набор инструментов.
В разделе управления узлами Jenkins проверьте:
- статус соединения;
- назначенные метки;
- число исполнительных слотов;
- удалённый корневой каталог;
- выбранный Launch Method;
- признак ручного или административного отключения.
Официальное руководство по управлению узлами и Agent в Jenkins полезно использовать как карту интерфейса, но не как замену журналам. Важна временная последовательность: что произошло первым — потеря канала, завершение процесса, недоступность каталога или отказ планировщика.
02Внимание: запись «SSH подключается» — это положительный результат только для одного слоя. Не используйте её как доказательство восстановления CI.
Где именно рвётся цепочка Jenkins macOS Agent
Слой подключения: DNS, прокси и разрешённый маршрут
Выясните, кто инициирует соединение. При SSH-контроллер подключается к системному SSH удалённого Mac. При входящем варианте сам Agent устанавливает канал к контроллеру. WebSocket также имеет собственный маршрут через HTTP(S). Эти механизмы используют разные точки проверки.
Не смешивайте:
- системный Remote Login macOS;
- SSH-службу контроллера Jenkins;
- транспорт Jenkins Agent;
- обратное WebSocket-соединение.
Проверьте с той стороны, которая инициирует канал:
- Разрешается ли имя контроллера или узла через DNS.
- Не изменился ли адрес контроллера после миграции.
- Не требует ли маршрут прокси.
- Не блокирует ли межсетевой экран исходящий или входящий трафик.
- Не истёк ли сертификат, если используется защищённый WebSocket или HTTPS.
- Не изменились ли правила доступа после перезапуска сетевого оборудования.
Для системного SSH на Mac отдельно убедитесь, что включён Remote Login и разрешён нужный пользователь. Инструкция Apple по Remote Login относится именно к доступу по SSH, а не к Jenkins Agent.
После исправления не ограничивайтесь однократным успешным подключением. Считайте канал восстановленным, если:
- рукопожатие завершается без повторных ошибок;
- heartbeat сохраняется в течение наблюдаемого периода;
- контроллер видит Agent после собственного перезапуска;
- временный сетевой обрыв не требует ручного запуска процесса.
Слой процесса: Java, agent.jar и секрет
Если канал потенциально доступен, проверьте процесс на Mac. Выполняйте диагностику от имени фактического пользователя Agent, а не только из вашей административной SSH-сессии.
ps aux | grep -i '[a]gent'
pgrep -af 'java.*agent'
Команды выше показывают наличие процесса, но не объясняют причину завершения. Сохраните:
- командную строку запуска;
- путь к Java;
- путь к
agent.jar; - код выхода;
- стандартный вывод и стандартную ошибку;
- время последнего старта;
- пользователя и рабочий каталог.
Проверьте, не изменились ли параметры запуска после обновления Jenkins. Частая ошибка — считать, что старый файл Agent и старые параметры автоматически подходят новой конфигурации контроллера. Сопоставьте используемый способ запуска с текущей страницей узла и официальным руководством Jenkins по работе с Agent.
Версию Java нельзя фиксировать в статье навсегда. Требования зависят от линии Jenkins и конкретного выпуска. Перед заменой runtime откройте актуальную политику поддержки Java в Jenkins и проверьте совместимость именно с вашей версией контроллера.
Отдельно проверьте секрет. Используйте только временные обозначения вроде <AGENT_SECRET>, <CONTROLLER_URL> и <NODE_NAME>. Не копируйте секрет в журналы, тикеты или команды, которые попадут в историю shell. Если секрет был заменён, старый процесс может завершаться или отклоняться при повторной регистрации.
Порядок исправления:
- Остановите старый процесс, если он завис и не завершился штатно.
- Проверьте Java по официальной матрице поддержки.
- Получите актуальные параметры подключения из конфигурации узла.
- Запустите Agent вручную в тестовой сессии.
- Сохраните ошибку, если процесс снова завершится.
- Только после успешной проверки возвращайте автоматический запуск.
Постоянный запуск macOS нельзя подтверждать одной SSH-сессией
Ручной запуск после входа по SSH создаёт ложное ощущение исправности. Процесс может исчезнуть после выхода пользователя, разрыва VNC-сеанса, перезагрузки или смены контекста доступа к файлам.
Проверьте четыре свойства запуска:
- Agent работает под тем же пользователем, которому принадлежат рабочий каталог и ключи;
- права на каталог позволяют читать и создавать файлы;
- автоматический механизм запуска включается без интерактивного входа;
- журнал macOS фиксирует успешный старт, а не только попытку.
Если используется launchd, исследуйте фактический plist и журнал конкретной службы вашей системы. Не устанавливайте универсальный шаблон без проверки: область запуска, имя пользователя, пути, переменные окружения и ограничения могут различаться. Важно не наличие файла конфигурации, а результат запуска после выхода из SSH и после перезагрузки.
Минимальный сценарий проверки:
- Запустите Agent штатным способом.
- Убедитесь, что Jenkins видит узел.
- Выполните безопасное диагностическое задание.
- Завершите SSH-сеанс.
- Проверьте, что Agent остаётся подключённым.
- Перезапустите Mac.
- Не входите вручную через VNC или SSH.
- Убедитесь, что узел снова появился в Jenkins.
- Запустите тестовую задачу от имени пользователя Agent.
Сбой на шаге выхода из SSH указывает на контекст сессии. Сбой только после перезагрузки — на автоматический запуск, порядок старта сети или права. Если процесс запущен, но не подключается, вернитесь к сетевому слою.
04Онлайн-узел не всегда готов к Xcode CI
Статус «в сети» означает, что Jenkins поддерживает соединение. Он не гарантирует доступность рабочего каталога, метки, Xcode, симуляторов, сертификатов или профилей подписи.
Проверьте удалённый корневой каталог:
pwd
id
df -h
mkdir -p "$HOME/jenkins-diagnostic"
touch "$HOME/jenkins-diagnostic/write-test"
Затем сравните фактический путь и пользователя с настройками узла. Неправильный Remote Root Directory, заполненный диск или каталог без права записи могут проявиться как зависание задания, а не как отключение Agent.
Проверьте метки и исполнитель:
- метка задания должна совпадать с меткой узла;
- узел не должен быть ограничен режимом «только задачи с меткой», если pipeline её не задаёт;
- число исполнителей должно соответствовать безопасной параллельности;
- рабочие каталоги параллельных задач не должны конфликтовать;
- после очистки старого workspace права должны остаться у пользователя Agent.
Xcode, shell и подпись требуют разных проверок
Сначала зафиксируйте выбранный путь к Xcode:
xcode-select -p
xcodebuild -version
Путь, установленный в интерактивной оболочке администратора, может отличаться от пути в окружении Jenkins. Настройки Command Line Tools проверяйте по официальной документации Apple, а отсутствие компонентов — по руководству по установке Command Line Tools.
Не превращайте одну короткую shell-команду в критерий готовности. Используйте три независимых задания:
- обычная сборка тестового проекта;
- запуск тестов и сохранение результата;
- архивирование и подпись артефакта.
Для тестов учитывайте формат отчётов и результат самого xcodebuild, а не только отсутствие ошибки в оболочке. Документация Apple по запуску тестов и интерпретации результатов помогает определить, что считать успешным завершением.
Задание подписи запускайте от имени того же пользователя, что и Agent. Проверьте доступ к связке ключей, сертификату, профилю и нужной команде разработчика. Для архивирования сверяйтесь с материалами Apple о подписанном коде и распространении. Секреты и приватные ключи не выводите в лог.
05Пошаговая процедура восстановления без поспешного пересоздания
Первый шаг: сохраните доказательства
До перезапуска соберите снимок:
- карточку узла и причину offline;
- причину ожидания задания;
- последние строки лога контроллера;
- лог Agent;
ps,pgrep,id,pwdиdf;- версию Jenkins и Java;
- выбранный Launch Method;
- время последней успешной сборки.
Это позволяет отличить первичную причину от последствий перезапуска.
Второй шаг: подтвердите направление соединения
Проверьте DNS, маршрут, прокси, сертификаты и правила фильтрации с нужной стороны. Для SSH не подменяйте тест соединения с контроллером проверкой системного SSH Mac. Для WebSocket проверяйте URL контроллера, TLS и прокси отдельно.
Третий шаг: повторно запустите процесс в наблюдаемом режиме
Не запускайте его в фоне сразу. Сначала увидьте стандартную ошибку и код выхода. Если ручной запуск успешен, оставьте процесс под наблюдением и проверьте появление узла в контроллере. Затем переносите запуск в штатный механизм.
Четвёртый шаг: проверьте выход из сессии
Закройте SSH и VNC, не завершая сам Mac. Если Agent исчез, исправляйте контекст запуска. Не добавляйте ещё один фоновый скрипт поверх уже работающего механизма: несколько процессов могут создать конкуренцию и запутать журналы.
Пятый шаг: проверьте перезагрузку без оператора
Перезапустите Mac и не выполняйте ручной вход. Отметьте, появился ли узел после загрузки сети и службы автоматического старта. Если требуется ручной вход, текущая схема не соответствует роли постоянного CI-узла.
Шестой шаг: выполните три разных приёмочных задания
Проверяйте отдельно сборку, тесты и подпись. Для каждого сохраняйте пользователя, путь к Xcode, рабочий каталог и итоговый статус. Успешный echo или xcodebuild -version не заменяет производственную задачу.
Седьмой шаг: повторите условия сбоя
Смоделируйте контролируемый краткий сетевой обрыв, перезапуск контроллера и перезагрузку Mac. Если узел восстанавливается только после ручного вмешательства, он ещё не принят в эксплуатацию.
06Чек-лист приёмки удалённого Mac-узла
- [ ] Причина последнего отключения сохранена из интерфейса Jenkins и журналов.
- [ ] Направление соединения соответствует выбранному Launch Method.
- [ ] DNS, маршрут, прокси, сертификаты и сетевые правила проверены с нужной стороны.
- [ ] Процесс Agent запускается под ожидаемым пользователем.
- [ ] Java соответствует актуальной политике поддержки для установленной версии Jenkins.
- [ ] Секрет подключения не просрочен и не попал в журналы.
- [ ] Agent переживает завершение SSH-сессии.
- [ ] Agent автоматически возвращается после перезагрузки Mac.
- [ ]
Remote Root Directoryсуществует и доступен для записи. - [ ] Метка узла совпадает с ограничениями pipeline.
- [ ] Тестовая сборка Xcode завершается успешно.
- [ ] Тестовая задача создаёт корректный результат.
- [ ] Задание подписи использует нужного пользователя и ресурсы.
- [ ] После сетевого сбоя и перезапуска контроллера не требуется ручное вмешательство.
Три таблицы для выбора следующего действия
| Наблюдение | Где искать подтверждение | Вероятный слой | Первое действие |
|---|---|---|---|
| SSH к Mac работает, Jenkins показывает offline | Лог контроллера, лог Agent, карточка узла | Транспорт Jenkins или процесс Agent | Определить Launch Method и проверить процесс |
| Узел online, задание не стартует | Причина очереди, метки, исполнитель | Планировщик Jenkins | Исправить label или доступность executor |
| Agent запускается вручную, но исчезает после выхода | Журнал launchd, контекст пользователя | Сессия macOS | Проверить автоматический запуск и владельца |
| Узел online, workspace не создаётся | Remote Root Directory, df -h, права |
Файловая система | Исправить путь, место или права |
| Shell проходит, сборка Xcode завершается ошибкой | Лог xcodebuild, путь Xcode, keychain |
Toolchain или подпись | Выполнить отдельные build, test и sign jobs |
| Способ запуска | Когда подходит | Что проверять | Риск неправильного выбора |
|---|---|---|---|
| SSH | Контроллер стабильно достигает Mac по системному SSH | Remote Login, учётную запись, ключи и маршрут | SSH доступен, но Jenkins-канал настроен иначе |
| Входящее подключение | Mac может сам достичь контроллера | URL, секрет, исходящий доступ и постоянный процесс | Процесс не переживает перезагрузку |
| WebSocket | Нужен канал через разрешённый HTTP(S)-маршрут | TLS, прокси, адрес контроллера и логи рукопожатия | Прокси разрывает длительное соединение |
| Ручной запуск из SSH | Только краткая диагностика | Ошибку старта и фактическое окружение | Agent исчезает после выхода пользователя |
| Состояние после проверки | Решение | Почему |
|---|---|---|
| Единичный сбой процесса, окружение стабильно | Ремонтировать на месте | Причина локализована и воспроизводимость низкая |
| Повторные сетевые обрывы, но причина известна | Исправить маршрут или изолировать узел | Нельзя маскировать нестабильность перезапусками |
| Дрейф Java, Xcode, прав или подписи | Пересоздать узел по документированной схеме | Ручные исправления увеличивают непредсказуемость |
| Нужна независимость от одного Mac | Добавить отдельный удалённый Mac | Снижает единичную точку отказа |
| Нужны физические USB-устройства или локальный оператор | Рассмотреть собственное оборудование | Удалённая аренда не заменяет физический доступ |
Публичные сетевые сервисы Jenkins и их требования к доступу следует сверять с официальным описанием сервисов и портов Jenkins. Это особенно важно после изменения адреса контроллера, прокси или правил межсетевого экрана.
08Когда текущий узел лучше заменить
Не пересоздавайте Mac после первого offline-события. Сначала найдите доказательство. Но бесконечное добавление скриптов перезапуска тоже не является эксплуатационной стратегией.
Решение о замене оправдано, если:
- причина отключений меняется от запуска к запуску;
- Agent регулярно требует ручного входа;
- рабочий каталог повреждается или самопроизвольно меняет владельца;
- версии Java и Xcode расходятся с утверждённым образом;
- состояние подписи пропадает после перезагрузки;
- узел принимает shell-задачи, но нестабилен на сборке или тестах;
- восстановление зависит от конкретного администратора.
Перед пересозданием заблокируйте узел для новых задач. Сохраните логи и сведения об окружении. Выпишите необходимые метки, разрешённые задания, путь к Xcode и требования к подписи. Затем создайте чистый узел, проведите приёмку по чек-листу и только после этого удаляйте старую регистрацию.
Для нескольких независимых macOS CI-потоков полезно заранее определить, какие задания нельзя запускать параллельно. Один нестабильный узел не должен задерживать все релизы. Разделяйте сборку, тестирование и подпись, если их окружения или секреты требуют разной степени изоляции.
09Итоговая рекомендация для remote Mac в Jenkins
Jenkins macOS Agent отключается не только из-за недоступного компьютера. SSH может продолжать работать, пока Jenkins-транспорт, Java-процесс, сессия macOS, рабочий каталог или Xcode-контекст уже неисправны. Для краткого сбоя выбирайте локальное восстановление. Для повторяющегося отключения и дрейфа среды — изоляцию, пересоздание или отдельный удалённый Mac.
Если текущий вариант — личный Mac разработчика, он имеет несколько реальных недостатков: зависит от рабочего места и ручного входа, конкурирует с интерактивной работой, может неожиданно перезагрузиться из-за обновлений и не даёт независимого резервного узла. Собственная покупка Mac решает часть этих проблем, но требует первоначальных затрат, обслуживания и постоянного контроля доступности. При необходимости временного или выделенного CI-окружения аренда Mac через VpsMesh позволяет рассматривать отдельный удалённый Mac с полными правами как независимый узел: сначала проверьте требования к перезапуску, SSH или VNC и Xcode, затем выберите подходящий вариант аренды Mac. Это разумнее, чем продолжать поддерживать нестабильный рабочий компьютер в роли единственного Jenkins Agent.