НейроАгент

Полное руководство: Принудительное завершение зависших сборок Jenkins

Узнайте, как принудительно завершать сборки Jenkins, застрявшие в состоянии прерывания, с помощью нашего подробного руководства. Изучите несколько методов: от завершения через пользовательский интерфейс до команд консоли скриптов и решений на уровне процессов. Быстро верните вашу среду Jenkins в нормальное состояние!

Сборка Jenkins застряла в состоянии “прерывания” — невозможно завершить запущенное задание

У меня есть задание pipeline Jenkins, запущенное на агенте Ubuntu (подключенном к главному узлу). Проблема в том, что когда я пытаюсь прервать сборку, она никогда не останавливается. В консольном журнале постоянно отображается “Прерывание сборки” неопределенное время, а исполнитель остается занятым. Как принудительно завершить сборку Jenkins, застрявшую в состоянии прерывания?

НейроАгент

Когда сборка Jenkins застревает в состоянии “прерывания”, вы можете принудительно завершить ее с помощью нескольких методов: сначала попробуйте ссылку “принудительно завершить выполняемые шаги” в пользовательском интерфейсе, затем используйте консоль скриптов с командами build.doStop() и build.doKill(), или вручную удалите каталог сборки. Для упорных сборок вам также может потребоваться проверить дампы потоков, завершить зависшие процессы на агенте или перезапустить агент Jenkins для полного решения проблемы застревания.

Содержание

Понимание состояния застревания при прерывании

Сборки Jenkins могут застревать в состоянии “прерывания” по нескольким причинам. Когда вы нажимаете кнопку “Прервать” на странице сборки, Jenkins отправляет сигнал для остановки выполняющихся процессов, но иногда процессы не реагируют должным образом или становятся “зомби”-процессами, которые продолжают работать несмотря на сигнал прерывания.

Общие причины застревания сборок при прерывании:

  • Дeadlocked процессы в скрипте сборки
  • Зависшие внешние приложения или сервисы
  • Недостаточно прав для завершения процессов
  • Проблемы с подключением агента
  • Истощение ресурсов на машине агента

Согласно обсуждениям на Stack Overflow, это особенно характерно для pipeline-заданий, выполняющихся на агентах Ubuntu, где в консольном логе бесконечно отображается “Aborting build” без фактической остановки выполнения.


Метод 1: Принудительное завершение через пользовательский интерфейс

Начните с простейшего метода с использованием веб-интерфейса Jenkins, прежде чем переходить к более радикальным мерам.

Пошаговое завершение через пользовательский интерфейс:

  1. Первоначальная попытка прерывания: Нажмите красную кнопку “X” (Прервать) на странице сборки
  2. Подождите 30 секунд: После первоначальной попытки прерывания Jenkins должен предоставить дополнительные опции
  3. Найдите ссылку “принудительно завершить”: В выводе консоли должна появиться ссылка с текстом “Нажмите здесь, чтобы принудительно завершить выполняемые шаги”
  4. Нажмите первую ссылку: Это пытается остановить выполняемые шаги более агрессивно
  5. Проверьте наличие второй ссылки: Если первое завершение не сработало, должна появиться еще одна ссылка “Нажмите здесь, чтобы принудительно убить всю сборку”
  6. Нажмите вторую ссылку: Это выполняет жесткое завершение всей сборки

Важно: Как указано в документации CloudBees, если вы видите эти ссылки и нажимаете их, но сборка все равно не останавливается, вам потребуется перейти к более агрессивным методам.


Метод 2: Команды консоли скриптов

Если методы пользовательского интерфейса не работают, используйте Консоль скриптов Jenkins для принудительного завершения сборки программным способом.

Доступ к Консоли скриптов:
Перейдите по адресу http://ваш-адрес-jenkins/script для доступа к консоли скриптов Groovy.

Базовый скрипт завершения:

groovy
def jobName = "ваше-имя-задания"
def buildNumber = 123 // Замените на фактический номер сборки

def job = Jenkins.instance.getItemByFullName(jobName)
def build = job.getBuildByNumber(buildNumber)

// Сначала попытка корректной остановки
build.doStop()

// Если это не сработает, принудительное завершение
build.doKill()

Расширенный скрипт для нескольких застрявших сборок:

groovy
// Завершение всех выполняющихся сборок
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:

groovy
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: Ручное удаление каталога сборки

Когда методы консоли скриптов не работают, ручное удаление каталога сборки может решить проблему.

Шаги для ручного удаления каталога:

  1. Найдите расположение каталога сборки:

    • Расположение по умолчанию: $JENKINS_HOME/jobs/[имя-задания]/builds/[номер-сборки]
    • Для pipeline-заданий: $JENKINS_HOME/jobs/[имя-задания]/builds/[номер-сборки]/workspace
  2. Остановите сервис Jenkins (необязательно, но рекомендуется):

    bash
    sudo systemctl stop jenkins
    
  3. Переместите или удалите проблемный каталог сборки:

    bash
    # Переместите каталог, чтобы предотвратить возобновление при перезапуске
    sudo mv $JENKINS_HOME/jobs/[имя-задания]/builds/[номер-сборки] /tmp/
    
    # Или удалите полностью
    sudo rm -rf $JENKINS_HOME/jobs/[имя-задания]/builds/[номер-сборки]
    
  4. Перезапустите сервис Jenkins:

    bash
    sudo systemctl start jenkins
    

Предупреждение: Как указано в документации CloudBees, этот метод можно использовать для предотвращения возобновления любой Pipeline-сборки при запуске Jenkins, но вы должны быть осторожны, чтобы не удалять каталоги сборок, которые все еще выполняются правильно.


Метод 4: Завершение на уровне процессов

Если методы Jenkins не работают, вам может потребоваться напрямую завершить базовые процессы на машине агента.

Поиск и завершение зависших процессов:

  1. Подключитесь к машине агента Ubuntu через SSH

  2. Найдите зависший процесс:

    bash
    # Найдите процессы, связанные с Jenkins
    ps aux | grep jenkins
    
    # Найдите процессы по номеру сборки или имени задания
    ps aux | grep "ваш-номер-сборки"
    ps aux | grep "ваше-имя-задания"
    
    # Проверьте наличие зомби-процессов
    ps aux | grep Z
    
  3. Завершите группу процессов (более эффективно, чем завершение одного процесса):

    bash
    # Найдите идентификатор процесса (PID)
    PID=$(pgrep -f "ваш-идентификатор-сборки")
    
    # Завершите всю группу процессов
    kill -TERM -$PID
    
    # Если это не сработает, принудительно завершите
    kill -KILL -$PID
    
  4. Для упорных зависших приложений:

    bash
    # Завершите все процессы, связанные с зависшей сборкой
    pkill -f "идентификатор-сборки"
    
    # Используйте killall для более широкого соответствия
    killall -9 "имя-зависшего-приложения"
    

Расширенное управление процессами:
Согласно GitHub gist, вы можете создавать более надежные скрипты очистки процессов:

bash
#!/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. Реализуйте правильную очистку в скриптах:

groovy
pipeline {
    agent any
    stages {
        stage('Сборка') {
            steps {
                script {
                    // Обеспечьте правильную очистку даже при прерывании
                    try {
                        // Ваши шаги сборки здесь
                    } catch (Exception e) {
                        // Код очистки
                        sh 'rm -rf /tmp/build-artifacts'
                        throw e
                    }
                }
            }
        }
    }
}

2. Используйте механизмы таймаута:

groovy
timeout(time: 30, unit: 'MINUTES') {
    // Ваши шаги сборки, которые могут зависнуть
}

3. Реализуйте мониторинг процессов:

  • Регулярно проверяйте дампы потоков: http://yourserver/jenkins/threadDump
  • Мониторьте здоровье агента и использование ресурсов
  • Настройте оповещения для застрявших сборок

4. Настройте правильную обработку сигналов:
Как отмечено в задаче Jenkins JIRA, убедитесь, что ваши скрипты правильно обрабатывают SIGTERM, чтобы они могли очистить ресурсы, когда Jenkins пытается их прервать.

5. Регулярное обслуживание:

  • Периодически перезапускайте агенты Jenkins
  • Мониторьте и очищайте временные артефакты сборки
  • Держите Jenkins и плагины обновленными

Советы по устранению неполадок

При столкновении с застрявшими сборками следуйте этой систематическому подходу:

Шаги диагностики:

  1. Проверьте дамп потоков Jenkins: Перейдите по адресу http://ваш-адрес-jenkins/threadDump и найдите потоки исполнителей
  2. Мониторьте ресурсы агента: Используйте top, htop или htop для проверки CPU, памяти и дискового пространства
  3. Проверьте сетевое подключение: Убедитесь в связи мастер-агент
  4. Изучите логи: Проверьте логи как мастера Jenkins, так и агента на наличие сообщений об ошибках

Распространенные шаблоны ошибок:

  • Проблемы с дисковым пространством: Сборки могут зависать при недостатке дискового пространства для временных файлов
  • Таймауты сети: Сборки могут зависать из-за проблем с подключением
  • Истощение ресурсов: Высокая загрузка CPU или памяти может вызывать зависание процессов
  • Проблемы с правами доступа: Недостаточно прав для очистки артефактов сборки

Последовательность восстановления:

  1. Сначала попробуйте завершение через пользовательский интерфейс
  2. Если это не сработает, используйте команды консоли скриптов
  3. Если все еще застряло, попробуйте ручное завершение процессов на агенте
  4. В крайнем случае удалите каталоги сборок и перезапустите сервисы
  5. После восстановления проанализируйте корневую причину для предотвращения повторения

Совет эксперта: По словам опытных администраторов Jenkins, комбинация build.doStop() за которой следует build.doKill() в консоли скриптов является наиболее надежным методом для завершения застрявших сборок, так как она пытается как корректное, так и принудительное завершение последовательно.

Источники

  1. Официальная документация Jenkins - Прерывание сборки
  2. Stack Overflow - Как остановить неостановимый зомби-задание в Jenkins
  3. Stack Overflow - Сборка Jenkins застряла в состоянии “прерывания”
  4. Документация CloudBees - Устранение неполадок застрявшего Pipeline
  5. Документация Mirantis - Прервать зависшую сборку в Jenkins
  6. Goldfish Tips - Как убить застрявшую сборку Jenkins?
  7. GitHub Gist - Остановка и завершение застрявшей сборки Jenkins
  8. Задача Jenkins JIRA - проблема корректного завершения задания

Заключение

Принудительное завершение сборки Jenkins, застрявшей в состоянии “прерывания”, требует систематического подхода, начиная с методов на основе пользовательского интерфейса и переходя к более агрессивным техникам при необходимости. Всегда начинайте со ссылки “принудительно завершить выполняемые шаги” в веб-интерфейсе, затем переходите к командам консоли скриптов с использованием build.doStop() и build.doKill(). Для упорных проблем может потребоваться ручное удаление каталогов сборок или завершение процессов на уровне ОС. Чтобы предотвратить будущие случаи, реализуйте правильные механизмы таймаута, процедуры очистки в ваших скриптах сборки и регулярный мониторинг системы. Помните, что каждый метод несет риски, поэтому всегда создавайте резервные копии важных данных перед выполнением разрушительных операций и документируйте процесс устранения неполадок для будущих ссылок.