Сборка Jenkins застряла в состоянии “прерывания” — невозможно завершить запущенное задание
У меня есть задание pipeline Jenkins, запущенное на агенте Ubuntu (подключенном к главному узлу). Проблема в том, что когда я пытаюсь прервать сборку, она никогда не останавливается. В консольном журнале постоянно отображается “Прерывание сборки” неопределенное время, а исполнитель остается занятым. Как принудительно завершить сборку Jenkins, застрявшую в состоянии прерывания?
Когда сборка Jenkins застревает в состоянии “прерывания”, вы можете принудительно завершить ее с помощью нескольких методов: сначала попробуйте ссылку “принудительно завершить выполняемые шаги” в пользовательском интерфейсе, затем используйте консоль скриптов с командами build.doStop() и build.doKill(), или вручную удалите каталог сборки. Для упорных сборок вам также может потребоваться проверить дампы потоков, завершить зависшие процессы на агенте или перезапустить агент Jenkins для полного решения проблемы застревания.
Содержание
- Понимание состояния застревания при прерывании
- Метод 1: Принудительное завершение через пользовательский интерфейс
- Метод 2: Команды консоли скриптов
- Метод 3: Ручное удаление каталога сборки
- Метод 4: Завершение на уровне процессов
- Предотвращение и лучшие практики
- Советы по устранению неполадок
Понимание состояния застревания при прерывании
Сборки Jenkins могут застревать в состоянии “прерывания” по нескольким причинам. Когда вы нажимаете кнопку “Прервать” на странице сборки, Jenkins отправляет сигнал для остановки выполняющихся процессов, но иногда процессы не реагируют должным образом или становятся “зомби”-процессами, которые продолжают работать несмотря на сигнал прерывания.
Общие причины застревания сборок при прерывании:
- Дeadlocked процессы в скрипте сборки
- Зависшие внешние приложения или сервисы
- Недостаточно прав для завершения процессов
- Проблемы с подключением агента
- Истощение ресурсов на машине агента
Согласно обсуждениям на Stack Overflow, это особенно характерно для pipeline-заданий, выполняющихся на агентах Ubuntu, где в консольном логе бесконечно отображается “Aborting build” без фактической остановки выполнения.
Метод 1: Принудительное завершение через пользовательский интерфейс
Начните с простейшего метода с использованием веб-интерфейса Jenkins, прежде чем переходить к более радикальным мерам.
Пошаговое завершение через пользовательский интерфейс:
- Первоначальная попытка прерывания: Нажмите красную кнопку “X” (Прервать) на странице сборки
- Подождите 30 секунд: После первоначальной попытки прерывания Jenkins должен предоставить дополнительные опции
- Найдите ссылку “принудительно завершить”: В выводе консоли должна появиться ссылка с текстом “Нажмите здесь, чтобы принудительно завершить выполняемые шаги”
- Нажмите первую ссылку: Это пытается остановить выполняемые шаги более агрессивно
- Проверьте наличие второй ссылки: Если первое завершение не сработало, должна появиться еще одна ссылка “Нажмите здесь, чтобы принудительно убить всю сборку”
- Нажмите вторую ссылку: Это выполняет жесткое завершение всей сборки
Важно: Как указано в документации CloudBees, если вы видите эти ссылки и нажимаете их, но сборка все равно не останавливается, вам потребуется перейти к более агрессивным методам.
Метод 2: Команды консоли скриптов
Если методы пользовательского интерфейса не работают, используйте Консоль скриптов Jenkins для принудительного завершения сборки программным способом.
Доступ к Консоли скриптов:
Перейдите по адресу http://ваш-адрес-jenkins/script для доступа к консоли скриптов Groovy.
Базовый скрипт завершения:
def jobName = "ваше-имя-задания"
def buildNumber = 123 // Замените на фактический номер сборки
def job = Jenkins.instance.getItemByFullName(jobName)
def build = job.getBuildByNumber(buildNumber)
// Сначала попытка корректной остановки
build.doStop()
// Если это не сработает, принудительное завершение
build.doKill()
Расширенный скрипт для нескольких застрявших сборок:
// Завершение всех выполняющихся сборок
Jenkins.instance.getAllItems(Job.class).findAll { it.isBuilding() }.each { job ->
def jobName = job.toString()
def val = jobName.split(/\[|\]/)
if(val.size() > 1) {
def actualJobName = val[1].trim()
def job = Jenkins.instance.getItemByFullName(actualJobName)
job.builds.each { build ->
if(build.isBuilding()) {
println "Остановка сборки ${build.fullDisplayName}"
build.doStop()
build.doKill()
}
}
}
}
Для Multibranch Pipeline:
def multibranchPipelineProjectName = "ваше-имя-multibranch-проекта"
Jenkins.instance.getItemByFullName(multibranchPipelineProjectName).getItems().each { repository ->
repository.getItems().each { branch ->
branch.builds.each { build ->
if (build.getResult().equals(null)) {
println "Завершение застрявшей сборки: ${build.fullDisplayName}"
build.doStop()
build.doKill()
}
}
}
}
Примечание: Как объяснено в документации Mirantis, метод
build.doStop()пытается выполнить корректное завершение, в то время какbuild.doKill()выполняет немедленное принудительное завершение.
Метод 3: Ручное удаление каталога сборки
Когда методы консоли скриптов не работают, ручное удаление каталога сборки может решить проблему.
Шаги для ручного удаления каталога:
-
Найдите расположение каталога сборки:
- Расположение по умолчанию:
$JENKINS_HOME/jobs/[имя-задания]/builds/[номер-сборки] - Для pipeline-заданий:
$JENKINS_HOME/jobs/[имя-задания]/builds/[номер-сборки]/workspace
- Расположение по умолчанию:
-
Остановите сервис Jenkins (необязательно, но рекомендуется):
bashsudo systemctl stop jenkins -
Переместите или удалите проблемный каталог сборки:
bash# Переместите каталог, чтобы предотвратить возобновление при перезапуске sudo mv $JENKINS_HOME/jobs/[имя-задания]/builds/[номер-сборки] /tmp/ # Или удалите полностью sudo rm -rf $JENKINS_HOME/jobs/[имя-задания]/builds/[номер-сборки] -
Перезапустите сервис Jenkins:
bashsudo systemctl start jenkins
Предупреждение: Как указано в документации CloudBees, этот метод можно использовать для предотвращения возобновления любой Pipeline-сборки при запуске Jenkins, но вы должны быть осторожны, чтобы не удалять каталоги сборок, которые все еще выполняются правильно.
Метод 4: Завершение на уровне процессов
Если методы Jenkins не работают, вам может потребоваться напрямую завершить базовые процессы на машине агента.
Поиск и завершение зависших процессов:
-
Подключитесь к машине агента Ubuntu через SSH
-
Найдите зависший процесс:
bash# Найдите процессы, связанные с Jenkins ps aux | grep jenkins # Найдите процессы по номеру сборки или имени задания ps aux | grep "ваш-номер-сборки" ps aux | grep "ваше-имя-задания" # Проверьте наличие зомби-процессов ps aux | grep Z -
Завершите группу процессов (более эффективно, чем завершение одного процесса):
bash# Найдите идентификатор процесса (PID) PID=$(pgrep -f "ваш-идентификатор-сборки") # Завершите всю группу процессов kill -TERM -$PID # Если это не сработает, принудительно завершите kill -KILL -$PID -
Для упорных зависших приложений:
bash# Завершите все процессы, связанные с зависшей сборкой pkill -f "идентификатор-сборки" # Используйте killall для более широкого соответствия killall -9 "имя-зависшего-приложения"
Расширенное управление процессами:
Согласно GitHub gist, вы можете создавать более надежные скрипты очистки процессов:
#!/bin/bash
set -euf -o pipefail
echo "ID группы процессов $$"
OK=0
trap 'if [[ "$OK" != "1" ]]; then echo "---"; echo "TRAP завершение, убиваем все процессы с родителем $$"; trap - SIGTERM && pkill -P $$; fi' SIGINT SIGTERM EXIT
SECONDS=0
echo "---"
"$@" &
PID=$!
set +e
wait $PID
CODE=$?
set -e
OK=1
echo "---"
echo "Процесс завершился с кодом $CODE, занял $SECONDS секунд"
exit $CODE
Предотвращение и лучшие практики
Чтобы избежать застревания сборок в состоянии прерывания, реализуйте следующие профилактические меры:
1. Реализуйте правильную очистку в скриптах:
pipeline {
agent any
stages {
stage('Сборка') {
steps {
script {
// Обеспечьте правильную очистку даже при прерывании
try {
// Ваши шаги сборки здесь
} catch (Exception e) {
// Код очистки
sh 'rm -rf /tmp/build-artifacts'
throw e
}
}
}
}
}
}
2. Используйте механизмы таймаута:
timeout(time: 30, unit: 'MINUTES') {
// Ваши шаги сборки, которые могут зависнуть
}
3. Реализуйте мониторинг процессов:
- Регулярно проверяйте дампы потоков:
http://yourserver/jenkins/threadDump - Мониторьте здоровье агента и использование ресурсов
- Настройте оповещения для застрявших сборок
4. Настройте правильную обработку сигналов:
Как отмечено в задаче Jenkins JIRA, убедитесь, что ваши скрипты правильно обрабатывают SIGTERM, чтобы они могли очистить ресурсы, когда Jenkins пытается их прервать.
5. Регулярное обслуживание:
- Периодически перезапускайте агенты Jenkins
- Мониторьте и очищайте временные артефакты сборки
- Держите Jenkins и плагины обновленными
Советы по устранению неполадок
При столкновении с застрявшими сборками следуйте этой систематическому подходу:
Шаги диагностики:
- Проверьте дамп потоков Jenkins: Перейдите по адресу
http://ваш-адрес-jenkins/threadDumpи найдите потоки исполнителей - Мониторьте ресурсы агента: Используйте
top,htopилиhtopдля проверки CPU, памяти и дискового пространства - Проверьте сетевое подключение: Убедитесь в связи мастер-агент
- Изучите логи: Проверьте логи как мастера Jenkins, так и агента на наличие сообщений об ошибках
Распространенные шаблоны ошибок:
- Проблемы с дисковым пространством: Сборки могут зависать при недостатке дискового пространства для временных файлов
- Таймауты сети: Сборки могут зависать из-за проблем с подключением
- Истощение ресурсов: Высокая загрузка CPU или памяти может вызывать зависание процессов
- Проблемы с правами доступа: Недостаточно прав для очистки артефактов сборки
Последовательность восстановления:
- Сначала попробуйте завершение через пользовательский интерфейс
- Если это не сработает, используйте команды консоли скриптов
- Если все еще застряло, попробуйте ручное завершение процессов на агенте
- В крайнем случае удалите каталоги сборок и перезапустите сервисы
- После восстановления проанализируйте корневую причину для предотвращения повторения
Совет эксперта: По словам опытных администраторов Jenkins, комбинация
build.doStop()за которой следуетbuild.doKill()в консоли скриптов является наиболее надежным методом для завершения застрявших сборок, так как она пытается как корректное, так и принудительное завершение последовательно.
Источники
- Официальная документация Jenkins - Прерывание сборки
- Stack Overflow - Как остановить неостановимый зомби-задание в Jenkins
- Stack Overflow - Сборка Jenkins застряла в состоянии “прерывания”
- Документация CloudBees - Устранение неполадок застрявшего Pipeline
- Документация Mirantis - Прервать зависшую сборку в Jenkins
- Goldfish Tips - Как убить застрявшую сборку Jenkins?
- GitHub Gist - Остановка и завершение застрявшей сборки Jenkins
- Задача Jenkins JIRA - проблема корректного завершения задания
Заключение
Принудительное завершение сборки Jenkins, застрявшей в состоянии “прерывания”, требует систематического подхода, начиная с методов на основе пользовательского интерфейса и переходя к более агрессивным техникам при необходимости. Всегда начинайте со ссылки “принудительно завершить выполняемые шаги” в веб-интерфейсе, затем переходите к командам консоли скриптов с использованием build.doStop() и build.doKill(). Для упорных проблем может потребоваться ручное удаление каталогов сборок или завершение процессов на уровне ОС. Чтобы предотвратить будущие случаи, реализуйте правильные механизмы таймаута, процедуры очистки в ваших скриптах сборки и регулярный мониторинг системы. Помните, что каждый метод несет риски, поэтому всегда создавайте резервные копии важных данных перед выполнением разрушительных операций и документируйте процесс устранения неполадок для будущих ссылок.