Каждый день системный администратор сталкивается с задачами, которые так или иначе приходится решать банальным набором команд. Порою доходит до смешного:
и т.д., администратор инфраструктуры делает руками, поочерёдно заходя на все сервера и выполняя набор из 1-10 команд. Продолжая так работать, вскоре, системный администратор крупной системы превращается в «эникейщика серверной».
И есть два пути решения данной проблемы: нанять младшего сотрудника и «сгрузить» на него всю грязную работу, либо автоматизировать простые и не очень задачи.
На данный момент существует множество систем, которые позволяют это сделать, но наиболее популярные это Chef, Puppet и Ansible.
В данной публикации речь пойдёт о Chef и как при помощи него автоматизировать повседневные задачи на множестве серверов.
Во-первых, у нас его использует заказчик. Так что, чтобы не городить зоопарк из Deploy`еров оставил Chef. Где-то на Хабре видел хорошее описание различий между 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.
Брать установочный пакет здесь.
После установки пакета, следует запустить «переконфигурацию», создать пользователя и организацию.
Механизм организаций позволяет организовать вполне удобную тестовую площадку или объединить всех заказчиков на одном сервере (ой, не советую).
Здесь есть информация, которую я описал, плюс информация как установить дополнительные компоненты, например, web-интерфейс.
Так же стоит подправить некоторые конфиги и создать необходимые каталоги:
Наиболее популярный инструмент в Chef это cookbook`и. В нём содержатся определённые рецепты.
Рецепт — это шаблон выполнения определённых действий на сервере с шаблонами файлов, переменными и т.п. для реализации определённого рабочего результата. Как и в кулинарии, наша цель получить «супчик», который готов к употреблению.
В качестве примера, мы напишем рецепт приготовления некоторого самописного приложения-демона на java, которое вместе с конфигами надо будет распространить на некотором количестве серверов.
Создадим заготовку:
В нашем проекте, мы будем использовать только директории attributes, recipes, templates, а так же файл metadata.rb.
Начнём с конца. В файле metadata.rb содержится базовая информация о рецепте, его разработчике, его лицензия и версия, а так же зависимости и список поддерживаемых ОС.
В нашем примере указана зависимость от рецепта java, чтобы избежать проблемы с её отсутствием. Здесь есть готовые рецепты, в том числе и для java.
Далее, в директории recipes мы видим файл default.rb. Приводим к следующему виду:
По порядку:
По сути, я описываю универсальный рецепт, при помощи которого можно установить практически любой пакет в практически любую систему.
Далее нам нужно поправить атрибуты. Атрибуты это удобный механизм в кукбуках, который позволяет задавать извне сколько угодно параметров. В нашем примере будут использоваться 4 атрибута: package, conf_dir, prog_name, cluster.
Приведём attributes/default.rb к следующему виду:
Таким образом мы задаём базовые значения атрибутов, при этом мы учли, что для разных систем, размещение конфигурационных файлов будет в разных местах.
Теперь, нам нужно создать шаблон конфигурационного файла:
Я думаю после вышесказанного понятно, как можно подставить необходимые атрибуты в шаблон. Можно даже использовать циклы, но на этом не буду заострять внимание.
Я не упоминал, но дополнительные рецепты по шаблонам тоже следует создать:
Да, вот так вот просто.
Загрузим наши рецепты на сервер:
Теперь мы создадим пример простого окружения, из которого будут браться наши параметры
Это не обязательно, но чтобы понять что и как работает, будет весьма полезно.
Откроется окно указанного EDITOR`а в которое мы занесём следующую информацию:
Теперь эту среду можно применять на некотором количестве хостов, где будет устанавливаться именно somejavaserver.
Теперь мы подошли к самому главному: распространению нашего продукта по серверам.
Теперь, чтобы установить нужный нам рецепт на сервер, нам нужно выполнить:
Нам ничего не мешает написать скрипт:
Спустя какое-то время (5минут/полчаса/час/сутки) все 100 серверов будут в строю в полной готовности.
При любом раскладе, установка Chef-сервера, написание рецепта и env, а так же deploy займёт меньше или столько же времени, что и ручная установка пакета на каждом сервере. НО! Если у нас уже всё готово, то повторная установка займёт уже гораздо меньше времени и уж тем более усилий. Самое главное, что делать вручную уже ничего не нужно. Достаточно только указать список серверов, запустить скрипт и пойти читать новые публикации на Хабре.
Это довольно философский вопрос.
Можно (и нужно) установить knife-windows. Там не сложно, но если будут вопросы — готов помочь.
Можно загрузить с супермаркета кучу готовых рецептов и деплоить всё что душе угодно на сколько угодном количестве серверов.
Можно написать свои рецепты на все случаи жизни и свести обслуживание серверной к установке ОС (которая тоже неплохо автоматизируется при помощи PXE), замене оборудования и мониторингу.
Можно подключить Chef к OpenStack (если таковой имеется) и деплоить новые сервера и сервисы «пачками». Тут можно узнать как это сделать. Там ничего сложного, особенно если уже разобрались с Cloud-Init и Chef.
Если я что-то забыл добавить, то поправьте меня, пожалуйста, в комментариях.
Надеюсь, эта публикация поможет кому-то разобраться с Chef и рутинной работой в серверной или офисе.
UPD: Решил добавить пример cloud-config для OpenStack:
- распространить файл на 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/grey.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
Таким образом мы задаём базовые значения атрибутов, при этом мы учли, что для разных систем, размещение конфигурационных файлов будет в разных местах.
Теперь, нам нужно создать шаблон конфигурационного файла:
templates/default/main.conf.erb
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 и рутинной работой в серверной или офисе.
UPD: Решил добавить пример cloud-config для OpenStack:
#cloud-config
ВМ после старта установит chef-client, настроит его на связь с chef-server.
Перезапуск клиента нужен, чтобы chef подхватил сразу рецепт, а не ждал какое-то время. У меня почему-то он ждал следующего планового запроса без перезапуска.
Пример для Ubuntu. На CentOS надо несколько больше действий совершить.
#cloud-config
packages:
- chef
chef:
install_type: "packages"
force_install: false
# Chef settings
server_url: "https://chef-server.lan/organizations/organization_name"
validation_name: "organization_name-validator"
validation_key: |
-----BEGIN RSA PRIVATE KEY-----
..................................................
-----END RSA PRIVATE KEY-----
run_list:
- "recipe[somerecipe]"
output: {all: '| tee -a /var/log/cloud-init-output.log'}
runcmd:
- service chef-client restart
ВМ после старта установит chef-client, настроит его на связь с chef-server.
Перезапуск клиента нужен, чтобы chef подхватил сразу рецепт, а не ждал какое-то время. У меня почему-то он ждал следующего планового запроса без перезапуска.
Пример для Ubuntu. На CentOS надо несколько больше действий совершить.