Каждый день системный администратор сталкивается с задачами, которые так или иначе приходится решать банальным набором команд. Порою доходит до смешного:
- распространить файл на 100 серверах
- распространить пакет на 100 серверах
- изменить строку в файле
- обновить систему
- добавить пользователя
- перезапустить сервисы
и т.д., администратор инфраструктуры делает руками, поочерёдно заходя на все сервера и выполняя набор из 1-10 команд. Продолжая так работать, вскоре, системный администратор крупной системы превращается в «эникейщика серверной».
И есть два пути решения данной проблемы: нанять младшего сотрудника и «сгрузить» на него всю грязную работу, либо автоматизировать простые и не очень задачи.
На данный момент существует множество систем, которые позволяют это сделать, но наиболее популярные это Chef и Puppet.
В данной публикации речь пойдёт о Chef и как при помощи него автоматизировать повседневные задачи на множестве серверов.
Вообще, почему Chef?
Во-первых, у нас его использует заказчик. Так что, чтобы не городить зоопарк из Deploy`еров оставил Chef. Где-то на Хабре видел хорошее описание различий между Chef и Puppet:
- Chef — что вы хотите получить?
- Puppet — что вы хотите сделать?
Но после просмотра видео-семинара «Дорога в облака», где Михаил Щербаков из Mirantis рассказывал про «Нестандартное использование Puppet в деплойменте», мне как-то расхотелось чётко следовать этой идеологии. Да и тестирование chef-рецептов, которые мы изготавливали для deploy`я проектов заказчику, навело на мысль, что использовать можно Chef как угодно.
Во-вторых, мне язык chef`а ближе, т.к. совсем не так давно, я познакомился с ruby.
В-третьих, 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 и рутинной работой в серверной или офисе.
ссылка на оригинал статьи http://habrahabr.ru/post/263341/
Добавить комментарий