От любой системы, которую внедряем в проект, мы ждём стабильной работы. Jenkins не исключение. Когда мы выбираем его в качестве инструмента CI/CD, он начинает напрямую влиять на time to market приложения и, соответственно, на деньги, которые может заработать компания. В случае сбоя Jenkins мы получаем влияние не только на команду разработки, но и на бизнес. Чтобы минимизировать риски, необходимо правильно настроить инструмент. В статье рассказываем о best practice, которые должен знать каждый администратор Jenkins.

Статья основана на нашем вебинаре «Как сделать Jenkins стабильным и сэкономить время, деньги и нервы». На нём Кирилл Борисов, Infrastructure Engineer технологического центра Deutsche Bank, разбирал самые распространенные ошибки администрирования Jenkins, и рассказывал, как избежать проблем на ранних этапах

Медленный и «не отвечающий» Jenkins

Большая часть претензий к Jenkins заключается в том, что он медленный. А иногда перестает отвечать на вопросы, когда вы пытаетесь залогиниться.

Основные факторы, влияющие на работу Jenkins:

  • Garbage Collection. Поскольку Jenkins — это Java Application, его производительность во многом зависит от правильно настроенного Garbage Collection.

  • Polling. В Jenkins есть возможность запуска пайплайна по триггеру. Пайплайн опрашивает систему контроля версий по заданному интервалу и, если находит изменения в коде, запускает пайплайн. Триггер, настроенный на большом количестве пайплайнов, сильно влияет на производительность Jenkins. Оптимально здесь использовать webhook — вы можете настроить его на события по push в основную ветку или создать URL, на который будете отправлять запросы и по этому событию будут запускать Java.

  • Конфигурация и неправильные JVM-аргументы. Необходимо следовать best practice по по настройке Jenkins и быть внимательным, потому что на разных версиях Java аргументы выглядят по разному. 

  • Некорректные pipeline. Избегайте использования мастер ноды для исполнения пайплайнов. Её работа состоит в менеджменте ваших заданий, для всего остального есть агенты. Не забывайте, что весь groovy-код, который вы пишете в пайплайнах, они исполняют на мастере в любом случае. Старайтесь использовать утилиты в командной строке — URL или GG. Такие команды выполняются непосредственно на агентах и никак не влияют мастер. 

  • Медленная файловая система. У Jenkins нет выделенной базы данных. Конфигурация, история, описание задач — всё лежит на диске в JENKINS_HOME директории. Поэтому рекомендуется использовать более быстрые диски. Или использовать сетевое файловое хранилище NFS версии 3.0 или 4.1.

  • Плагины — то, что должно упростить работу с Jenkins, но с чем нужно быть осторожнее. Совет Капитана: используйте плагины только в том случае, когда без них совсем не обойтись. Если вы можете работать без них, отдайте предпочтение groovy-коду.

Мониторинг и метрики

Первое, о чём стоит задуматься после установки Jenkins, — это мониторинг. Его нужно настроить, чтобы вы понимали, как приложение чувствует себя здесь и сейчас, а не узнавали о сбоях из отзывов пользователей или от разработчиков. 

При настройке мониторинга важно учитывать, что существуют два типа метрик. Первый тип — макрометрики: Application Response Time, CPU Utilization, Memory Usage. Они на верхнем  показывают, что происходит, но не позволяют провести глубокое исследование. Понять, как чувствует себя Jenkins, помогут на микрометрики: Object Creation Rate, GC Latency, GC Throughput, Thread Count&State и Open File Descriptor.

Для отслеживания метрик вы можете использовать:

Сборка мусора — что это и почему важно для Jenkins? 

Для работы любого приложения требуется память. Однако память компьютера ограничена, поэтому важно очищать её о старых неиспользуемых данных. Так выглядит структура памяти Java:

У нас есть Native Memory — вся доступная память в системе.

Heap Size, которую в русскоязычном комьюнити прозвали «куча», — часть Native Memory. Это общее пространство для потоков приложения, где Java хранит все свои объекты. Размер этой области настраивается с помощью параметров в Xms на минимальные размеры, в Xmx на максимальные. 

Stack — место для хранения локальных переменных. Для каждого потока выделяется свой Stack.

Metaspace — метаданные. В этой части хранятся данные метакласса и статистические переменные. Важно помнить, что это пространство является общим для всех, поскольку Metaspace входит NativeMemory. Верхний предел объема памяти, используемый для Metaspace, можно выставить с помощью флага max metaspace size.

Что же такое мусор? Мусором считается объект, который больше не может быть достигнут по ссылке из какого-либо объекта, поскольку такой объект больше не используется в приложении. Соответственно, сборка мусора — процесс автоматического управления памятью, который выполняется специальным компонентом Garbage Collector.

Как работает Garbage Collector:

Для сборки мусора он используется процесс Mark&Sweep, который состоит из нескольких этапов. Первый этап — Mark. Garbage Collector сканирует все объекты и помечает живые — те, которые все еще используются в памяти. Далее программа останавливается — этот этап называется Stop the world. Затем идёт этап очистки — Sweeping. Объекты, которые не были отмечены на предыдущем шаге, удаляются из памяти. И последний этап — Compaction. На нем объекты, пережившие очистку перемещаются в единый непрерывный блок памяти. Это уменьшает фрагментацию Heap и позволяет быстрее размещать новые объекты. 

Как не стать заложником проблемы Out Of Memory и низкой пропускной способности

Не стоит игнорировать рекомендации, которые Jenkins предлагает для Java. Вот основные из них:

  • Минимальный размер Heap — -Xms = 2Gb, для production 4GB.

  • Максимальный размер Heap — -Xmx = 16 Gb. Часто возникает вопрос: почему именно 16, можем ли мы взять больше? Технически можем. Но стоит помнить, что при увеличении размера Heap, мы увеличиваем размер Metaspace. Плюс, чем б��льше максимальный размер Heap, тем дольше Garbage Collector чистит память. 

  • Тип Garbage Collection — -G1GC (по умолчанию ParallelGC). Не забывайте выставлять G1, потому что он помогает Jenkins: работает параллельно с приложением и используется, когда время отклика важнее пропускной способности. 

  • Включение логирования GC. Не забывайте включать логирование Garbage Collector, чтобы понимать, что с ним происходит. 

  • Опция HeapDumpOnOutOfMemoryError. Для автоматического снятия Dump при Out Of Memory.

Другие рекомендации:

Контроль изменений

Еще одна проблема, с которой можно столкнуться при больших инсталляциях, — контроль изменений. Когда у вас один большой Jenkins, который используется несколькими командами, зачастую возникают сложности в коммуникациях. Например, одна команда обновила плагин, не дождавшись подтверждения другой. Или команда информационной безопасности заблокировала порт на порты на firewall.  

Рекомендации:

  • Не делайте больше одного изменения за единицу времени. Тогда в случае возникшей проблемы вы всегда будете знать, что конкретно ее спровоцировало.

  • Наладьте коммуникацию между командами. Создайте подобие чейнджлога, а если у вас большой Jenkins — отдельную Wiki-страничку.

  • Используйте плагины, помогающие понять, какое изменение вызвало поломку. Плагин Audit Trail фиксирует все изменения Jenkins, которые совершают пользователи. Плагин Job Configuration Historyсохраняет изменения прошлых конфигураций пайплайнов и показывает, кто и что менял.

Резервное копирование

Еще одна проблема, с которой не хочется сталкиваться, — отсутствие бэкапов или их наличие в поврежденном виде. Важно не просто делать резервные копии, но и тестировать их на корректность. 

Для создания резервных копий вы можете использовать:

Обязательно проверяйте вашу резервную копию один-два раза в месяц в зависимости от критичности инстанса. 

Горизонтальное масштабирование 

И основная проблема: как понять, что Jenkins нужно масштабировать и нужно ли масштабировать мастер. Чтобы решите её, ответьте на два вопроса:

Есть ли у вас ресурсы для обслуживания нескольких контроллеров? Не забывайте, что Jenkins требует обновлений плагинов и ядра, регулярного резервного копирования. 

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

Рекомендации:

  • Старайтесь не использовать Freestyle задания. Если в какой-то момент у вас умрет мастер, все Freestyle задания перестанут выполняться. В то же время декларативные или скриптовые пайплайны продолжат выполняться даже при потере соединения агента с контроллером. 

  • Подумайте, насколько для вас важен быстрый запуск вашего экземпляра Jenkins. Чем больше заданий настроено, тем больше времени потребуется для загрузки Jenkins после обновления или сбоя. 

  • Используйте папки для организации заданий. Они ограничат количество заданий, которые необходимо отобразить сразу при запуске, поэтому старт контроллера будет быстрее. 

  • Следите метриками мониторингов файловой системы и дисковой подсистемы. Если понимаете, что диск не справляется с текущим количеством пайплайнов и джобов, настроенных на мастере, подумайте о его масштабировании.

  • Избегайте больших мастеров. Старайтесь дробить Jenkins по сегментам.

  • Не забывайте про правило «не больше 16Gb Heap». Чем больше памяти вы выделяете для Heap, тем дольше Garbage Collector придётся работать, и тем дольше процесс Stop The World.

Коротко о главном

Что вы можете сделать прямо сейчас:

Настроить ротацию джобов. На практике про это часто забывают, из-за чего получают огромное количество файлов на Jenkins Home. Обычно хватает двух-трёх недель хранения. Если же вам нужно хранить дольше, например, чтобы доказать, что какой-то пайплайн исполнялся год, рассмотрите вариант выгрузки ваших логов заданий в артефакт для долгосрочного хранения. Это отличный способ избежать переполнения мастера и сохранить все ваши задания. 

Избегать использования больших мастеров. Разделяйте Jenkins по сегментам, выбирайте JDK, а не JRE, потому что JDK предоставляет вам больше инструментов для работы с памятью и её траблшутинга. Если есть возможность использовать SSD-диски, старайтесь работать с NFC версии 3, 3.3, 4.1. 

Включить логирование Garbage Collector. В случае возникновения проблем вы всегда сможете понять, что происходит.

Не забывайте про Heap Size. По умолчанию в Java нет никаких опций — установите их. Это позволит вашему Jenkins работать более стабильно.

Следите за показателями макро- микрометрик. Вы должны понимать, как ведёт себя система, а не ждать, когда же придёт злой пользователь. 

Используйте best practice для написания пайплайнов. Pipeline Code — best practices от Jenkins, Top 10 — Top 10 Best Practice, Best Practice Overview 

И главная рекомендация — где возможно используйте bash-скрипты вместо groovy-методов, потому что они исполняются не на мастер ноде, а на агентах.

Для тех, кто хочет углубить знания в Jenkins

Кирилл Борисов — не только спикер наших вебинаров, но и автор курса «CI/CD с Jenkins». В нём он делится личным опытом работы с Jenkins, разбирает конкретные кейсы, а ещё помогает не совершить распространённых ошибок.

На курсе вы научитесь автоматизировать процесс интеграции и поставки, сможете ускорить цикл разработки и пройдёте путь от настройки первого плагина до Jenkins as code и внедрения в Kubernetes.

Посмотреть программу и записаться: https://slurm.club/3TotHtG