Статьи

Развитие к поваренной книге многократного использования в Поваре

Несколько месяцев назад я начал вкладывать большие средства в Chef, чтобы автоматизировать развертывание наших приложений и вспомогательной инфраструктуры. Пока все хорошо, но это не всегда были солнечные собаки и щенки. Одной из основных проблем является попытка повторно использовать кулинарные книги, найденные на сайте сообщества , на GitHub или даже в нашей собственной организации. Я обнаружил, что мне часто приходилось сильно настраивать кулинарные книги или переписывать кулинарные книги с нуля, чтобы удовлетворить наши потребности.

Недавно я обнаружил шаблон, который мы используем в наших внутренних кулинарных книгах, который, кажется, делает повторное использование возможным, даже легким. Поэтому я подумал, что отправлю это в мир, чтобы посмотреть, будет ли это полезным для других. Так вот как это развивалось …

Фаза 1: Поваренная книга как большой сценарий bash

Вначале наши кулинарные книги в основном были похожи на сценарии с большим bash. Концептуально они будут делать что-то подобное;

bash "install mypackage" do
  cwd "#{Chef::Config[:file_cache_path]}"
  code <<-EOH
wget http://example.com/mypackage-1.0.tar.gz
tar xzf mypackage-1.0.tar.gz
cd mypackage-1.0
./configure && make && make install
  EOH
  not_if { File.exists?("/usr/bin/mypackage") }
end

Это было быстро написать, но это лучшее, что можно сказать об этой технике. Этот подход не привел к повторному использованию поваренных книг, если у нас не было одинаковых требований на другом узле.

Этап 2: Атрибуты для настройки

Мы быстро столкнулись с проблемами, когда нам нужно было настроить приложение в зависимости от среды. В этот момент мы ввели атрибуты для настройки приложения. Концептуально наши рецепты начали выглядеть примерно так;

bash "install mypackage" do
  cwd "#{Chef::Config[:file_cache_path]}"
  code <<-EOH
wget http://example.com/mypackage-#{node[:mypackage][:version]}.tar.gz
tar xzf mypackage-#{node[:mypackage][:version]}.tar.gz
cd mypackage-#{node[:mypackage][:version]}
./configure && make && make install
  EOH
  not_if { File.exists?("/usr/bin/mypackage") }
end

template "/etc/mypackage.conf" do
  source "mypackage.conf.erb"
  mode "0644"
  variables(
      :database => node[:mypackage][:database],
      :user => node[:mypackage][:user],
      :password => node[:mypackage][:password]
    )
end

Этап 3: Разделите рецепты на единицы повторного использования

В дальнейшем мы обнаружили, что разные узлы предъявляют разные требования. то есть одна установка mypackage будет использовать локальную базу данных для аутентификации, а другая установка будет проходить аутентификацию в Active Directory. Это привело к тому, что мы разделили рецепты на несколько рецептов на основе единиц повторного использования. Таким образом, наш гипотетический рецепт «mypackage :: default» будет разделен на «mypackage :: default», «mypackage :: db_auth», «mypackage :: ad_auth». Роль будет включать в себя конкретные рецепты, которые необходимы.

Этап 4: ресурсы для спасения

Ресурсы (через LWRP) были следующей абстракцией, которую мы представили. Это позволило легко повторять похожие наборы сложных действий во многих рецептах с небольшими различиями в конфигурации. Типичный сценарий включает определение нескольких очередей в брокере сообщений, например, в этом фрагменте с использованием поваренной книги Glassfish ;

glassfish_mq_destination "WildfireStatus queue" do
  queue "Fireweb.WildfireStatus"
  config {'validateXMLSchemaEnabled' => true, 'XMLSchemaURIList' => 'http://...'}
  host 'localhost'
  port 7676
end

glassfish_mq_destination "PlannedBurnStatus queue" do
  queue "Fireweb.PlannedBurnStatus"
  config {'maxCount' => 1000, ...}
  host 'otherhost'
  port 7676
end

Следует отметить, что эти ресурсы могут быть составлены. Так что ресурсы низкого уровня могут быть использованы для создания ресурсов высокого уровня. Таким образом, у нас фактически есть ресурс glassfish_mq, который использует ресурс glassfish_mq_destination в своей реализации.

glassfish_mq "MessageBroker Instance" do
  instance "MessageBroker"
  users {...}
  access_control_rules {...}
  config {...}
  queues {
    "Fireweb.WildfireStatus" => {'validateXMLSchemaEnabled' => true, 'XMLSchemaURIList' => 'http://...'},
    "Fireweb.PlannedBurnStatus" => {'maxCount' => 1000, ...}
  }
  port 7676
  admin_port 7677
  jms_port 7678
  jmx_port 8087
  stomp_port 8087
end

Этап 5: повторное использование данных

Использование ресурсов позволило нам легко создавать индивидуальные кулинарные книги, но создание кулинарных книг может быть однообразным. В каждом рецепте было много стандартного кода. Мы отреагировали, сохранив упрощенное описание ресурсов в виде данных, интерпретируя описание и вызывая ресурсы для представления данных. Иногда описание хранилось в пакетах данных, иногда описание было синтезировано с помощью поиска на сервере chef, иногда описание было синтезировано с использованием слоя правил.

Например, мы обнаружили набор очередей для создания в нашем брокере сообщений, выполнив поиск на сервере chef узлов в той же среде, которая объявила требование для очередей сообщений в атрибутах (т. Е. «Openmq.destination.queues»). При настройке аспектов ведения журналов в наших системах мы ищем узел graylog2 и гарантируем, что мы получим производственный узел в производственной среде и узел разработки во всех других средах. Файлы .war и их необходимые настройки объявляются в пакете данных и мы запрашиваем пакет данных при заполнении нашего сервера приложений.

Этап 6: рецепт политики + рецепт на основе атрибута

Подход, основанный на данных, сэкономил нам много работы, но ограничил повторное использование поваренной книги; бизнес-правила были закодированы таким образом, чтобы мы хранили, синтезировали и открывали данные. Это также означало, что некоторые наши основные кулинарные книги менялись каждый раз, когда мы меняли способ абстрагирования данных конфигурации нашего приложения.

Наш самый последний подход состоял в том, чтобы вытянуть код политики, специфичный для бизнеса, в отдельную кулинарную книгу, а затем включить рецепт, который использует атрибуты, определенные на текущем узле, для управления созданием инфраструктуры.

Наши рецепты политики выглядят примерно так:

node.override[:openmq][:extra_libraries] =  ["http://example.org/repo/myext.jar"]

queues = []
search(:node, 'openmq_destinations_queues:* AND NOT name:' + node.name) do |n|
  queues.merge( n['openmq']['destinations']['queues'].to_hash )
end
queues.merge( node['openmq']['destinations']['queues'].to_hash )

include_recipe "glassfish::attribute_driven_mq"

Этот подход, кажется, дал нам возможность создать поваренную книгу многократного использования ( стеклянная рыба в вышеописанном случае) с компонентами, которые с меньшей вероятностью будут повторно использованы в отдельном рецепте «политики». Мы уже используем это для успешного управления сервером приложений, брокером сообщений, для настройки мониторинга и ведения журнала, а также для применения правил брандмауэра. Интересно, был ли это подход, который открыли другие, и можно ли применить его к другим кулинарным книгам?