Pull to refresh
EPAM
Компания для карьерного и профессионального роста

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

EPAM corporate blog
Привет, Хабрапользователи!
Я продолжаю свое погружение в пикантности 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


В итоге, для cookbookdatabase будут загружены 4 cookbook-а, соответствующих определенным условиям, а также все остальные зависимости, упомянутые в metadata.rb, а также упомянутые зависимости зависимостей (уж простите за тавтологию).
Все, что остается сделать после редактирования Berksfile-ов наших cookbook-ов — это запустить в директории ./chef-repo команды
berks install && berks upload

Вот такое вот решение, возможно не очень надежное или удобное — но решение. Отработало с нашими репозиториями несколько раз успешно.
Если кто-то сталкивался с данным вопросом и может поделится опытом — пишите комментарии или ЛС.

Всем спасибо за внимание, до новых статей.

P.S. Коллега говорит, что Berkshelf v.3.0 — поломан, так что — не советуем!
Tags:system administrationchefberkshelfdependency managercookbookautomation
Hubs: EPAM corporate blog
Total votes 6: ↑4 and ↓2+2
Views7.8K

Information

Founded
1993
Location
США
Website
www.epam.com
Employees
over 10,000 employees
Registered
Representative
vesyolkinaolga