Jenkins and Docker HOWTO

2

 

Здарова щеглы! Сегодня будем проникаться Continuous Integration и популярным нынче её представителем – Jenkins (Не путать с Лироем) вкупе с docker.

Для начала разберёмся, что же это за неведома херня и зачем оно нам нужно?

Непрерывная интеграция (Continuous Integration (CI)) это, если не вдаваться в подробности, совокупность процессов разработки софта, коммитов в git/svn, сборки, тестирования, выкладки в продуктив. Есть много разных продуктов для осуществления CI в этой статье мы рассмотрим один из них – Jenkins .

А нужно это мне, быдлоадмину, человеку близкому к разработке чуть более чем никак, – just for lulz конечно же. Сразу стоит оговориться, предполагается, что наше ПО jenkins будет установлено непосредственно на сервера (виртуалки в нашем случае) и всё, что будет делать jenkins – будет происходить внутри docker контейнеров. Это важно понимать, потому что некоторые маньяки ещё и jenkins в docker ставят. Но это уже совсем другая история…

Плюсы jenkins:

  • Универсальность. Да, некоторые мои знакомые наркоманы используют его в роли configuration manager (i.e. Puppet). А почему бы и да?
  • Отсутствие БД. Все конфиги он хранит в виде файлов, что, в общем-то, не плохо.
  • Интеграция с docker. Вам больше не нужно засерать систему разномастными jdk/jre, maven, node.js разных версий и иже с ними.
  • Security. Благодаря докеру злоумышленник не завладеет никак вашим гипервизором.

Минусы Jenkins:

  • Java. Самый здоровенный минус. Java в вашей системе означает повышенное потребление ресурсов машины (особенно ОЗУ), здоровенная куча файлов (Одна jdk чего стоит), возможные проблемы обновления всего этого и т.п.
  • XML. Все конфиги в xml. Серьёзно? В 2к17 году при jinja2 (jinjava), yaml (yamlbeans), etc юзать xml?
  • Интеграция с docker. ЛОЛ да, это не ошибка. Вы пробовали когда-нибудь дебажить java стэк-трэйсы из докера? Учитывая, что для управления докером в pipeline свой язык/модуль, вам потребуется ещё дебажить и его, когда ваши тесты буду валиться один за одним в контейнере и при этом проходить “с руки”.
  • Unstable. Я настроил это всё и остановился на половине, через 15 дней я продолжил и обнаружил, что у модулей jenkins’а (а jenkins это прежде всего модульность) сменилось 100500 версий, при чём это багфиксы. Взгляните на jira jenkins’а, туда постят миллион человек в день и это просто жестятина потому что иногда хочется какой-то стабильности.

Установка



Как обычно, по доброй традиции, собирать всё это будем из говна и палок на виртуалках (Лично я использую virtualbox). Создаём 3 виртуальные машины jenkins-master, jenkins-slave-1 и jenkins-slave-2 . Машинные ресурсы примерно следующие на каждую машину – 2 cores / 2GB RAM / 10GB HDD / 2 Net. cards (1 – NAT, 2 – Vert net). На все машины ставим centos 7 и обновляем. Настраиваем сетевые интерфейсы таким образом, чтоб первый получал dhcp от вашего NAT, вторым будет внутренняя сеть со статичными адресами 100.64.0.1/24 (master), 100.64.0.2/24 (slave-1), 100.64.0.3/24 (slave-2).
Далее установим необходимые компоненты на master:

yum install epel-release
yum install wget mc nano sudo git
wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key
yum install java jenkins

и на slaves. Обратите внимание, что на slaves нам не нужно устанавливать jenkins

yum install epel-release
yum install wget mc nano sudo java git

однако потребуется создать пользователя jenkins

adduser jenkins -d /var/jenkins_home -G wheel

и установить ему какой-то пароль

passwd jenkins

Теперь нам нужен второй компонент ради которого эта статья – docker.

Шутка-минутка
Ехал докер через докер,
Видит докер в докер докер,
Сунул докер в докер докер,
Докер докер докер докер ^_^

Его мы ставим на мастера и на рабов. Укажем свежие репы для докера

cat >/etc/yum.repos.d/docker.repo <<-EOF
[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/centos/7
enabled=1
gpgcheck=1
gpgkey=https://yum.dockerproject.org/gpg
EOF

Установим

yum install docker-engine

Добавим в автозагрузку и обязательно дадим права дженкинсу работать с контейнерами добавив его в группу docker

systemctl enable docker
systemctl start docker

usermod -aG docker jenkins

И ребутаемся – /sbin/reboot
Наконец, после загрузки машин, проверим, что у нас всё получилось залогинившись под jenkins и запустив тестовый контейнер hello-world

su jenkins

docker run hello-world

Увидеть в ответ вы должны что-то вроде

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the 'hello-world' image from the Docker Hub.
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://cloud.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/engine/userguide/

Настройка



После всего что мы сделали, результатом должны стать три сервера с джавой, докером и Jenkins на мастере. Пришло время сказать мастеру, что у него есть рабы. Заходим через web-браузер на http://127.0.0.1:8080 предварительно пробросив этот порт в своей виртуальной машине. Если всё сделано правильно, вы увидите web-морду jenkins где необходимо ввести login/pass. Это сочетание можно найти в логах jenkins на мастер-ноде /var/log/jenkins/jenkins.log:

*************************************************************
*************************************************************
*************************************************************

Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:

dad1539aa27549bd8f312375c2bc7b69

This may also be found at: /var/lib/jenkins/secrets/initialAdminPassword

*************************************************************
*************************************************************
*************************************************************

Используем логин admin и пароль из файла (у меня он сгенерился как dad1539aa27549bd8f312375c2bc7b69), обязательно меняем его в Jenkins – Люди – admin

Следуем по пути Jenkins – Состояние сборщиков , жмякаем Новый узел в названии узла пишем jenkins-slave-1 выбираем снизу Permanent Agent и попадаем на страницу настройки ноды. Из важного:

  • в Корень удаленной ФС указываем /var/jenkins_home ,
  • Способ запуска меняем на Launch slave agents via SSH ,
  • если вы следовали данной инструкции, то в графе Host записываем 100.64.0.2 (адрес внутренней сети jenkins-slave-1),
  • в Credentials нажимаем Add и добавляем пользователя jenkins с тем паролем, который вы ему задали командой passwd на этапе настройки серверов.

Жмякаем save и смотрим логи в которых, если всё сделано правильно, вы увидите как он коннектится по ssh с мастера на слейв, устанавливает environments и копирует клиент Slave.jar (Это всё можно сделать вручную, но зачем?)
Идём по пути Jenkins – Настроить Jenkins – Global Tool Configuration сюда мы можем добавить необходимый нам софт (maven, docker, git etc) но мы его уже установили вручную. В принципе, если вы хотите, можете его ставить и через jenkins, но лично я предпочёл в этой статье сделать это руками.
Переходим в настройки мастера Jenkins – Настроить Jenkins – Конфигурирование системы тут нам нужно только в графе “Использование” указать “Only build jobs with label expressions …” что значит, что мастер будет выполнять только то, где метки мастера и джоба совпадают. Мастеру же мы меток назначать не будем никаких вообще, потому что мы хотим чтоб наш мастер управлял только логикой, вебой и рабами (Прям как мой начальник (шутка-минутка)) но не был вовлечён в процесс сборок. Остальные пункты для данной статьи не обязательны и вы можете настроить их по желанию.

Установим необходимые плагины/модули. Сделать это можно из Jenkins – Настроить Jenkins – Управление плагинами

Blue Ocean beta
Maven Integration plugin
Docker Pipeline
Pipeline: Groovy
Docker Commons Plugin

Они будут устанавливаться с зависимостями и часто бывает, что один зависит от другого. То есть возможно, у вас они уже будет установлены.

Использование



Хух, чёт я подзапарился уже писАть к этому моменту, а ведь это только азы, это то, что должен знать любой админ и это ещё пока ни разу не CI, о нём как раз в этом пункте.
Пришло время использовать наш дженкинс. Жмякаем Jenkins – Создать Item называем его как-нибудь (У меня это her) и выбираем тип Pipeline, жмём OK. Внизу страницы в Pipeline пишем

node {
   echo 'Hello World'
}

либо с помощью выпадающего окна справа (Это кусок groovy плагина которого мы ставили ранее) выбираем Hello World. Сохраняем и попадаем в меню нашего первого итема (у меня это her) где жмём слева “Собрать сейчас”. Там же, слева у нас появится #1 в истории сборок. Жмякаем по нему и выбираем Console Output где видим примерно следующее

Started by user admin
[Pipeline] node
Running on jenkins-slave-2 in /var/jenkins_home/workspace/her
[Pipeline] {
[Pipeline] echo
Hello World
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

Что всё это значит? Pipeline это некий “язык” который позволяет нам составлять сценарии для сборки/проверки/публикации/чего_угодно_ещё в наших проектах. При создании itema есть много типов проекта который можно указать, но на мой скромный взгляд, pipeline и multipipeline это самые полезные. В данном конкретном примере мы сказали нашему дженкинсу: – выбери любую ноду и выполни на ней “echo Hello World”. Далее мы видим в консольном выхлопе, как он выбирает jenkins-slave-2 создаёт на нём рабочую директорию нашего итема /var/jenkins_home/workspace/her и выполняет echo Hello world.

Теперь давайте усложним пример. Откройте настройки своего итема из меню дженкинса и поменяйте свой pipeline на

node {
   stage('Build') {
       docker.image('maven:3.3.3-jdk-8').inside {
           git 'https://github.com/jglick/simple-maven-project-with-tests.git'
           sh 'mvn clean package'
       }
     
   }
   stage('Results') {
      junit '**/target/surefire-reports/TEST-*.xml'
      archive 'target/*.jar'
   }
}

Выполните его. Как вы уже догадались, появится второй билд. Посмотрим его выхлоп Console Output. Этот билд у вас может провалиться, но не стОит отчаиваться, просто перезапустите его. Шанс того, что он закончится успешно или провалится – зависит от random’а (См. код). В этом примере мы говорим jenkins’у, чтоб он создал docker-контейнер maven версии 3.3.3-jdk-8 внутри которого бы скачал из git’а некий код и с помощью maven выполнил бы его. Далее, в случае успеха, сформировал бы отчёт. На самом деле это очень сложный процесс который очень просто описывается, и это гениально! Но всё это очень и очень сложно дебажить в случае неудачи 🙁
На странице билда своего итема вы можете найти много полезной информации. Если это успешный билд, там для вас автоматически соберутся артефакты (Это некие скомпилированные исходники того, что вы делали, результат билда), результаты тестов, которые записывает для вас junit, вывод консоли который вы уже видели.
Ранее, мы установили плагин blueocean – это приятный взгляду интерфейс. Посмотреть на него можно пройдя жмякнув вверху экрана Open Blue Ocean где вы увидите все свои pipeline и результаты сборок в красивом виде. Здесь очень удобно создавать pipeline для своих реп в git которым указывается дефолтное поведение “съипортировать всё что есть в проекте включая все ветки”, что не очень хорошо… далее в настройках через стандартное меню можно отключить чужие ветки и включить проверку коммитов. Можно даже компилить один и тот же проект до тех пор, пока все тесты не пройдут даже если в этом проекте не было ни одного нового коммита – такое поведение нужно для сбора статистики, потому что некоторые тесты меняют стутас на FAIL при, например, высоком времени ответа страницы с кодом 200.
Возможности запуска всего чего угодно в изолированном окружении через понятный веб-интерфейс потрясают. Язык pipeline очень простой и функциональный.

Послесловие



Взгляните на всё, что мы сделали. На самом деле это лишь установки и первичная настройка jenkins парка + пара банальных примеров pipeline, это даже не 10-ая часть всего, что с ним можно делать. Если вы читали это от начала и до конца и делали всё что тут написано, знайте – всё это бессмысленно TROLLFACE. Все git-сервисы давным давно уже предлагают совершенно бесплатно услугу CI которая настраивается прямо в вашем репозитории где абсолютно тот же самый jenkins делает всё что вы ему скажете с помощью Jenkinsfile. Мораль сей басни такова – если у вас есть 100500 разрабов и миллионы приватных реп, настраивайте jenkins; если вы ноунейм с одной репой в которую коммитите только вы один пару коммитов в месяц и весь проект состоит из двух-трёх файлов – нахер бы оно вам надо было, настройте прям в гите Integrations & services. В общем такие дела, ребята!

Leave a Reply

Your email address will not be published. Required fields are marked *