Создание манифестов Puppet. Что такое система управления конфигурацией? Цикл синхронизации RAL


Автор: Luke Kanies
Дата публикации: 2 Мая 2012 г.
Перевод: А.Панин
Дата перевода: 27 Августа 2013 г.

18.1. Введение

Puppet является инструментом для управления IT-инфраструктурой, разработанным с использованием языка программирования Ruby и используемым для автоматизации обслуживания датацентров и управления серверами компаний Google, Twitter, Нью-Йоркской фондовой биржи и многих других организаций. Главным образом развитие проекта поддерживается организацией Puppet Labs, которая положила начало его развитию. Puppet может управлять серверами в количестве от 2 до 50,000 и обслуживаться командой, состоящей из одного или сотен системных администраторов.

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

В общем случае Puppet выполняет все возможные действия направленные на то, чтобы использовать функции существующей системы для выполнения своей работы; т.е., в дистрибутивах, основанных на технологиях компании RedHat, он будет использовать утилиту yum для управления пактами и init.d для управления службами, при этом в операционной системе OS X он будет использовать утилиту dmg для управления пактами и launchd для управления службами. Одной из основополагающих целей проекта Puppet является выполнение полезной работы вне зависимости от того, используется ли для этого код проекта Puppet или сама система, поэтому следующие системные стандарты являются критичными.

Проект Puppet создан с учетом опыта использования множества других инструментов. В мире приложений с открытым исходным кодом наибольшее влияние на его развитие оказал проект CFEngine, который являлся первым инструментом конфигурации общего назначения с открытым исходным кодом, а также проект ISconf, который использовал утилиту make для выполнения всей работы, что в свою очередь обусловило особое внимание к явно описанным зависимостям в системе. В мире коммерческого программного обеспечения Puppet может рассматриваться как конкурент проектов BladeLogic и Opsware (которые впоследствии были приобретены более крупными компаниями), каждый из которых успешно продавался в момент появления Puppet, но при этом каждый из этих инструментов продавался руководителям больших компаний, вместо развития в соответствии с непосредственными требованиями к качественным инструментам системных администраторов. Предназначением проекта Puppet было решение аналогичных решаемым этими инструментами проблем, при этом он был предназначен для совершенно других пользователей.

В качестве простого примера метода использования Puppet, ниже приведен фрагмент кода, который позволяет быть уверенным в правильной установке и конфигурации службы безопасной оболочки (SSH): class ssh { package { ssh: ensure => installed } file { "/etc/ssh/sshd_config": source => "puppet:///modules/ssh/sshd_config", ensure => present, require => Package } service { sshd: ensure => running, require => , Package] } }

Этот код позволяет быть уверенным в том, что пакет будет установлен, файл будет размещен в необходимом месте и служба будет запущена. Следует отметить, что мы описали зависимости между ресурсами, поэтому всегда будем выполнять любую работу в корректной последовательности. Этот класс может быть ассоциирован с любым узлом для применения заданной конфигурации в рамках этого узла. Обратите внимание на то, что строительными блоками конфигурации Puppet являются структурированные объекты, в данном случае это объекты package , file и service . В терминологии Puppet мы называем эти объекты ресурсами (resources ) и любые спецификации конфигурации Puppet состоят из этих ресурсов и зависимостей между ними.

Нормальная установка Puppet будет содержать десятки или даже сотни этих фрагментов кода, называемых нами классами (classes ); мы храним эти классы на диске в файлах, называемых манифестами (manifests), а также объединяем логически связанные классы в рамках групп, называемых модулями (modules ). Например, вы можете иметь в распоряжении модуль ssh с этим классом ssh и любыми другими логически связанными классами наряду с модулями mysql , apache и sudo .

Большая часть операций взаимодействия с Puppet осуществляется с использованием командной оболочки или постоянно работающих служб HTTP, но существуют и графические интерфейсы для выполнения таких задач, как обработка отчетов. Компания Puppet Labs также предоставляет коммерческие программные продукты для работы с Puppet, которые используют графические веб-интерфейсы.

Первый прототип Puppet был разработан летом 2004 года, а полноценная разработка проекта началась в феврале 2005 года. Изначально он был спроектирован и разработан Luke Kanies, системным администратором, имеющим большой опыт разработки небольших инструментов, но не имеющим опыта разработки проектов, содержащих более 10,000 строк кода. По существу Luke Kanies получил навыки программирования в ходе разработки проекта Puppet, что отразилось на архитектуре проекта как положительно, так и отрицательно.

Puppet разрабатывался изначально и в первую очередь как инструмент для системных администраторов, облегчающий их жизнь, позволяющий выполнять работу быстрее, более эффективно и с меньшим количеством ошибок. Первой ключевой инновацией для реализации этого принципа были описанные выше ресурсы, являющиеся примитивами Puppet; они могут переноситься между операционными системами, при этом абстрактно представляя детали реализации, позволяя пользователю думать о результатах работы, а не о том, как их достичь. Этот набор примитивов был реализован на уровне абстракции ресурсов Puppet (Puppet"s Resource Abstraction Layer).

Ресурсы Puppet должны быть уникальными для заданного узла. Вы можете иметь в распоряжении только один пакет с именем "ssh", одну службу с именем "sshd" и один файл с именем "/etc/ssh/sshd_config". Это ограничение предотвращает взаимные конфликты между различными частями ваших конфигураций и вы узнаете об этих конфликтах на раннем этапе процесса конфигурации. Мы ссылаемся на эти ресурсы по их типам и именам, т.е., Package и Service . Вы можете использовать пакет и службу с одним и тем же именем, так как они относятся к различным типам, но не два пакета или службы с одним и тем же именем.

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

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

В основе функциональных компонентов Puppet лежат два направляющих его развитие принципа: он должен быть настолько простым в использовании, насколько это возможно, причем предпочтение должно отдаваться удобству в использовании, а не возможностям; а также он должен разрабатываться в первую очередь в форме фреймворка и во вторую - приложения, таким образом при желании сторонние разработчики получат возможность создавать свои приложения на основе программных компонентов Puppet. Было понятно, что в дополнение к фреймворку необходимо также широко применяемое качественное приложение, но в первую очередь разработчики все равно занимались фреймворком, а не приложением. Многие люди все еще считают, что Puppet является этим самым приложением, а не фреймворком, на основе которого оно реализовано.

После создания первого прототипа Puppet, Luke стал в целом неплохим Perl-разработчиком с небольшим опытом разработки сценариев оболочки и небольшим опытом работы с языком C, большей частью полученным при работе с системой CFEngine. В дополнение к этому он имел опыт создания систем разбора данных для простых языков, который был получен при разработке двух таких систем для работы в составе небольших инструментов, а также повторной разработки с нуля системы разбора данных для CFEngine с целью упрощения ее поддержки (этот код не был передан проекту из-за небольших несовместимостей).

Решение об использовании динамического языка для реализации Puppet было принято достаточно быстро ввиду значительно более высокой производительности труда разработчика и распространения данного типа языков, но выбор самого оказался достаточно сложным. Начальные прототипы на языке Perl были отвергнуты, поэтому проводились эксперименты для поиска других языков. Была предпринята попытка использования языка Python, но Luke посчитал это язык значительно противоречащим его взгляду на мир. Услышав рассказ друга о преимуществах нового языка, Luke попробовал использовать язык Ruby и за четыре часа создал работающий прототип. В момент, когда началась полномасштабная разработка Puppet, язык Ruby был практически не известен, поэтому решение о его использовании было сопряжено с большим риском, но в этом случае производительность труда разработчика снова сыграла решающую роль в выборе языка. Главной отличительной чертой языка Ruby, по крайней мере от Perl, была простота создания неиерархических отношений классов, при этом язык не противоречил мыслительной деятельности разработчика Luke, что было критично.

Представьте себя в роли системного администратора, ответственного за поддержание работоспособности сотни-другой машин, работающих под управлением операционных систем типа UNIX. Каждая из них требует настройки, периодического обновления и мониторинга, но предполагается, что многие из них выполняют сходные функции. Две трети это - рабочие станции, еще несколько - маршрутизаторы, остальные - несколько web-серверов и хранилищ данных. Вопрос: как всем этим хозяйством управлять?

Самый простой ответ - это просто подключаться к каждой из них с помощью SSH и вносить необходимые изменения. Однако, такой способ имеет две проблемы. Во-первых, он очень трудозатратный. Во-вторых, админу постоянно придется выполнять множество однообразных действий (например, чтобы обновить OpenOffice.org на всех рабочих станциях придется выполнить одни и те же команды несколько десятков раз). Можно попытаться избежать этой проблемы написав несколько скриптов, которые будут сами подключаться к каждой машине и выполнять заранее прописанные команды. Но и здесь нас ожидают проблемы. Скрипты придется постоянно видоизменять, чтобы подстроить их под каждую задачу, в скриптах придется учитывать различие в операционных системах и версиях, их придется долго отлаживать перед тем как применить к работающим машинам. В общем не камильфо.

Правильный ответ заключается в использовании так называемых систем удаленного управления конфигурациями, наиболее известными представителями которых являются открытые системы Cfengine и Puppet. Такие системы берут на себя все обязанности за приведение конфигурации машин к нужному виду, требуя от администратора лишь описание конечного состояния системы на специальном языке (например, описание того, какие пакеты должны быть установлены в ОС, какие строки должны быть добавлены в конфигурационные файлы, какие команды должны быть выполнены и т.д.). После этого все узлы сами получат информацию о требуемом состоянии от сервера и проведут автоконфигурирование системы. Благодаря такому механизму новые машины могут быть полностью настроены без вмешательства человека, а существующие - перенастроены с помощью добавления всего нескольких строк в описание состояний.

Puppet?

Puppet была разработана Люком Каниесом (Luke Kanies), который устал от ограничений Cfengine и решил создать ее более совершенный аналог с нуля. Если вы уже использовали Cfenfine, то наверняка найдете Puppet более удобной и мощной системой. Язык описания состояний Puppet более высокоуровневый и гибкий, благодаря чему администратору не нужно заботится о таких вещах, как написание отдельных правил для каждого типа ОС или подробное описание выполнения тривиальных действий. Puppet позволяет сосредоточится на том, что он хочет сделать, вместо того как это делать (например, чтобы установить определенный пакет в любую из поддерживаемых системой ОС, достаточно написать буквально несколько строк, говорящих "Установи эту программу", вместо описания команд, необходимых для ее установки). Puppet написан на простом языке Ruby, благодаря чему его достаточно просто подогнать под конкретную задачу и расширить функционал (предусмотрена гибкая система плагинов). Кроме того, в отличие от модели развития Cfengine, которая фактически вращается вокруг одного человека, вокруг Puppet сформировалось большое сообщество энтузиастов, которые вносят доработки в код, делятся примерами конфигурации и пишут документацию.

В целом Puppet производит впечатление более современной и продуманной системы с хорошим дизайном. Как и Cfengine она поддерживает почти все современные UNIX-подобные ОС (в том числе MacOS X), а также может работать в среде Cygwin, поверх Windows. Список ее зависимостей включает только интерпретатор Ruby и инструмент Factor, так что проблем с установкой возникнуть не должно (справедливости ради стоит сказать, что список зависимостей Cfengine и того короче).



Файл-сервер

Многие задачи удаленного администрирования не могут быть решены без копирования на машины дополнительных файлов. Это могут быть заранее подготовленные конфиги, web-страницы для Apache, пакеты, отсутствующие в официальном репозитории и многое другое. Чтобы облегчить процесс переноса этих файлов на удаленные узлы Puppet включает в себя файловый сервер.

Настройки файлового сервера хранятся в файле /etc/puppet/fileserver.conf. Чтобы заставить Puppet отдавать клиентам содержимое определенного каталога, необходимо поместить в него несколько строк:

Path = /var/puppet/files allow *.server.com

Эти две строки указывают на то, что каталог /var/puppet/files должен быть доступен всем хостам домена server.com. Так же мы можем указать полное доменное имя разрешенной машины или ее IP-адрес, а также отрезать неугодных с помощью директивы deny. После этого любой файл этого каталога можно переместить на клиент с помощью ресурса file. Например:

File { "/etc/httpd/conf/httpd.conf": source => "puppet://httpd/httpd.conf", mode => 644, }

Файл httpd.conf, расположенный на сервере в каталоге /var/puppet/files/httpd будет скопирован на целевую машину по пути, указанном в имени ресурса.

Выводы

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

Шла о том, что такое управление конфигурацией и как внедрить эту технологию в свою инфраструктуру.

Примечание : Руководство выполнено на Ubuntu 14.04 и Apache.

Данное руководство поможет подготовить автоматизированную оркестровку сервера с помощью инструмента конфигурационного управления Puppet. Вы ознакомитесь с основными терминами, синтаксисом и функциями Puppet. В результате вы получите полностью автоматизированное простое развёртывание, которое состоит из таких этапов:

  • Обновление индекса пакетов.
  • Установка Apache.
  • Создание пользовательского каталога document root.
  • Создание в нём файла index.html.
  • Применение шаблона для установки пользовательского виртуального хоста.
  • Перезапуск Apache.

Примечание : Данное руководство сосредоточено на создании манифестов – сценариев Puppet для автоматизации настройки. Больше о Puppet можно прочитать в статьях:

Начало работы

Прежде чем приступить к разработке манифеста, нужно ознакомиться с основными терминами Puppet.

Терминология Puppet

  • Мастер Puppet: ведущий сервер, который управляет настройкой нод.
  • Агент Puppet: ведомая нода, которая подчиняется мастеру.
  • Манифест: сценарий оркестровки.
  • Ресурс: фрагмент кода, который определяет необходимые системе изменения.
  • Модуль: группа манифестов и других файлов, организованная заранее определенным образом, которая позволяет облегчить совместное и повторное использование ее отдельных частей оркестровки.
  • Класс: как и в любом обычном языке программирования, классы отвечают за организацию и повторное использование частей оркестровки.
  • Факты: глобальные переменные системы.
  • Сервисы: изменяют статус сервиса (запуск, остановка и т.д.).

Оркестровка Puppet разрабатывается на языке DSL, который основан на Ruby.

Ресурсы

Puppet определяет задачи с помощью ресурсов. Ресурсы могут представлять пакеты, файлы, сервисы, пользователей и команды. Они могут иметь состояние, которое будет приводить к изменению системы в случае, если состояние заявленного ресурса отличается от текущего состояния системы. Например, ресурс package с состоянием installed в манифесте запустит установку пакета, если такой пакет не был установлен ранее. Такой ресурс выглядит так:

package { "apache2":

ensure => "installed"

Ресурс exec позволяет выполнить любую команду:

exec { "apt-get update":

command => ‘/usr/bin/apt-get update’

Обратите внимание: apt-get update в приведённом выше примере является не объявлением команды, а идентификатором ресурса. Часто в Puppet нужно ссылаться на другие ресурсы, и для этого используются их идентификаторы.

Зависимость ресурсов

При написании манифестов важно помнить о том, что Puppet использует ресурсы не в том порядке, в котором они определены. Ресурсы должны явно определять их зависимость друг от друга, в противном случае невозможно понять, в каком порядке будут читаться и выполняться ресурсы, и будут ли они выполнены вообще.

В качестве примера можно привести следующий код; он определяет зависимость ресурса, а уже затем сам ресурс:

package { "python-software-properties":

ensure => "installed"

}
exec { "add-repository":

command => "/usr/bin/add-apt-repository ppa:ondrej/php5 -y"
require => Package["python-software-properties"]

Опция require получает в качестве параметра ссылку на другой ресурс. В данном случае ресурс Package определяется пакетом python-software-properties.

Примечание : Объявления ресурсов начинаются с маленькой буквы (exec, package), а зависимости – с большой (Exec, Package).

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

package { "curl":

ensure => "installed"
before => Exec["install script"]

exec { "install script":

command => "/usr/bin/curl http://example.com/some-script.sh"

Формат манифестов

Манифесты – это наборы ресурсов с расширением.pp. Ниже приведён пример простого манифеста, который выполняет две задачи: обновляет индекс пакетов и устанавливает vim.

exec { "apt-get update":

command => "/usr/bin/apt-get update"

}
package { "vim":

ensure => "installed"
require => Exec["apt-get update"]

Примечание : В конце данного руководства вы найдёте полный код манифеста Puppet.

Написание манифеста

Переменные

Переменные можно определить в любой части манифеста. Наиболее распространёнными типами переменных являются строки и массивы строк, но Puppet поддерживает и другие типы.

Этот код определяет строку переменной, которую в дальнейшем можно использовать в манифесте:

$package = "vim"
package { $package:

ensure => "installed"

Циклы

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

Проще всего определить цикл в Puppet с помощью массива, например:

$packages = ["vim", "git", "curl"]
package { $packages:

ensure => "installed"

С версии 4 Puppet поддерживает дополнительные пути для перебора задач. Приведенный ниже код делает то же самое, что и предыдущий код, но на этот раз используется итератор each. Эта опция упрощает создание циклов ресурсов:

$packages.each |String $package| {
package { $package:

ensure => "installed"

Использование условных выражений

Условные выражения можно использовать для динамической настройки (например, когда на основе переменной или вывода команды нужно решить, следует ли выполнять задачу).

Puppet поддерживает большую часть условных структур традиционных языков программирования (например, выражения if/else и case); кроме того, некоторые ресурсы (например, exec), поддерживают атрибуты, которые работают как условные выражения, но принимают как условие только выходные данные команды.

Допустим, вы хотите выполнить команду, основываясь на факте. В таком случае, чтобы проверить значение переменной, вам необходимо использовать одну из поддерживаемых условных структур поддерживается, например if/else:

if $osfamily != "Debian" {

warning("This manifest is not supported on this OS.")

notify { "Good to go!": }

Также условные выражения часто используются в IT-автоматизации, если выполнение одной команды зависит от вывода другой команды. В таких случаях используются onlyif или unless, как показано в примере ниже. Следующая команда будет выполнена только в том случае, если вывод /bin/which php успешен:

command => "/bin/echo PHP is installed here > /tmp/test.txt",
onlyif => "/bin/which php"

Аналогично, выражение unless выполнит команду, только если команда в unless не была выполнена.

command => "/bin/echo PHP is NOT installed here > /tmp/test.txt",
unless => "/bin/which php"

Использование шаблонов

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

  • Embedded Puppet (EPP): работает только с Puppet 4+.
  • Embedded Ruby (ERB)

Ниже приведён пример шаблона ERB для создания виртуального хоста Apache, в котором используется переменная для создания корневого каталога этого хоста:


ServerAdmin webmaster@localhost
DocumentRoot <%= @doc_root %>
>
AllowOverride All
Require all granted

Чтобы применить шаблон, нужно создать ресурс file, который отображает содержание шаблона с помощью метода template. Чтобы заменить виртуальный хост Apache по умолчанию, используйте такой шаблон:

ensure => "present",
content => template("apache/vhost.erb")

В данном случае Puppet будет искать шаблон vhost.tpl в каталоге apache/templates.

Определение сервисов

Ресурсы сервисов изменяют состояние системного сервиса (например, останавливают или перезапускают его).

Рассмотрим предыдущий пример шаблона, который предназначен для создания виртуального хоста Apache. Чтобы обеспечить перезагрузку Apache после изменения виртуального хоста, нужно создать ресурс сервиса. Это делается так:

service { "apache2":

ensure => running,
enable => true

Чтобы определить ресурс, используйте опцию notify.

file { "/etc/apache2/sites-available/000-default.conf":

ensure => "present",
content => template("vhost.erb"),
notify => Service["apache2"]

Пример манифеста

Теперь можно собрать весь код данного руководства в один манифест, который будет автоматизировать установку Apache в Ubuntu 14.04.

Примечание: Дополненный вариант манифеста можно найти на Github . Также эта папка содержит файл Vagrant, который позволяет протестировать манифест на упрощённой установке с помощью виртуальной машины Vagrant .

$doc_root = "/var/www/example"
exec { "apt-get update":

command => "/usr/bin/apt-get update"

}
package { "apache2":

ensure => "installed",
require => Exec["apt-get update"]

}
file { $doc_root:

ensure => "directory",
owner => "www-data",
group => "www-data",
mode => 644

}
file { "$doc_root/index.html":

ensure => "present",
source => "puppet:///modules/main/index.html",
require => File[$doc_root]

}
file { "/etc/apache2/sites-available/000-default.conf":

ensure => "present",
content => template("main/vhost.erb"),
notify => Service["apache2"],
require => Package["apache2"]

}
service { "apache2":

ensure => running,
enable => true

  • В первой строке находится переменная $doc_root, которая в дальнейшем используется для объявления ресурса.
  • Строки 3-5: ресурс exec выполняет команду apt-get update.
  • Строки 7-10: ресурс package устанавливает пакет apache2, зависит от apt-get update. То есть этот ресурс будет выполнен только если выполнится требуемый ресурс.
  • Строки 12-17: ресурс file создаёт новый корневой каталог. Ресурс file может создавать файлы и каталоги, применять шаблоны и копировать локальные файлы на удалённый сервер. Эта задача может быть выполнена на любом этапе оркестровки, потому ей не нужны зависимости.
  • Строки 19-23: ещё один ресурс file копирует файл index.html в корневой каталог на сервере. Параметр source позволяет Puppet найти исходный файл. Этот код основан на методе обработки локальных файлов в Puppet. В репозитории Github можно найти структуру каталогов, которая позволит Puppet найти этот ресурс. Корневой каталог нужно создать до выполнения этого ресурса, потому здесь применяется опция require.
  • Строки 25-30: этот ресурс file применяет шаблон Apache и перезапускает сервис. В данном примере оркестровка организована с помощью модуля main (потому исходным шаблоном будет main/vhost.erb). Опция require обеспечивает выполнение ресурса только в том случае, если установлен пакет apache2.
  • Строки 32-35: ресурс service перезапускает сервис apache2.

Заключение

Puppet – это производительный инструмент управления конфигурацией, который использует язык DSL для управления ресурсами сервера и автоматизации задач. Этот язык предлагает дополнительные ресурсы, которые обеспечивают гибкость оркестровки.

При работе с Puppet важно помнить, что ресурсы не всегда читаются и выполняются том же порядке, в каком они определены. Будьте очень внимательны, создавая цепочку исполнения.

Tags: ,

Когда число серверов, которыми вы управляете меньше десяти — редко кто задумывается об их централизованном управлении, этого может и не требоваться. Когда серверов десятки — централизованное управление ПО и конфигурациями крайне полезно. Когда серверов сотни и тысячи — это жизненно необходимо. Программ такого рода много, например: Chef, CFEngine, … Вот о последнем и пойдет речь в этой записи.

Puppet по достоинству считается одним из лучших решений в этом роде. Его используют такие компании как Google, Citrix и Red Hat. Это собой клиент-серверное приложение написанное на языке программирования Ruby, которое распространяется в двух вариантах:

  • Puppet Open Source — полностью бесплатная версия
  • Puppet Enterprise — бесплатная в конфигурации до 10 серверов, далее требуется приобретение лицензий

Рассмотрим установку сервера и агента Puppet Open Source, которые присутствует в пакетах большинства современных дистрибутивов. Далее речь пойдет о Ubuntu 12.04 Precise Pangolin.

Серверная часть Puppet называется puppetmaster , начнем установку с нее:

:~# apt-get install puppetmaster

А теперь клиент:

:~# apt-get install puppet

В конфигурационном файле клиента /etc/puppet/puppet.conf необходимо рассказать о сервере, добавив следующую секцию:

Server=puppet.local report=true pluginsync=false

На первоначальном этапе pluginsync лучше выключить.

Запустим клиент puppet чтобы он создал запрос на получение сертификата:

:~# puppetd --verbose --test info: Creating a new SSL key for linux.local info: Caching certificate for ca info: Creating a new SSL certificate request for linux.local info: Certificate Request fingerprint (md5): E5:EA:AC:5B:22:9A:BA:42:B8:A1:63:9E:1F:1F:23:51 Exiting; no certificate found and waitforcert is disabled

На сервере необходимо проверить что запрос сертификата получен и, если это так, выписываем сертификат:

:~# puppetca --list "linux.local" (E5:EA:AC:5B:22:9A:BA:42:B8:A1:63:9E:1F:1F:23:51) :~# puppetca --sign linux.local notice: Signed certificate request for linux.local notice: Removing file Puppet::SSL::CertificateRequest linux.local at "/var/lib/puppet/ssl/ca/requests/linux.local.pem"

Повторяем предыдущий шаг на клиенте:

:~# puppetd --verbose --test info: Caching certificate for linux.local info: Retrieving plugin info: Caching certificate_revocation_list for ca info: Caching catalog for linux.local info: Applying configuration version "1356278451" info: Creating state file /var/lib/puppet/state/state.yaml notice: Finished catalog run in 0.02 seconds

Отлично, все работает. Переходим к созданию первого манифеста. Манифесты, они же конфигурации описываются на специальном декларативном языке. Будем сразу приучаться к хорошему, использовать модульную структуру и классы. Для примера напишем модуль который будет поддерживать в актуальном виде файл /etc/hosts на всех наших серверах.

Проверим, где puppet ищет модули:

:~# puppet apply --configprint modulepath /etc/puppet/modules:/usr/share/puppet/modules

Создаем каталоги для своего модуля

:~# cd /etc/puppet/modules :~# mkdir hosts; cd hosts; mkdir manifests; cd manifests

Первый манифест, он же основной файл модуля — должен называться init.pp

Class hosts { # puppet.local host { "puppet.local": ensure => "present", target => "/etc/hosts", ip => "192.168.0.1", host_aliases => "puppet", } # linux.local host { "linux.local": ensure => "present", target => "/etc/hosts", ip => "192.168.0.2", host_aliases => "linux", } }

По-умолчанию puppet ищет файл /etc/puppet/manifests/site.pp чтобы загрузить конфигурацию, приведем его к следующему виду:

Node default { include hosts }

Проверяем манифест на сервере:

:~# puppet apply --verbose /etc/puppet/manifests/site.pp info: Applying configuration version "1356281036" notice: /Stage//Host/ensure: created info: FileBucket adding {md5}notice: /Stage//Host/ensure: created notice: Finished catalog run in 0.03 seconds

На клиенте:

:~# ll /etc/hosts rw-r--r-- 1 root root 290 Dec 16 19:10 /etc/hosts :~# puppetd --verbose --test info: Caching catalog for linux.local info: Applying configuration version "1356283380" info: FileBucket adding {md5}notice: /Stage/Hosts/Host/ensure: created notice: /Stage/Hosts/Host/ensure: created notice: Finished catalog run in 0.04 seconds :~# ll /etc/hosts -rw-r--r-- 1 root root 551 Dec 23 20:43 /etc/hosts

После того как мы убедились что все работает, разрешаем запуск службы, в /etc/default/puppet меняем:

# Start puppet on boot? START=yes

Запускаем службу

:~# service puppet start

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

  • Ruby
    • Tutorial

    Здравствуйте.

    Этот топик открывает цикл статей по использованию системы управления конфигурацией Puppet .

    Что такое система управления конфигурацией?

    Предположим, что у вас есть парк серверов, выполняющих различные задачи. Пока серверов мало и вы не растёте, вы легко настраиваете каждый сервер вручную. Устанавливаете ОС (может быть, автоматизированно), добавляете пользователей, устанавливаете софт, вводя команды в консоль, настраиваете сервисы, правите конфиги ваших любимых текстовых редакторов (nanorc, vimrc), выставляете на них одинаковые настройки DNS-сервера, устанавливаете агент системы мониторинга, настраиваете syslog для централизованного сбора логов… Словом, работы довольно много и она не особенно интересна.

    Я искренне верю, что хороший админ - ленивый админ. Он не любит делать что-то несколько раз. Первая мысль - написать пару скриптов, в котором будет что-то наподобие:

    Servers.sh
    servers="server00 server01 server02 server03 server04" for server in $servers ; do scp /path/to/job/file/job.sh $server:/tmp/job.sh ssh $server sh /tmp/job.sh done

    Job.sh
    #!/bin/bash apt-get update apt-get install nginx service nginx start

    Вроде всё стало легко и хорошо. Нужно что-то сделать - пишем новый скрипт, запускаем. Изменения приходят на все серверы последовательно. Если скрипт хорошо отлажен - всё станет хорошо. До поры.

    Теперь представьте, что серверов стало больше. Например, сотня. А изменение долгое - например, сборка чего-нибудь большого и страшного (например, ядра) из исходников. Скрипт будет выполняться сто лет, но это полбеды.

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

    Самое плохое - это то, что в подобных скриптах вы описываете действия , которые необходимо выполнить для приведения системы в определенное состояние, а не само это состояние. Значит, если система изначально находилась не в том состоянии, что вы предполагали, то всё обязательно пойдет не так. Манифесты Puppet декларативно описывают необходимое состояние системы, а вычисление, как к нему прийти из текущего состояния - задача самой системы управления конфигурацией.

    Для сравнения: манифест puppet, выполняющий ту же работу, что и пара скриптов из начала топика:

    Nginx.pp
    class nginx { package { "nginx": ensure => latest } service { "nginx": ensure => running, enable => true, require => Package["nginx"] } } node /^server(\d+)$/ { include nginx }
    Если правильно использовать серверы и потратить некоторое время на первичную настройку системы управления конфигурацией, можно добиться такого состояния парка серверов, что вам не потребуется логиниться на них для выполнения работы. Все необходимые изменения будут приходить к ним автоматически.

    Что такое Puppet?

    Puppet - система управления конфигурацией. Архитектура - клиент-серверная, на сервере хранятся конфиги (в терминах puppet они называются манифесты ), клиенты обращаются к серверу, получают их и применяют. Puppet написан на языке Ruby, сами манифесты пишутся на особом DSL, очень похожем на сам Ruby.

    Первые шаги

    Давайте забудем о клиентах, серверах, их взаимодействии и т.п. Пусть у нас есть только один сервер, на котором установлена голая ОС (здесь и далее я работаю в Ubuntu 12.04, для других систем действия будут несколько отличаться).

    Сначала установим puppet последней версии.

    Wget http://apt.puppetlabs.com/puppetlabs-release-precise.deb dpkg -i puppetlabs-release-precise.deb apt-get update apt-get install puppet puppetmaster

    Замечательно. Теперь у нас в системе установлен puppet и с ним можно играть.

    Hello, world!
    Создадим первый манифест:

    /tmp/helloworld.pp
    file { "/tmp/helloworld": ensure => present, content => "Hello, world!", mode => 0644, owner => "root", group => "root" }
    И применим его:

    $ puppet apply helloworld.pp /Stage//File/ensure: created Finished catalog run in 0.06 seconds

    Немного о запуске

    Манифесты, приведённые в этом топике можно применять вручную с помощью puppet apply. Тем не менее, в последующих топиках для работы будет использоваться master-slave конфигурация (стандартная для Puppet).


    Теперь посмотрите на содержимое файла /tmp/helloworld. В нём окажется (удивительно!) строка «Hello, world!», которую мы задали в манифесте.

    Вы можете сказать, что можно было сделать echo "Hello, world!" > /tmp/helloworld , это было бы быстрее, проще, не пришлось бы думать, писать какие-то страшные манифесты и вообще это нафиг никому не нужно это как-то слишком сложно, но задумайтесь серьезнее. На самом деле, необходимо было бы написать touch /tmp/helloworld && echo "Hello, world!" > /tmp/helloworld && chmod 644 /tmp/helloworld && chown root /tmp/helloworld && chgrp root /tmp/helloworld , чтобы гарантированно добиться того же результата.

    Давайте по строкам разберём, что именно содержится в нашем манифесте:

    /tmp/helloworld.pp
    file { "/tmp/helloworld": ensure => present, # файл должен существовать content => "Hello, world!", # содержимым файла должна являться строка "Hello, world!" mode => 0644, # права на файл - 0644 owner => "root", # владелец файла - root group => "root" # группа файла - root }

    В терминах Puppet здесь описан ресурс типа файл с названием (title) /tmp/helloworld .

    Ресурсы
    Ресурс - это самая мелкая единица абстракции в Puppet. Ресурсами могут быть:
    • файлы;
    • пакеты (Puppet поддерживает пакетные системы многих дистрибутивов);
    • сервисы;
    • пользователи;
    • группы;
    • задачи cron;
    • и т. д.
    Синтаксис ресурсов вы можете невозбранно подсмотреть .

    В Puppet есть возможность добавлять свои ресурсы. Поэтому если хорошенько заморочиться, можно докатиться до манифестов наподобие:

    Webserver.pp
    include webserver; webserver::vhost { "example.com": ensure => present, size => "1G", php => false, https => true }
    Puppet при этом будет создавать logical volume размером в 1 ГиБ на сервере, монтировать его куда положено (например в /var/www/example.com), добавлять нужные записи в fstab, создавать нужные виртуальные хосты в nginx и apache, рестартовать оба демона, добавлять в ftp и sftp пользователя example.com с паролем mySuperSecretPassWord с доступом на запись в этот виртуальный хост.

    Вкусно? Не то слово!

    Причем, самое вкусное, на мой взгляд - это не автоматизация рутины. Если вы например, идиот, и постоянно пересетапливаете ваши серверы в продакшне, Puppet позволит подхватить старый любовно созданный набор пакетов и конфигов с нуля в полностью автоматическом режиме. Вы просто устанавливаете Puppet-агент, подключаете его к вашему Puppet-мастеру и ждёте. Всё придёт само. На сервере волшебным (нет, правда волшебным!) образом появятся пакеты, разложатся ваши ssh-ключи, установится фаервол, придут индивидуальные настройки bash, сети, установится и настроится весь софт, который вы предусмотрительно ставили с помощью Puppet.
    Кроме того, Puppet при старании позволяет получить самодокументируемую систему, ибо конфигурация (манифесты) сами же являются костяком документации. Они всегда актуальны (они же работают уже), в них нет ошибок (вы же проверяете свои настройки перед запуском), они минимально подробны (работает же).

    Ещё немного магии

    Немного о кроссдистрибутивности

    В Puppet есть возможность использовать кроссдистрибутивные манифесты, это одна из целей, для которых он создавался. Я намеренно никогда не пользовался этим и вам не рекомендую. Парк серверов должен быть максимально гомогенным в плане системного ПО, это позволяет не думать в критические моменты «айблин, тут
    rc.d, а не init.d» (реверанс в сторону ArchLinux) и вообще позволяет меньше думать на рутинных задачах.

    Многие ресурсы зависят от других ресурсов. Например, для ресурса «сервис sshd» необходим ресурс «пакет sshd» и опционально «конфиг sshd»
    Посмотрим, как это реализуется: file { "sshd_config": path => "/etc/ssh/sshd_config", ensure => file, content => "Port 22 Protocol 2 HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_dsa_key HostKey /etc/ssh/ssh_host_ecdsa_key UsePrivilegeSeparation yes KeyRegenerationInterval 3600 ServerKeyBits 768 SyslogFacility AUTH LogLevel INFO LoginGraceTime 120 PermitRootLogin yes StrictModes yes RSAAuthentication yes PubkeyAuthentication yes IgnoreRhosts yes RhostsRSAAuthentication no HostbasedAuthentication no PermitEmptyPasswords no ChallengeResponseAuthentication no X11Forwarding yes X11DisplayOffset 10 PrintMotd no PrintLastLog yes TCPKeepAlive yes AcceptEnv LANG LC_* Subsystem sftp /usr/lib/openssh/sftp-server UsePAM yes", mode => 0644, owner => root, group => root, require => Package["sshd"] } package { "sshd": ensure => latest, name => "openssh-server" } service { "sshd": ensure => running, enable => true, name => "ssh" subscribe => File["sshd_config"], require => Package["sshd"] }

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

    Самые вкусные строчки здесь - это строчки зависимостей - require и subscribe.

    Puppet поддерживает много вариантов описания зависимостей. Подробно, как всегда, можно прочитать в



    Есть вопросы?

    Сообщить об опечатке

    Текст, который будет отправлен нашим редакторам: