Jenkins of Jenkinses: как устроена наша система непрерывной интеграции - Академия Selectel

Jenkins of Jenkinses: как устроена наша система непрерывной интеграции

Тирекс Тирекс Самый зубастый автор 27 сентября 2016

Компания «Селектел» предоставляет достаточное количество услуг. Над каждой из этих услуг трудятся люди — разрабатывают ПО, пишут код и управляют инфраструктурой. Для упрощения и ускорения процесса разработки и внедрения было решено сделать свою CI-лабораторию, которая бы реализовала CI и CD в рамках разработки, а также для DevOps-нужд. О том, что у нас получилось, мы подробно расскажем в этой статье.

Изображение записи

Компания «Селектел» предоставляет большое количество услуг. Над каждой из этих услуг трудятся люди — разрабатывают ПО, пишут код и управляют инфраструктурой. Для упрощения и ускорения процесса разработки и внедрения было решено сделать свою CI-лабораторию. В качестве инструмента непрерывной интеграции мы используем Jenkins.

Архитектура проекта была выбрана следующей: один Jenkins для каждого отдела и главный Jenkins, который позволяет менеджерам проектов выполнять действия по пересозданию Jenkins самостоятельно. Мы сразу же придумали для этой архитектуры название: Jenkins of Jenkinses.

Jenkins of Jenkinses

Благодаря такому подходу мы решаем проблемы изоляции ноды с Jenkins не только от конфликтов пакетов в системе, а также избегаем смешивания заданий (jobs) между отделами и сложности конфигурирования доступа к ним. При этом предоставляем возможность экстренно пересоздать ноду с Jenkins проекта без нашего участия. Такой подход является наиболее оптимальным и наиболее простым как для отделов, так и для администраторов, обслуживающих CI-host.

В итоге была настроена железная машина под управлением Ubuntu 15.04, впоследствии обновленная до 16.04, с расположенными на ней в LXC-контейнерах Jenkins’ами. Поверх на самом хосте был установлен nginx, через который осуществляется доступ в контейнеры по веб и главный Jenkins, который управляет обновлением заданий внутри других Jenkins и пересозданием контейнеров, в которых они запущены.

Предварительная конфигурация а также последующее управление осуществляется с помощью Ansible и Groovy, который нативно поддерживается в Jenkins. Через Ansible мы можем управлять контейнерами, устанавливать и конфигурировать дополнительные пакеты для каждого контейнера, устанавливать Jenkins, создавать специфичные окружения внутри сервера и деплоить Groovy-скрипты.

Через Groovy осуществляется конфигурирование Jenkins при старте. С помощью groovy мы настраиваем LDAP-авторизацию и project matrix-based security, в которой добавляем список групп и пользователей, которым разрешено выполнять какие-либо операции на этом Jenkins, конфигурируем выполнение shell через /bin/bash, а не установленный по умолчанию /bin/sh, устанавливаем перечень всех необходимых для работы плагинов и конфигурируем некоторые из них, — например, Jenkins Docker Plugin с необходимым подключением к локальному Docker Registry.

Задания Jenkins

Для управления заданиями был выбран инструмент Jenkins Job Builder(JJB), разработанный в рамках проекта OpenStack. Это весьма простой инструмент, который имеет весьма низкий порог вхождения, так как вся конфигурация описывается в формате YAML. Загрузка заданий осуществляется путем преобразования YAML в запросы к API Jenkins.

Но в любом проекте есть свои недостатки. Формат YAML, в котором предлагается описывать задания строго структурирован со стороны парсера от Jenkins Job Builder. Поэтому любое отклонение в отступах ведет к появлению ошибок. Также в процессе использования Jenkins Job Builder мы столкнулись с тем, что в продукте нет поддержки части необходимых нам плагинов и их поддержка не скоро предвидится.

Рассмотрим теперь поподробнее, как запускаются задания. В рамках главного Jenkins всё устроено так: на каждый проект есть два задания — обновление jenkins jobs и пересоздание jenkins-контейнера.

Обновление происходит путем запуска задания через веб-хук, который запускается после коммита в репозиторий с файлами Jenkins Job Builder. В самом задании используется локальный ini-файл с настройками, содержащими токен, имя пользователя и адрес Jenkins и ключ update для обновления.

pr-2926-2-2

Задание с переустановкой контейнера позволяет в случае сбоев пересоздать Jenkins для отдела с нуля. Upstream job’ом является задание на обновление.

В рамках Jenkins отдела все отдано на усмотрение администраторов и менеджеров проектов.
Отдельно, пожалуй, стоит остановиться на том, где же выполняются задания. Поскольку отдел имеет в своем распоряжении ноду, то может ставить какие угодно пакеты и окружения для сборки и использовать любые другие средства для сборки. Часть проектов решила не использовать сборку на стороне master jenkins’а, а добавила в работу jenkins slaves, выполнение которых осуществляется в Docker, где собираются npm-пакеты. Пока что большего распространения Docker не получил. Но это еще пока что.

Управление доступом и правами

pr-2926-3

Как писалось выше, для Jenkins мы используем LDAP-авторизацию и разграничение доступа через project matrix based security. Доступы Jenkins’ов на стейджинг- или продакшн- серверы осуществляются по паролям и отдельным пользователям, со строгим разграничением команд через sudo. Для менеджмента ключей используется Ansible, в котором содержится список серверов для каждого jenkins’а, который куда-либо подключается.

Менеджер проекта видит и может запускать все задания, а так же видит два задания, касающихся его проекта в главном Jenkins. Обычные администраторы/мейнтейнеры могут видеть в своих Jenkins все задания, но не могут запускать production deploy. А в главном Jenkins могут запускать только перезагрузку заданий в Jenkins их проекта. Если возникает необходимость выдать какие-либо права, то в задание добавляется еще один пользователь, который может выполнять какие-либо действия. Например, фронтенд-программистам нужно видеть часть заданий со сборками в других проектах. Для этого им дается возможность получить доступ на просмотр и чтение этих заданий.

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

Заключение

Резюмируя, можно сказать, что описанная архитектура хорошо справилась с решением запуска и работы CI/CD для всех проектов, так как ее планирование позволило нам избежать проблем с изоляцией, перемешиванием заданий между отделами, а также дало возможность более гибко заниматься не только деплоем новых Jenkins для проектов, но и сопровождать их.

За время использования накопилось некоторое количество проблем, которые хотелось бы решить в новой версии архитектуры. Например, отказ от виртуальных серверов, переход на полностью контейнеризованные среды сборки/стейджингового деплоя, отказ в пользу или же совмещение Jenkins Job Builder с Job DSL Plugin или же Jenkins File и т.д.

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