- распространить файл на 100 серверах
- распространить пакет на 100 серверах
- изменить строку в файле
- обновить систему
- добавить пользователя
- перезапустить сервисы
и т.д., администратор инфраструктуры делает руками, поочерёдно заходя на все сервера и выполняя набор из 1-10 команд. Продолжая так работать, вскоре, системный администратор крупной системы превращается в «эникейщика серверной».
И есть два пути решения данной проблемы: нанять младшего сотрудника и «сгрузить» на него всю грязную работу, либо автоматизировать простые и не очень задачи.
На данный момент существует множество систем, которые позволяют это сделать, но наиболее популярные это Chef, Puppet и Ansible.
В данной публикации речь пойдёт о Chef и как при помощи него автоматизировать повседневные задачи на множестве серверов.
Вообще, почему Chef?
Во-первых, у нас его использует заказчик. Так что, чтобы не городить зоопарк из Deploy`еров оставил Chef. Где-то на Хабре видел хорошее описание различий между Chef и Puppet:
- Chef — что вы хотите получить?
- Puppet — что вы хотите сделать?
Но после просмотра видео-семинара «Дорога в облака», где Михаил Щербаков из Mirantis рассказывал про «Нестандартное использование Puppet в деплойменте», мне как-то расхотелось чётко следовать этой идеологии. Да и тестирование chef-рецептов, которые мы изготавливали для deploy`я проектов заказчику, навело на мысль, что использовать можно Chef как угодно.
Во-вторых, мне язык chef`а ближе, т.к. совсем не так давно, я познакомился с ruby, а синтаксис манифестов Chef`а как раз его и использует.
В-третьих, chef-рецепты можно распространять с сервера централизованно, просто вызвав "knife bootstrap --run-list «recipe[somerecipe]» somehost,domain.lan". Это реально удобно.
Ну и в-четвёртых, у chef`а есть нормальный клиент под Windows. А без этого порою никуда.
Установка
Я буду продолжать использовать Ubuntu в качестве примера. Только сервер будет на Ubuntu, клиенты будут на Ubuntu, CentOS и Windows.
Брать установочный пакет здесь.
# cd ~; wget https://web-dl.packagecloud.io/chef/stable/packages/ubuntu/trusty/chef-server-core_12.1.2-1_amd64.deb
# dpkg -i chef-server-core_12.1.2-1_amd64.deb
После установки пакета, следует запустить «переконфигурацию», создать пользователя и организацию.
# chef-server-ctl reconfigure
# chef-server-ctl user-create grey Sergey K grey@mydomain.lan superpassword123 --filename /etc/chef/mypem.pem
# chef-server-ctl org-create vst "VST Consulting, Inc." --association_user grey --filename /etc/chef/vst-validator.pem
Механизм организаций позволяет организовать вполне удобную тестовую площадку или объединить всех заказчиков на одном сервере (ой, не советую).
Здесь есть информация, которую я описал, плюс информация как установить дополнительные компоненты, например, web-интерфейс.
Так же стоит подправить некоторые конфиги и создать необходимые каталоги:
# cat /etc/chef/knife.rb
current_dir = File.dirname(__FILE__)
log_level :info
log_location STDOUT
node_name "grey"
client_key "#{current_dir}/grey.pem"
validation_client_name "vst-validator"
validation_key "#{current_dir}/vst-validator.pem"
chef_server_url "https://chef/organizations/vst"
cookbook_path ['/root/chef-repo/cookbooks']
# ln -s /opt/opscode/embedded/bin/knife /usr/bin/knife
# ln -s /etc/chef /root/.chef
# git clone https://github.com/opscode/chef-repo.git
# knife ssl fetch && knife ssl check
Простой кукбук
Наиболее популярный инструмент в Chef это cookbook`и. В нём содержатся определённые рецепты.
Рецепт — это шаблон выполнения определённых действий на сервере с шаблонами файлов, переменными и т.п. для реализации определённого рабочего результата. Как и в кулинарии, наша цель получить «супчик», который готов к употреблению.
В качестве примера, мы напишем рецепт приготовления некоторого самописного приложения-демона на java, которое вместе с конфигами надо будет распространить на некотором количестве серверов.
Создадим заготовку:
# cd /root/chef-repo/cookbooks
# knife cookbook create prog
# cd prog; ls
attributes CHANGELOG.md definitions files libraries metadata.rb providers README.md recipes resources templates
В нашем проекте, мы будем использовать только директории attributes, recipes, templates, а так же файл metadata.rb.
Начнём с конца. В файле metadata.rb содержится базовая информация о рецепте, его разработчике, его лицензия и версия, а так же зависимости и список поддерживаемых ОС.
name 'prog'
maintainer 'vstconsulting'
maintainer_email 'admin@vst.lan'
license 'All rights reserved'
description 'Installs/Configures Prog'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version '1.2.3'
# список поддерживаемых ОС
%w{ ubuntu debian centos redhat fedora oracle windows}.each do |os|
supports os
end
# зависимости
%w{ java }.each do |cb|
depends cb
end
В нашем примере указана зависимость от рецепта java, чтобы избежать проблемы с её отсутствием. Здесь есть готовые рецепты, в том числе и для java.
Далее, в директории recipes мы видим файл default.rb. Приводим к следующему виду:
#
# Cookbook Name:: Prog
# Recipe:: default
#
# Copyright 2015, vstconsulting
#
# All rights reserved - Do Not Redistribute
#
# Установка jdk версии 1.7
node.override['java']['jdk_version'] = '7'
include_recipe "java"
# Определение платформы
case node['platform_family']
when 'debian'
include_recipe 'prog::deb'
when 'rhel'
include_recipe 'prog::rhel'
when 'windows'
include_recipe 'prog::windows'
else
Chef::Application.fatal!('Attempted to install on an unsupported platform')
end
package_name = node['prog']['package']
remote_file 'prog' do
path "#{Chef::Config[:file_cache_path]}/#{package_name}"
source "http://domain.lan/packages/#{package_name}"
mode 0644
end
package 'prog' do
source "#{Chef::Config[:file_cache_path]}/#{package_name}"
end
service 'prog' do
action [:enable, :start]
end
template "#{node['prog']['conf_dir']}/main.conf" do
source 'main.conf.erb'
notifies :restart, 'service[prog]', :delayed
end
По порядку:
- node.override['java']['jdk_version'] = '7' говорит о том, что для cookbook`а java мы изменяем дефолтное значение атрибута jdk_version на '7'. Про атрибуты будет рассказано чуть позже.
- include_recipe «java» говорит о том, что мы должны запустить сперва рецепт default.rb из кукбука java. Дальнейшее приготовление по рецепту будет только после успешного приготовления по рецепту java.
- При помощи конструкции case и стандартного атрибута platform_family мы определяем платформу для установки и вызываем соответствующий рецепт из текущего cookbook`а. По большому счёту, в тех рецептах можно производить все манипуляции с установкой и запуском, но т.к. большинство действий будут идентичны, мы там будем приводить некоторые параметры к необходимому виду для конкретной платформы.
- package_name = node['prog']['package'] говорит о том, что мы объявляем переменную, которую в дальнейшем будем использовать. Эта переменная содержит в себе значение атрибута 'package'
- remote_file конструкция позволяет нам загрузить файл с открытого источника и сохранить его в директории с кешем.
- service конструкция говорит о том, что наш сервис будет в автозагрузке и запущен.
- template конструкция сохраняет шаблон конфигурации в необходимую директорию и перезапускает сервис.
По сути, я описываю универсальный рецепт, при помощи которого можно установить практически любой пакет в практически любую систему.
Далее нам нужно поправить атрибуты. Атрибуты это удобный механизм в кукбуках, который позволяет задавать извне сколько угодно параметров. В нашем примере будут использоваться 4 атрибута: package, conf_dir, prog_name, cluster.
Приведём attributes/default.rb к следующему виду:
default['prog']['prog_name'] = 'somejavademon'
default['prog']['package'] = "#{node['prog']['prog_name']}.deb"
case node['platform_family']
when 'debian'
default['prog']['conf_dir'] = "/etc/#{node['prog']['prog_name']}/conf"
when 'rhel'
default['prog']['conf_dir'] = "/etc/#{node['prog']['prog_name']}/conf"
when 'windows'
default['prog']['conf_dir'] = "C:/#{node['prog']['prog_name']}/conf"
else
Chef::Application.fatal!('Attempted to install on an unsupported platform')
end
Таким образом мы задаём базовые значения атрибутов, при этом мы учли, что для разных систем, размещение конфигурационных файлов будет в разных местах.
Теперь, нам нужно создать шаблон конфигурационного файла:
cluster.name: <%= node["prog"]["cluster"] %>
node.name: <%= node['hostname'] %>
Я думаю после вышесказанного понятно, как можно подставить необходимые атрибуты в шаблон. Можно даже использовать циклы, но на этом не буду заострять внимание.
Я не упоминал, но дополнительные рецепты по шаблонам тоже следует создать:
# cat recipes/deb
node.override['prog']['package'] = "#{node['prog']['prog_name']}.deb"
# cat recipes/rhel
node.override['prog']['package'] = "#{node['prog']['prog_name']}.rpm"
# cat recipes/windows
node.override['prog']['package'] = "#{node['prog']['prog_name']}.msi"
Да, вот так вот просто.
Загрузим наши рецепты на сервер:
# knife cookbook upload --all
Environment
Теперь мы создадим пример простого окружения, из которого будут браться наши параметры
Это не обязательно, но чтобы понять что и как работает, будет весьма полезно.
# export EDITOR=nano
# knife environment create someserver -d "Environment for group of servers where somejavademon will work."
Откроется окно указанного EDITOR`а в которое мы занесём следующую информацию:
{
"name": "someserver",
"description": "Environment for group of servers where somejavademon will work.",
"cookbook_versions": {
},
"json_class": "Chef::Environment",
"chef_type": "environment",
"default_attributes": {
},
"override_attributes": {
"prog": {
"prog_name": "somejavaserver",
}
}
}
Теперь эту среду можно применять на некотором количестве хостов, где будет устанавливаться именно somejavaserver.
DEPLOY
Теперь мы подошли к самому главному: распространению нашего продукта по серверам.
- У нас есть рецепт, в котором указано что, как и куда нужно установить.
- У нас есть Env в котором указано что конкретно нужно установить.
- У нас есть рабочий сервер Chef, на котором всё это лежит и он имеет доступ ко всем необходимым серверам.
- У нас есть 100 серверов с рабочим domainname на Ubuntu, CentOS, на которые всё это нужно установить.
- У нас есть рут/админ-доступ по ssh ко всем необходимым серверам.
Теперь, чтобы установить нужный нам рецепт на сервер, нам нужно выполнить:
# knife bootstrap --run-list "recipe[prog]" server1.domain.lan -E someserver -P rootpasswordfromnode
Нам ничего не мешает написать скрипт:
#!/bin/bash
for i in {1..100}; do
knife bootstrap --run-list "recipe[prog]" server$i.domain.lan -E someserver -P rootpasswordfromnode
done
Спустя какое-то время (5минут/полчаса/час/сутки) все 100 серверов будут в строю в полной готовности.
При любом раскладе, установка Chef-сервера, написание рецепта и env, а так же deploy займёт меньше или столько же времени, что и ручная установка пакета на каждом сервере. НО! Если у нас уже всё готово, то повторная установка займёт уже гораздо меньше времени и уж тем более усилий. Самое главное, что делать вручную уже ничего не нужно. Достаточно только указать список серверов, запустить скрипт и пойти читать новые публикации на Хабре.
Что ещё можно сделать?
Это довольно философский вопрос.
Можно (и нужно) установить knife-windows. Там не сложно, но если будут вопросы — готов помочь.
Можно загрузить с супермаркета кучу готовых рецептов и деплоить всё что душе угодно на сколько угодном количестве серверов.
Можно написать свои рецепты на все случаи жизни и свести обслуживание серверной к установке ОС (которая тоже неплохо автоматизируется при помощи PXE), замене оборудования и мониторингу.
Можно подключить Chef к OpenStack (если таковой имеется) и деплоить новые сервера и сервисы «пачками». Тут можно узнать как это сделать. Там ничего сложного, особенно если уже разобрались с Cloud-Init и Chef.
Если я что-то забыл добавить, то поправьте меня, пожалуйста, в комментариях.
Надеюсь, эта публикация поможет кому-то разобраться с Chef и рутинной работой в серверной или офисе.
Комментарии (21)
aik
23.07.2015 08:04-11Посмотрите, как дяденька мучается из-за того, что у него
поляроидаActive Directory нет. :)dfm
23.07.2015 12:06-4Видимо минусят те, кто этого анекдота не знает
анекдотПрогуливается новый русский со своей маленькой дочуркой по берегу живописного озера. Видит — художник рисует пейзаж. Новый русский с дочкой встают у него за спиной и наблюдают за работой художника. Через некоторое время новый русский назидательно говорит дочке: — Вот смотри, дочка, как дядька без полароида мучается!rbobot
23.07.2015 16:18AD сам этого никак не сделает, нужен либо sccm, либо powershell dsc.
Для последнего, кстати, для шефа есть обертка: www.chef.io/solutions/windows
gto
23.07.2015 14:28мне язык chef`а ближе, т.к. совсем не так давно, я познакомился с ruby
А puppet, простите, на чём?
В-третьих, в-четвёртых
Попробуйте поставте поверх puppeta foreman. И манифесты можно будет централизованно запускать и на клиентов не заморачиваться.renya
23.07.2015 15:15+1> А puppet, простите, на чём?
Думаю, что автор говорит про синтаксис манифестов, а не на чем написан сабж.onegreyonewhite Автор
24.07.2015 01:48Именно это я и имел в виду. Спасибо за уточнение.
Добавлю уточнение в публикацию.
alex_www
23.07.2015 17:15Насчёт 100 сервеверов все верно, но если надо 1000+ — быстро упретесь в производиельность руби. Потому-то Facebook и linkedin используют cfengine.
onegreyonewhite Автор
24.07.2015 02:38Поэтому я и оперировал сотнями. cfengine «руки чешутся» попробовать, но пока нет такой возможности.
alex_www
24.07.2015 03:06Оно того стоит. В хронологическом порядке
habrahabr.ru/post/164445
habrahabr.ru/post/164923
habrahabr.ru/post/249249onegreyonewhite Автор
24.07.2015 03:51Придётся поверить, особенно с учётом того, что 2 из 3ёх публикаций ваши) Почитаю на досуге.
jsirex
29.07.2015 00:32Я думал, Facebook сидит на Chef. А есть где почитать как и когда они перешли на cfengine.
И мне не совсем понятен вопрос производительности? Какая разница 100, 1000, 10000? Точнее, она там есть, но тогда причём тут руби?
KorP
23.07.2015 21:42Ну не знаю… НА мой взгляд для этих целей Ansible куда проще и лучше подходит. Я вот пол года как раз для администрирования множества серверов его использую и кайфую
varnav
24.07.2015 11:17Мне тоже все твердят что будущее за Ansible
gto
24.07.2015 13:26Это всё теория. «Говорят», «будущее за» понятия немного абстрактные. У нас вот полторы тысячи серверов, несчитано вагрантов у девов, aws-ки и всё это бегает на связке puppet + foreman, при том, что девам делигированна часть фукнкций по управлению. И я вам точно скажу, для нас будущее точно за этой связкой, просто потому, что работает.
onegreyonewhite Автор
27.07.2015 03:15«будущее за» тем, что выберет администратор в своём серверном парке. Конечно администратор мог и ошибиться с выбором, но если продукт развивается и к нему привык персонал, то скорее всего этот продукт будет использоваться ещё очень долго.
Главное, чтобы конечный инструмент мог и решал бОльшую часть задач администратора. И чем больше задач решаются «из коробки», тем удачнее выбран продукт. Ярким примером для меня был Мегафон, где «костыль» подпирается «костылём», просто потому что рабочий продукт не решает необходимых задач.
Поэтому (я слегка «скапитаню») нужно выбирать не то, что «все твердят», а то, что реально подходит.
jsirex
29.07.2015 00:37Если у вас 100+ серверов и chef-client установлен в режиме демона (крутится как клиент, на машине), осторожнее с:
remote_file 'prog' do path "#{Chef::Config[:file_cache_path]}/#{package_name}" source "http://domain.lan/packages/#{package_name}" mode 0644 end
У вас там наверное трафик с этого сервера большой идёт. Каждый запуск chef-client перекачивает этот файл.
pavelsh
> На данный момент существует множество систем, которые позволяют это сделать, но наиболее популярные это Chef и Puppet.
В последнее время я больше слышу ansible. Как-то про chef и puppet забывать стали.
onegreyonewhite Автор
Точно! Про ansible я и забыл. Заказчик в США, а у них почему-то Chef да Puppet очень любят.
Сейчас добавлю в публикацию.
brabon
AWS / CloudFormation — построен и использует chef
На маленьких мне по душе больше ansible:
— не надо ставить cchef/puppet client, все идет по СШ
— минимальная конфигурация
— можно устроить полноценную aws orchestration или простую установку apache+php