Berkshelf и зависимости Chef cookbook-ов

Привет, Хабрапользователи! b77fb03e6f010a70baade23b512604f3.pngЯ продолжаю свое погружение в пикантности automation-а и configuration management-а, параллельно пытаясь делится опытом с community.Речь пойдет опять об инструменте автоматизации разрешения зависимостей Сhef cookbook-ов, которым наша компания пользуется, а именно — Berkshelf.

А при чем тут Berkshelf? Chef имеет достаточно большое и развивающееся community, которое постоянно делает свой внос в создание и редактирование cookbook-ов. Все они хранятся на сайте Community, многие из них — очень часто используются нами.Однако есть одно «но» в нашей компании, связанное с редактированием community cookbook-ов. Правильный путь внесения каких-либо изменений в оные, связанных с спецификой инфраструктуры компании — это написание wrapper-ов, содержащих в себе изменения (например, переназначение атрибутов, подмена рецептов и пр.). Вкратце, процесс написания wrapper-а описан в этой статье.

Но, наличие правильного пути совсем не означает, что все последуют по нему. Именно поэтому в репозитории cookbook-ов нашей компании — оказалось много community cookbook-ов с недобросовестными правками. И настало время почистить репозиторий :)

План был следующим:

— выделить community cookbook-и в нашем репозитории; — оценить наличие и количество локальных правок (diff между одинаковыми версиями cookbook-ов); — вынести изменения во wrapper и включить в него вызов community cookbook-а или рецепта из него; — удалить community cookbook и внести его в зависимостях wrapper-а.

А что делать с «очищенными» community cookbook-ами? Как после удаления — они появятся «чистыми» на Chef Server-е?

Как раз тут на помощь и приходит Berkshelf.

Что такое Berkshelf и с чем его едят? Berkshelf является менеджером зависимостей для Chef cookbook-ов. Он написан на Ruby и имеет методы и API для взаимодействия с Chef Server.Установка Berkshelf происходит из Ruby Gems либо в рамках использования Chef DK.Мы используем Berkshelf версии 2.0, однако совсем недавно была выпущена версия 3.0, которая принесла некоторые изменения и «плюшки».Если вы решите использовать Ruby Gem — советую устанавливать его в рамках Ruby, установленного Chef Server-ом (исполняемые файлы находятся по пути — /opt/chef/embedded/bin/).Для взаимодействия с Chef Server-ом необходимо сконфигурировать Berkshelf, указывая ему адрес нашего сервера и сертификаты для авторизации на нем. Для конфигурации необходимо запустить следующую команду:

berks configure Конфигурационные файлы находятся по одному из нижеприведенных путей: $PWD/.berkshelf/config.json $PWD/berkshelf/config.json $PWD/berkshelf-config.json $PWD/config.json ~/.berkshelf/config.json После корректной установки Berkshelf-а — можно переходить к разрешению зависимостей cookbook-ов.Для этого, Berkshelf на первом этапе копирует cookbook-и и их зависимости на свои shelf-ы (локальный хранилище/репозиторий Berkshelf-а, по умолчанию — директория ~/.berkshelf/cookbooks/), а потом загружает все на Chef Server.Сразу появляются вопросы: «Откуда Berkshelf знает про зависимости?», «Что он делает для их разрешения? «Инструкции для Berkshelf содержатся в Berksfile, находящемся в корневой директории cookbook-а. Создается этот файл при помощи команды berks init в корневой директории.Содержимое этого файла описывает зависимости и источник для их разрешения. Пример такого файла: site: opscode metadata cookbook 'my-cookbook', (: path | : git | : github) cookbook 'my-book-2', ('> 1.0.0') Этот файл предписывается следующее: — учитывать зависимости из файла metadata.rb нашего cookbook-а и загружать их с Opscode Community сайта; — my-cookbook будет загружен по пути, указанному в скобках (это может быть либо локальный путь, либо ссылка на Git); — my-book-2 последней версии, высшей чем 1.0.0, будет загружен с Opscode Community сайта.

После этого можно запустить

berks install и дождаться успешного копирования зависимостей в локальное хранилище Berkshelf-а. В результате в директории хранилища должны оказаться все cookbook-и, упомянутые в поле depends файла metadata.rb, их зависимости (зависимости зависимостей) и два cookbook-а, упомянутых в Berksfile. Верифицировать результат можно командой berks shelf list Следующий шаг — запуск berks upload который загрузит все с локального хранилища на Chef Server. В результате (при условии, что Chef Server доступен и мы можем авторизоваться на нем, используя файлы сертификатов) — все зависимости будут разрешены. Результат загрузки можно проверить командой knife cookbook list вывод которой должен содержать новые cookbook-и.По сути, вот и весь процесс базового использования Berkshelf. Конечно, это еще не весь функционал, т.к. не упоминается взаимодействие Berkshelf с Vagrant, Chef Solo, Chef Client, а также некоторые новшества версии 3.0. Однако, я считаю этого достаточно для большинства.

Наша история использования Berkshelf Все было бы хорошо, если бы опять не одно «но» — Berkshelf не умеет работать циклически. Я очень удивлен, т.к. не нашел варианта, при котором он «нативно» мог учитывать вложенность директорий с cookbook-ами, эдакий nested-режим. Что я имею ввиду? Например, представим себе типичнейшую ситуацию, есть директория chef-repo, в которой вложена директория cookbooks, содержащая наши cookbook-и (./chef-repo/cookbooks/).В текущей версии Berkshelf — необходимо переходить в каждую из директорий cookbook-ов и выполнять в ней команды, связанные с Berkshelf. То есть — bash-скрипт, который бы это делал, не руками же, в самом деле… Это решение, но увы — не самое лучшее, откровенно говоря — «костыльное».На просторах Интернета была найдена статья, в которой используя Ruby-код, решался данный вопрос.Приведу код нашего «корневого» Berksfile, находящегося в директории ./chef-repo/: site: opscode

metadata

def dependencies (path) berks = »#{path}/Berksfile» instance_eval (File.read (berks)) if File.exists?(berks) end

Dir.glob ('./cookbooks/*').each do |path| dependencies path cookbook File.basename (path), : path => path end

cookbook 'gecode', '= 2.1.0' По сути, этот кусок кода собирается содержимое всех директорий cookbook-ов (их metadata.rb и Berksfile-ов) в «корневой» Berksfile.

Мы успешно применили предложенное решение и вуаля — все cookbook-и оказались на нашем Chef Server.Однако, в упомянутой статье не упоминалось одна большая особенность — формат Berksfile-ов наших cookbook-ов.Опытным образом было выяснено, что они должны выглядеть следующим образом:

group: name_of_cookbook do cookbook 'my-cookbook', (: path | : git | : github) cookbook 'my-book-2', ('> 1.0.0') end То есть, список cookbook-ов, которые должны соответствовать определенным условиям — например, версии или местоположению, заключенный в группу (для того, чтобы одинаковые зависимости разных cookbook-ов не вызывали конфликты типа multiple entries). Все остальные зависимости берутся из файла metadata.rb. Под катом — конкретный пример, дабы было нагляднее: Скрытый текст group: database do cookbook 'postgresql', '= 3.3.4' cookbook 'aws', : path => './cookbooks/aws' cookbook 'xfs', : path => './cookbooks/xfs' cookbook 'mysql', '= 4.1.2' end В итоге, для cookbook-а database будут загружены 4 cookbook-а, соответствующих определенным условиям, а также все остальные зависимости, упомянутые в metadata.rb, а также упомянутые зависимости зависимостей (уж простите за тавтологию).Все, что остается сделать после редактирования Berksfile-ов наших cookbook-ов — это запустить в директории ./chef-repo команды berks install && berks upload Вот такое вот решение, возможно не очень надежное или удобное —, но решение. Отработало с нашими репозиториями несколько раз успешно.Если кто-то сталкивался с данным вопросом и может поделится опытом — пишите комментарии или ЛС.Всем спасибо за внимание, до новых статей.

P.S. Коллега говорит, что Berkshelf v. 3.0 — поломан, так что — не советуем!

© Habrahabr.ru