Chef за 21 день. Часть вторая. Создание и использование cookbook

  • Tutorial
Привет-привет, хабраюзер! Все еще с нами? CHEF – это интересно! Продолжим наш вояж к мастерству воина-автоматизатора, который начался в первой части данной статьи. В этой статье речь пойдет о первом опыте написания cookbook-а, о рецептах, атрибутах и шаблонах.

Прежде чем идти дальше, маленькое отступление по поводу инфраструктуры. В дальнейшем нам понадобиться пара компьютеров или виртуальных машин. Конечно же, есть VirtualBox, есть Vagrant, но я настоятельно советую использовать Amazon Web Services (AWS). Основная причина – AWS повсеместно используется разными компаниями, и знакомство с ним – дополнительный бонус Вам же. Есть бесплатные образы на нем, которые каждый может использовать. Существует большое количество разных сервисов и инструментов, которые предлагает Amazon. Некоторые из них — крайне актуальны. Я считаю, что данный опыт — must-have experience.

Шаг 5. Добро пожаловать на кухню, детка



Добро пожаловать на кухню! В наших руках находится самый главный и незаменимый инструмент – knife!
Что мы будем готовить? Конечно же наш первый рецепт, и дабы не забыть его и использовать его в будущем – запишем его в наш cookbook. Именно в этом нам поможет knife, который умеет создавать cookbook-и. Конечно же можно воссоздать структуру cookbook-а вручную, но зачем? Лучше познакомиться с корректной структурой стандартного cookbook-а.
В создании нам поможет директива knife cookbook create. Она создаст в директории /cookbooks (указать ее местоположение можно указать в файле конфигурации knife.rb) папку с нашим первым cookbook-ом. Давайте ознакомимся с основным содержимым данной папки.

  • Директория /attributes содержит в себе файлы, с описанием атрибутов cookbook-а, которые могут быть использованы на узле для перезаписи значения тех или иных дефолтных значений узла. Это могут быть переменные, содержащие в себе пути к рабочим директориям, номера сетевых портов для сервисов, какие-либо специфические метки данного узла (например, его роль в рабочей среде). Самое главное при использовании атрибутов – понимание как их применить посредством рецепта. Как же CHEF получает значения стандартных атрибутов? У него существует инструмент, называемый ohai – коллектор атрибутов системы, используемых для CHEF. Эти атрибуты не являются системными переменными, Вы вряд ли увидите такие названия атрибутов в Вашей ОС – это переменные, с логически понятными названиями, такими как node[“platform”], которая хранит название ОС узла, или node[“fqdn”] – хранящая полное доменное имя узла. Если Вы хотите вносить изменения в текущую конфигурацию того или иного сервиса/ПО – необходимо использовать именно те названия атрибутов, которые предоставляет ohai. Не менее важным свойством атрибутов является идентификация узла – назначение упомянутых «меток». Приведу пример из практики.
    Необходимо было создать группу виртуальных машин (chef-клиентов), связать их с Chef-сервером и раздать им cookbook-и в соответствии с их ролью в этой группе (master или slave). На этапе регистрации узлов на Chef-сервере неизвестно, какой узел является master, а какой – slave. Что делать, не руками же назначать каждому? Решилось все просто до невозможности. Каждый узел получал, в зависимости от своего назначения, атрибут env_role = master или slave, который был доступен Chef-серверу. Сервер, в свою очередь, по всем зарегистрированным на нем узлам, проводил поиск по данному атрибуту и в зависимости от значения – раздавал cookbook-и (посредством ролей, о которых мы поговорим в дальнейшем).
  • Директория /files – содержит в себе набор файлов, которые будут использованы для дистрибуции на узлы. Иными словами, если надо генерировать на узле файл со статическим содержимым (подразумевается, что содержимое файла не меняется в процессе использования оного) – это именно та директория, куда Вы поместите файлы. Далее, в рецепте, ресурс cookbook_file инициализирует использование Вашего файла. Стоит заметить, что имя данного ресурса указывает на абсолютный путь расположения файла на узле, так что будьте внимательны при указании имени. Для того, чтобы указать исходный файл – используется свойство ресурса под названием source, в котором указывается имя исходного файла, размещенного в директории /files. Также дополнительно можно указывать права доступа к файлам на узлах, пользователя и группу пользователей, «владеющих» данными файлами.
    Еще одним интересным свойством обладает имя файла. Для него существуют шаблоны, согласно которым специфический файл может быть передан конкретному узлу (используя FQDN), использован на конкретной платформе с конкретной текущей версией. Пример – файл с именем ubuntu-12.04 будет передан только узлам с ОС Ubuntu версии 12.04.
  • Директория /recipies – фундаментальная директория нашего cookbook-а, директория с рецептами. Это наши рецепты. Именно тут определяется что и как мы будем конфигурировать. Файл рецепта – это Ruby-файл, в котором, очевидно, используется синтаксис языка Ruby (кэп тут!) В зависимости от сложности задачи – может содержать в себе описание функционала и коллекции ресурсов (для простых задач) либо же коллекции ресурсов и вызовы провайдеров (о них мы поговорим ниже). В рецепте можно вызывать другие рецепты, выстраивать зависимости от других рецептов, помещать блоки скриптов для конечных узлов (например, bash или powershell команды) и использовать многие другие возможности, доступные языку Ruby. Стоит запомнить, что выполнение кода происходит именно в том порядке, который указан в рецепте. В итоге, в наших руках достаточно массивные возможности, ограниченные нашим знанием языка Ruby и его возможностями.
  • Директория /templates – содержит шаблоны ресурсов, которые могут быть использованы в рецепте. Шаблоны описываются в формате Embedded Ruby, имеют расширение .erb и описывают динамический контент, который генерируется на базе переменных, логики или же простого текста. Далее ресурс шаблон объявляется в ресурсе. Минимальный вариант объявления выглядит следующим образом:

    template “/path/to/file/on/our/node.cmd” do
         source “node.erb”
    end


    Также, есть возможность задать, например, права доступа, владельца и группу владельцев этого файла. В этом конкретном случае на узле создастся файл cmd с указанным абсолютным путем, шаблоном которого является файл node.erb. Этот шаблон может быть набором команд, которые необходимо запустить на узле через командную строку. А может также содержать какие-то переменные и логику. Переменные в шаблоне могут быть, например, атрибутами Вашего cookbook-а, придавая шаблону упомянутую динамичность. Выглядит это так:
    <%= node['sql_server']['product_key'] %>,
    и является объявлением атрибута (ключа SQL сервера), присутствующего в cookbook-е. Также, стоит отметить, что, как и имена файлов в директории /files, имена шаблонов имеют такое же свойство имени, а именно описывают соответствие шаблона конкретной ОС и версии, либо FQDN узла.
  • Директории /providers и /resources – это те две директории, которые в терминах Chef организуют LWRP (light-weight resource providers). Я бы мог сравнить это с понятием класса в ООП, однако может такое сравнение и не очень корректно (уж простят админа братья-программисты). В провайдере можно описать функционал, в ресурсах – атрибуты/переменные и доступные action (возможные действия для провайдеров, которые могут быть вызваны из рецептов). Ресурсы идентифицируются и ассоциируются с провайдером, образуя подобие «класса».
    Взаимодействия между частями LWRP обеспечивается использованием Resource DSL – языка, содержащего несколько методов, для описания атрибутов и действий. И учитывая, что это вариант Ruby DSL – то и Ruby-код может быть частью определения ресурсов и провайдеров. Дабы долго не вдаваться в теорию, вот пример LWRP, который рассылает письма (например, при наступлении какого-либо события в системе).

    /providers/default.rb

    
    def mailing  
      puts "\n Sending your email..."
      
      r = chef_gem "mail" do
      	action :install
      end
      
      Gem.clear_paths
    
      require 'mail'
      options = { 
      			:address              => new_resource.server,
                :port                 => new_resource.port,
                :mailto				  => new_resource.mailto,
                :user_name            => new_resource.user_name,
                :password             => new_resource.password,
                :authentication       => 'plain',
                :enable_starttls_auto => true  
            }
    
        Mail.defaults do
              delivery_method :smtp, options
        end
    
        mail = Mail.deliver do
            from options[:user_name]
            to options[:mailto]
            subject 'Hello'
            body new_resource.msg
        end
    
    end



    /resources/default.rb
    
    actions :create
    default_action :create
    
    attribute :app_name, :kind_of => String
    
    attribute :user_name, :kind_of => String, :default => ""
    attribute :password, :kind_of => String, :default => ""
    attribute :server, :kind_of => String, :default => ""
    attribute :port, :kind_of => Integer, :default => 465
    attribute :mailto, :kind_of => [String, NilClass], :default => ""
    attribute :from, :kind_of => [String, NilClass], :default => ""
    attribute :msg, :kind_of => String, :default => "Hi there"
    
    def initialize(*args)
       super
       @ action = :create
    End
    



    Я думаю, достаточно очевидно, даже для тех, кто не встречался с синтаксисом Ruby, что описано в данном файле. Это функция отправки письма по электронной почте. В следующей части – мы познакомимся с cookbook-ом, который использует LWRP для отправки сообщений об изменениях в системе.


Шаг 6. Время дегустации


Ну что ж, давайте представим себе, что наш cookbook уже готов (я предоставлю его пример и опишу использование в следующей части).
Что делать дальше? Как загрузить его на сервер и отправить на исполнение узлами? Knife сделает это за нас. Для того, чтобы успешно провести дальнейшие операции, нам необходимо, чтобы Chef-админ имел верно сконфигурированный knife (файл knife.rb) и сертификат администратора (например, admin.pem). Далее, необходимо перейти в директорию /chef-repo (там, где находится наш starter kit, например) и, находясь в ней, исполнять команды.
Первое действие — удостоверится, что узлы зарегистрированы на сервере — knife node list. В результате должны получить имена активных узлов.
Далее, загрузим наш cookbook на сервер. Он должен находится в директории, указанной в cookbook_path файла knife.rb.
Выполняем — knife cookbook upload name-of-cookbook. В результате — сообщение об успешной загрузке и присутствие нашего cookbook-а в списке, полученном командой knife cookbook list.
Следующий шаг — назначение run-list узла. Тут можно пойти 2 путями — простым или правильным.
Простой — сразу добавить в run-list рецептknife node edit name-of-node и внести текстовые изменения в раздел run-list, добавляя туда строку «recipe[name-of-recipe]». А что, если таких рецептов десяток? Не очень удобно.

Правильный путь — добавить роль. Файл роли представляет собой описание атрибутов run-list. В том числе — и рецептов. Соответственно, одна роль может быть назначена множеству узлов. Файл роли находится по адресу /chef-repo/roles:

name "mailer"
description "Role for host that will notify us on changes"
run_list "recipe[name-of-recipe]"


Для того, чтоб загрузить роль на сервер, используется команда knife role from file name-of-role-file. После загрузки — роль можно назначить в run-list узла, что мы и сделаем.

На этом нехитрый процесс закончен, мы готовы запускать клиента на узле. После этого — получим узел с (условно) реализованным на нем cookbook-ом.

На этом я буду заканчивать вторую часть и буду анонсировать третью — более технически-ориентированную (с большим количеством кода), которая расскажет о примере использование AWS и Chef.
  • +17
  • 15,8k
  • 8
EPAM
144,26
Компания для карьерного и профессионального роста
Поделиться публикацией

Похожие публикации

Комментарии 8

    +1
    Несколько вопросов (возможно, на некоторые был дан ответ, но я невнимательно прочел):
    — «Сервер» — это нода или сервер chef'a?
    — Надо ли закачивать cookbook на ноды вручную или это можно настроить так, чтобы нода сама скачивала кукбуки? Если можно, то как?
    — Как сделать обновление кукбуков? Появился новый релиз, как сделать так, чтобы все ноды выполнили обновление?
      +1
      1. Сервер это в данном случае — chef-сервер. Еще там упоминается master — но это уже конкретный пример различия между нодами на определенной задаче, озвученной мной.
      2-3. Процесс chef-client, который при bootstrap — устанавливает клиента на узел, можно запускать по расписанию (используя cron или windows scheduler), соответственно он периодически связывается с сервером и проверяет изменения. Cookbook-и скачиваются этим же процессом.
      +1
      Хоть и не автор, попробую ответить:
      — сервер — имеется в виду chef-сервер;
      — при каждом запуске chef клиента, кукбуки на нодах синхронизируются с теми что есть на сервере.
      — ввиду второго пункта третий отпадает.
        0
        Тем, кто захочет заняться шефом вплотную могут помочь следующие keywords:
        vagrant (упоминалось в статье и именно с него стоит начать), chef-zero, berkshelf, vagrant-berkshelf, vagrant-omnibus.

        Сейчас идёт очень хорошая тенденция к универсальности в плане VM провайдеров: для knife есть масса плагинов для интеграции с различными облаками, vagrant так же интегрируется с различными системами виртуализации, облаками и т.д.

        Полезное видео (eng): www.youtube.com/watch?v=hYt0E84kYUI
        От авторов berkshelf

        Если у вас линукс, можно попробовать ещё vagrant-lxc (сам пока не пробовал).
        Есть ещё test-kitchen, но он пока сыроват.

        Когда сам начал в этом разбираться — знание об этих тулах могло сэкономить мне пару недель.
        Изучение и разработка значительно ускоряется.

          0
          Спасибо большое, полезная информация, действительно. У меня она частично запланирована на другую часть. Думаю, что люди, жаждущие разобраться — все равно придут к berkshelf и vagrant, ибо удобно решать зависимости и быстро разворачивается. С другой стороны — как уже упоминал я в статье — AWS это реально интересно и востребовано. Спасибо еще раз за собирательный комментарий.
            0
            Ну темткитчен уже вышел в релиз, вполне работает. Не пугайте людей)
            0
            На этапе регистрации узлов на Chef-сервере неизвестно, какой узел является master, а какой – slave. Что делать, не руками же назначать каждому? Решилось все просто до невозможности. Каждый узел получал, в зависимости от своего назначения, атрибут env_role = master или slave, который был доступен Chef-серверу. Сервер, в свою очередь, по всем зарегистрированным на нем узлам, проводил поиск по данному атрибуту и в зависимости от значения – раздавал cookbook-и (посредством ролей, о которых мы поговорим в дальнейшем).


            Не совсем понятно, узлы сами знали, кем они являются?
              0
              Идентификация узлов лежит на нас, поэтому каждому из них — назначался атрибут (он же метка, упомянутая в статье). Назначался он путем конфигурации клиента и параметра json_attribs. В итоге узел знал, кто он, но не знал, что с этой меткой делать — пока не регистрировался на сервере.

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое