Эта статья — способ заглянуть в курс «Ansible: от первых шагов до большого проекта». Всеволод Севостьянов, Lead Engineer в Vene, отвечающий за пайплайны и deployment, показал, как настраивать Jenkins в связке с Ansible.
Первые шаги
Предположим что у нас есть система с установленным Jenkins и мы хотим привязать к ней IaaC в виде Ansible. После изначальной установки Jenkins, необходимо настроить связку с Ansible. Нужно договориться об условиях:
Jenkins установлен со стандартными плагинами;
Все пайплайны запускаются на машине, где установлен Jenkins (стандартный build agent), но для remote-агентов будет то же самое.
После установки Jenkins создаём новую сборочную задачу:
Вы можете создать Freestyle project — шаблон для Jenkins, в котором есть все этапы «Спулить код» → «Запустить работу», они позволяют с помощью шаблонов выбрать готовые пайплайны. Эта опция была добавлена в Jenkins чтобы повысить дружелюбность интерфейса к начинающим администраторам и автоматизаторам. Но мы выберем Pipeline.
Окно со свойствами проекта:
Здесь можно задать описание проекта, настроить как будут вести себя пайплайны. Во вкладке Build Triggers можно поставить параметры для автоматического запуска пайплайна, например запускать раз в день, или запускать, если появился новый коммит в определенной ветке Git.
Обратите внимание на поле ниже — Pipeline:
Jenkins, как и Gitlab, использует скрипт, который умеет выполнять консольные команды для запуска пайплайна по шагам. В отличие от Gitlab, Jenkins использует Groovy — полноценный язык программирования, который дает возможность тоньше кастомизировать работы и позволяет полноценно использовать программные конструкции для автоматизации. Но его сложнее освоить.
Итак, с помощью Pipeline достигнем целей:
Запустим Ansible и выведем его версию;
Скачаем Playbook с Github и запустим его;
Постучимся в другую машину изнутри Jenkins;
Используем специальный плагин Ansible для предыдущих трёх пунктов.
Запускаем Ansible и выводим его версию
Начнем с очень простой задачи — запустим Ansible в пайплайне и выведем его версию в консоль билда.
Пайплайны в Jenkins задаются очень простым путем: пишется Stage, аналогично стейджу в Gitlab, а внутри него перечисляются Steps. Все системы CI/CD основаны на одном принципе, дьявол именно в деталях.
Напишем свой Stage, назовем его Deploy и вызовем там версию Ansible.
|
Сохраняем пайплайн, выходим в главное окно проекта и нажимаем Build Now.
Если у вас на машине уже установлен Ansible, все пройдет успешно. Первый пайплайн готов.
Заглянем ему под капот
Нажмем на #1 внизу в Build history. Каждый пайплайн создает history, которую можно ограничить настройками билда, чтобы предотвратить засорение диска логами и артефактами сборки. По умолчанию ничего не удаляем, я рекомендую на период настройки пайплайнов не удалять билды, чтобы вернуться на любой шаг и посмотреть необходимую информацию.
Жмем на Console Output чтобы посмотреть вывод:
Видим пользователя, активировавшего билд, и настройки его ограничений. Внутри Jenkins по умолчанию вы очень ограничены во взаимодействии с системой, потому что можете убить ноду с Jenkins неправильным пайплайном.
Дальше — шаги пайплайна подсвеченные серым, а вывод консоли черным цветом. После отображения папки, где был запущен пайплайн, выводятся результаты работы нашей sh команды, которая покажет версию Ansible в привычном виде, как если бы мы запустили ее из консоли.
Запускаем Playbook с Github
Для изначального тестирования я создам очень простой плейбук:
|
|
|
|
|
|
|
|
|
|
|
Он располагается в github по адресу https://github.com/Nortsx/jenkinsansiblebook. Важно: перед началом работы склонируйте его в свой репозиторий, чтобы не зависеть от оригинала.
Модифицируем пайплайн:
|
Я скачиваю плейбук его через ssh, а не http.
Запускаем Pipeline и смотрим на результаты билда:
Jenkins провалился на первом этапе, не смог скачать исходники с Git, потому что не смог установить соединение с Github. Ответ на вопрос «как это пофиксить?» в тексте ошибки. Мы увидим эту ошибку, если соединимся по ssh с локальным ssh-agent, но при этом сервера нет в known_hosts. Добавим сервер Github для Jenkins.
Логинимся на машину с Jenkins, от лица пользователя Jenkins, если вы не переставляли пользователя для Jenkins и запускаем ssh github.com. На вопрос «Do you want to add gihutb.com to known hosts» жмем Y. Первая ошибка больше не будет мешать.
Запускаем пайплайн второй раз:
Ошибка в stderr поменялась на Permission Denied — для подключения по ssh к Github нужен ключ, который Github знает. Добавим этот ключ.
Убеждаемся, что плагин Credentials установлен: Dashboard → Manage Jenkins → Manage Plugins, если нет, то установим его.
Генерируем ключ для Github и добавляем его в аккаунт.
Запустим команду на машине с linux
|
После ответа на вопросы об имени ключа (укажите другое имя кроме id_rsa, если ваш стандартный ключ уже используется, поскольку его можно случайно перезаписать), защита паролем (выбираем «no») вы получите пару приватный/публичный ключ. Публичный ключ имеет расширение .pub после имени, приватный ключ его не имеет.
Важно! Старайтесь не светить свой приватный ключ, особенно если он используется где то для доступа к защищенным репозиториям, это вопрос безопасности.
После генерации ключей идем на github.com, кликаем на иконку профиля справа, Settings→SSH and GPG keys и попадаем на страницу добавления ssh ключей профиля.
Жмякаем New SSH Key
Копируем ПУБЛИЧНУЮ часть ключа и называем его произвольным именем
В Dashboard → Manage Jenkins → Credentials нажимаем на Global и Add Credentials.
В открывшемся окне выбираем SSH Username with private key и заполняем данные.
ID — идентификатор, уникальный для каждого credential, по которому вызывают их из пайплайна. Username — имя для вашего профиля Github. Private key → нажмите Enter Directly → Add и скопируйте значение из сгенерированного Приватного ключа.
После добавления ключ в списке Credentials.
Время использовать ключ в пайплайне:
|
Запускаем пайплайн и смотрим на вывод:
Сработало!
Посмотреть результаты запусков по шагам можно, нажав кнопку Pipeline Steps.
Она покажет аргументы запуска и позволит по клику на мониторчике изолированно посмотреть вывод по конкретному шагу, что может быть удобно для отладки.
Например вывод только запуска нашего Ansible playbook:
Переходим к следующей части.
Стучимся в другую машину изнутри Jenkins
Воспользуемся Ansible, чтобы постучаться в другие хосты.
В плейбук добавим файлы hosts и ansible.cfg
Hosts.ini
|
Я использую Vagrant, поэтому мои адреса принадлежат локальной сети.
|
|
После запуска видим провал на втором шаге:
Ключи не авторизованы на удалённой машине, поэтому с ней нельзя связаться.
Добавим ключи для авторизации на удаленной машине:
Я буду использовать тот же ключ, что для github. Возьмем публичную часть ключа и добавим в ~/.ssh/authorized_keys машины, к которой подключаемся через ansible.
Изменим пайплайн, чтобы Ansible мог использовать ключи авторизации.
|
И вуаля:
Для других переменных, которые не надо скрывать, мы можем использовать секцию variables.
Например:
|
Используем специальный плагин Ansible для всего сделанного выше
Снова идём в список плагинов в Manage Jenkins и ищем Ansible в списке Available плагинов.
Устанавливаем его.
При установке ставим галочку «Restart Jenkins», после установки Jenkins перезагрузится.
Теперь можно переписать пайплайн:
|
Вместо оборачивания в credentials, мы передали строчку в Id и вызвали специальный модуль, делающий за нас работу. Это сравнимо с использованием, например command или shell в Ansible, когда можно использовать специальный модуль, упрощающий и контролирующий работу, вместо «голых» вызовов консоли.
Плагин умеет больше, чем простой запуск плейбука, сильно упрощает пайплайны и саму жизнь.
Комментарии (16)
Odmino
28.10.2021 12:15После установки Jenkins создаём новую build-работу:
Простите, может и придраться решил, но звучит buld-работу ну очень уж криво
SvetaUlyanchenko Автор
28.10.2021 14:02+1Изменила на «создаем новую сборочную задачу»
saboteur_kiev
30.10.2021 01:53В дженкинсе вроде есть вполне устоявшиеся термины - freestyle project/job и pipeline
Worky
29.10.2021 01:13Ага! Значит не я один использую связку официанта+анзибл!! Прочитав статью не понял одного - а зачем вообще писать многоходовочки в официанте? зачем развивать пайплайнинг официанта, если все то же самое можно анзиблом сделать?
Я у себя просто вызываю анзибл с нужным плейбуком по изменениям в гите, которые проверяет официант (даже веб хук лень было настраивать для связки гити+официант). Авторизация по ключам, права рута у анзибла.
ИМХО, время официанта уходит, а анзибл настолько нужный инструмент, что лучше его изучить подробнее для админа.
SvetaUlyanchenko Автор
29.10.2021 17:28Привет! Здесь вопрос в разделении обязанностей: ансибл, например, не может подготовить систему, потом собрать приложение и залить его в эту систему. А вот дженкинс может, таким образом первый шаг ансибл, второй — какой-нибудь пайплайн дженкинс, третий — снова ансибл. Ничего страшного в этом нет, у официанта и ансибла немного разный класс задач.
Worky
30.10.2021 16:32Как это не может?!?!?
Все ансибл может и делает это в моем хозяйстве: подготавливает систему, собирает приложение и переносит в целевую систему. Причем файл с нужными для заливки хостами я кладу прямо в гит, чтобы разраб мог управлять на какой сервак залить обнову, а куда не надо.
Я согласен, что официант и ансибл имеют разные функции, но я больше отдаю функций ансиблу, чем официанту, так как думаю, что для админа ансибл углубленно знать полезнее, чем официанта.
unseriously
29.10.2021 10:08Полезно, спасибо.
Позвольте немного оффтопа: не подскажите ли, как слать логи из Console Output (Jenkins) в Телеграм? У дженкинса есть плагин для телеграма (https://plugins.jenkins.io/telegram-notifications/), но умеет слать только SUCCESS или FAILURE в результате сборки + умеет добавлять кастомное сообщение если сборка успешна. А вот бы как еще получать в сообщении строку с ошибкой если билд не прошел?
MSigillite
Довольно интересно, спасибо! Но сразу возникает вопрос, a как в данном случае повышать привелегии?
Например у меня в ansible.cfg сейчас вот так:
vanyas
Делать sudo без пароля для пользователя, под которым идет ансибл
MSigillite
sudo без пароля? Такой вариант в принципе не рассматривается из соображений безопасности.
saboteur_kiev
Тогда никак.
пароль на sudo нужно ставить для интерактивных пользователей, которые могут внезапно пойти пить чай, забыв залочить свою консоль. Или могут свой пароль оставить в паблике.
А для ansible можно сделать отдельного пользователя без пароля, доступ к которому идет по ssh ключам и соответственно ему можно настроить выполнение команд через sudo без пароля, чтобы он мог автоматически администрировать ваши ресурсы.
vainkop
Довольно таки legacy stack решения для которого есть в первых строках любого поиска :)
ansible_become_pass + ansible vault и не слушайте этих судобезпарольщиков
MSigillite
Спасибо, вот то что надо прям! Хоть и знаком с ansible vault но как-то не додумался что его и в таком качестве можно использовать. Век живи век учись :)
ggo
да, но появляется пароль на ansible vault ;) у-а-а-ха-ха-ха
SvetaUlyanchenko Автор
Здравствуйте! Авторизоваться через ключи, или хранить пароли в секретных переменных Jenkins, из CI/CD пайплайнов интерактивный ввод не делают:)