Как удалить все сертификаты puppet. Master of puppets: Установка и настройка системы удаленного управления конфигурацией Puppet. Использование модуля в главном манифесте


Автор: 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 очень прост в настройке и сопровождении, тем более что в сети можно найти массу примеров его конфигурации.

  • 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 поддерживает много вариантов описания зависимостей. Подробно, как всегда, можно прочитать в

    Статья написана в журнале Системный администратор

    World Revolution

    Управление множеством Unix систем нельзя называть комфортабельным. Для конфигурации 1-го параметра администратору приходится обращаться к каждой машине, скрипты только частично могут помочь, ну и не во всех ситуациях.

    Следует признать, что администраторы Windows сетей находятся все-таки в более успешном положении. Достаточно поменять функции групповых политик и через некоторое время все компютеры сети, в том числе и с не так издавна установленной операционной системой “выяснят” о нововведении, если они их естественно касаются.

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

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

    Например Cfengine не очень пользуется популярностью у администраторов, хотя не считая Linux, может употребляться в *BSD, Windows и Mac OS X. Может быть это связано с относительной сложностью в разработке конфигураций. При описании заданий приходится учитывать особенности каждой определенной системы, и вручную контролировать последовательность действий при выполнении команд.

    Другими словами администратор должен держать в голове, что для одних систем следует писать adduser для других useradd, учитывать размещение файлов в разных системах, и т.д.. Это на порядок усложняет процесс написания команд, с ходу сделать правильную конфигурацию очень тяжело, а изготовленные конфигурации прочитать через некоторое время практически не реально.

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

    Чтобы улучшить cfengine сторонними разработчиками были изготовлены различные дополнения, что часто только ухудшало ситуацию. Создатель нескольких таких модулей к cfengine Люке Каниес (Luke Kanies) в итоге решил сделать похожий инструмент, но лишенный многих недостатков cfengine.

    Возможности Puppet

    Puppet как и cfengine является клиент-серверной системой использующей декларативный, другими словами неотклонимый для выполнения язык для описания задач и библиотеки для их реализации. Клиенты периодически (по умолчанию 30 минут) соединяются с центральным сервером и получают последнюю конфигурацию.

    Если обретенные функции не совпадают с системным состоянием, они будут выполнены, при необходимости серверу отсылается отчет о изготовленных операциях. Сервер сообщения может сохранить в syslog или файл, сделать RRD график, отослать на обозначенный e-mail.

    Дополнительные уровни абстракции Transactional и Resource обепечивают наивысшую сопоставимость с существующими опциями и приложениями, позволяя сфокусироваться на системных объектах, не заботясь о различиях в реализации и описании подробных команд и форматах файлов. Администратор оперирует только с типом объекта, остальное Puppet берет на себя. Так тип packages знает о Семнадцать пакетных системах, подходящая автоматом будет распознана на основании инфы о версии дистрибутива или системы, хотя при необходимости пакетный менеджер можно задать принудительно.

    В отличие от скриптов, которые часто не может быть использовать в других системах, конфигурации Puppet написанные сторонними администраторами будут в большинстве без заморочек работать в хоть какой другой сети. В Puppet CookBook уже имеется три 10-ка готовых рецептов. В настоящее время Puppet официально поддерживает следующие операционные системы и сервисы: Debian, RedHat/Fedora, Solaris, SUSE, CentOS, Mac OS X, OpenBSD, Gentoo и MySQL, LDAP.

    Язык Puppet

    Чтобы идти дальше, поначалу следует разобраться с основными элементами и возможностями языка. Язык это одна из сильных сторон Puppet. С его помощью описываются ресурсы которыми администратор планирует управлять и деяния.

    В отличие от большинства похожих решений, в Puppet язык позволяет упростить обращение ко всем схожим ресурсам на хоть какой системе в гетерогенной среде. Описание ресурса, обычно, состоит из наименования, типа и атрибутов. Например укажем на файл /etc/passwd и установим его атрибуты:

    file { «/etc/passwd»:

    owner => root,

    group => root,

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

    А что делать если конфигурационный файл используемый на сервере отличается от клиентских или вообще не употребляется? Например такая ситуация может показаться при настройках VPN соединений. В этом случае следует на файл можно указать директивой source.

    Здесь два варианта, как обычно указать путь к другому файлу, также поддерживается два URI протокола: file и puppet. В первом случае употребляется ссылка на внешний NFS сервер, во втором варианте на сервере Puppet, запускается NFS похожий сервис, который и экспортирует ресурсы.

    В последнем случае по умолчанию путь указывается относительно корневого каталога puppet - /etc/puppet. Другими словами ссылка puppet://server.domain.com/config/sshd_config будет соответствовать файлу /etc/puppet/config/sshd_config.

    Переопределить этот каталог, можно с помощью директивы filebucket, хотя более правильно использовать одноименную секцию в файле /etc/puppet/fileserver.conf. В этом случае можно ограничить доступ к сервису только с определенных адресов. Например опишем секцию config.

    path /var/puppet/config

    allow *.domain.com

    allow 192.168.0.*

    allow 192.168.1.0/24

    deny *.wireless.domain.com

    А позже обращаемся к этой секции при описании ресурса.

    source => «puppet://server.domain.com/config/sshd_config»

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

    file { «/etc/passwd»:

    alias => passwd

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

    file { sshdconfig:

    name => $operatingsystem ? {

    solaris => «/usr/local/etc/ssh/sshd_config»,

    default => «/etc/ssh/sshd_config»

    В этом примере мы столкнулись с возможностью выбора. Раздельно указан файл для Solaris, для всех других будет избран файл /etc/ssh/sshd_config. На данный момент к этому ресурсу можно обращаться как к sshdconfig, зависимо от операционной системы будет избран подходящий путь.

    Например укажем, что в случае если бес sshd запущен и получен новый файл, следует перезапустить сервис.

    ensure => true,

    subscribe => File

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

    $homeroot = «/home»

    На данный момент к файлам определенного пользователя можно обратиться как

    ${homeroot}/$name

    В параметр $name будет подставлено учетное имя пользователя. В некоторых случаях комфортабельно отыскать значение по умолчанию для некоторого типа. Например для типа exec очень часто указывают сборники в каких он должен отыскивать исполняемый файл:

    Exec { path => «/usr/bin:/bin:/usr/sbin:/sbin» }

    В том случе если нужно указать на несколько вложенных файлов и каталогов, можно использовать параметр recurse.

    file { «/etc/apache2/conf.d»:

    source => «puppet:// puppet://server.domain.com/config/apache/conf.d»,

    recurse => «true»

    Несколько ресурсов могут быть объеденены в классы или определения. Классы являются законченным описанием системы или сервиса и употребляются обособленно.

    «/etc/passwd»: owner => root, group => root, mode => 644;

    «/etc/shadow»: owner => root, group => root, mode => 440

    Как и в объектно-ориентированных языках классы могут переопределяться. Например в FreeBSD группой-владельцем этих файлов является wheel. Поэтому чтобы не переписывать ресурс полностью, создадим новый класс freebsd, который будет наследовать класс linux:

    class freebsd inherits linux {

    File["/etc/passwd"] { group => wheel };

    File["/etc/shadow"] { group => wheel }

    Для удобства все классы можно вынести в отдельный файл, который подключать директивой include. Определения могут принимать многочисленные свойства в качестве аргументов, но не поддерживают наследования и употребляются в данном случае если нужно описать не один раз используемые объекты. Например определим домашний каталог юзеров и команды нужные для сотворения новой учетной записи.

    define user_homedir ($group, $fullname, $ingroups) {

    user { «$name»:

    ensure => present,

    comment => «$fullname»,

    gid => «$group»,

    groups => $ingroups,

    membership => minimum,

    shell => «/bin/bash»,

    home => «/home/$name»,

    require => Group[$group],

    exec { «$name homedir»:

    command => «/bin/cp -R /etc/skel /home/$name; /bin/chown -R $name:$group /home/$name»,

    Сергей Яремчук

    Централизованная настройка UNIX-систем с помощью Puppet

    Управление большим количеством UNIX-систем нельзя назвать удобным. Для изменения одного параметра администратору приходится обращаться к каждой машине, скрипты лишь частично могут помочь, да и не во всех ситуациях.

    Следует признать, что администраторы Windows-сетей находятся все-таки в более выгодном положении. Достаточно изменить настройки групповых политик, и через некоторое время все компьютеры сети, в том числе и с недавно установленной операционной системой, «узнают» о нововведении, если они их, конечно, касаются. Оглянувшись на долгий период развития UNIX, можно заметить, что ничего подобного так и не прижилось. Есть решения вроде kickstart, которые помогают при первичной установке операционной системы, но дальнейшая доводка потребует значительных усилий. Коммерческие решения, вроде BladeLogic и OpsWare , проблему автоматизации настроек решают лишь отчасти, основное их достоинство – наличие графического интерфейса, да и позволить их приобрести могут только крупные организации. Есть, конечно, и проекты, предлагающие свободные решения, но за все время своего существования они так и не смогли создать большого сообщества. Например, Cfengine не очень пользуется популярностью уадминистраторов, хотя, кроме Linux, может использоваться в *BSD, Windows и Mac OS X. Возможно, это связано с относительной сложностью в создании конфигураций. Приописании заданий приходится учитывать особенности каждой конкретной системы и вручную контролировать последовательность действий при выполнении команд. То есть администратор должен помнить, что для одних систем следует писать adduser для других – useradd, учитывать расположение файлов в разных системах и так далее. Это на порядок усложняет процесс написания команд, с ходу создать правильную конфигурацию очень сложно, а созданные конфигурации прочитать через некоторое время практически нереально. Несмотря на GPL-лицензию Cfengine, фактически проект одного человека, который контролирует все изменения и не очень заинтересован в построении открытого общества. В результате возможности Cfengine вполне удовлетворяют разработчика, а для остальных администраторов это скорее лишняя головная боль. Чтобы улучшить Cfengine, сторонними разработчиками были созданы различные дополнения, что часто только ухудшало ситуацию. Автор нескольких таких модулей к Cfengine Люке Каниес (Luke Kanies) витоге решил разработать подобный инструмент, но лишенный многих недостатков Cfengine.

    Возможности Puppet

    Puppet , как и Cfengine, является клиент-серверной системой, использующей декларативный, то есть обязательный для выполнения язык для описания задач и библиотеки дляихреализации. Клиенты периодически (по умолчанию каждые 30 минут) соединяются с центральным сервером и получают последнюю конфигурацию. Если полученные настройки не совпадают с системным состоянием, они будут выполнены, при необходимости серверу отсылается отчет о произведенных операциях. Сервер сообщения может сохранить вsyslog или файл, создать RRD-график, отослать на указанный e-mail. Дополнительные уровни абстракции Transactional и Resource обеспечивают максимальную совместимость ссуществующими настройками и приложениями, позволяя сфокусироваться на системных объектах, не заботясь о различиях в реализации и описании подробных команд иформатах файлов. Администратор оперирует лишь с типом объекта, остальное Puppet берет на себя. Так, тип packages знает о 17 пакетных системах, нужная автоматически будет распознана на основании информации о версии дистрибутива или системы, хотя при необходимости пакетный менеджер можно задать принудительно.

    В отличие от скриптов, которые часто невозможно использовать в других системах, конфигурации Puppet, написанные сторонними администраторами, будут в большинстве безпроблем работать в любой другой сети. В Puppet CookBook уже имеется три десятка готовых рецептов. В настоящее время Puppet официально поддерживает следующие операционные системы и сервисы: Debian, RedHat/Fedora, Solaris, SUSE, CentOS, Mac OS X, OpenBSD, Gentoo и MySQL, LDAP.

    Язык Puppet

    Чтобы идти дальше, вначале следует разобраться с основными элементами и возможностями языка. Язык – это одна из сильных сторон Puppet. С его помощью описываются ресурсы, которыми администратор планирует управлять, и действия. В отличие от большинства подобных решений, в Puppet язык позволяет упростить обращение ко всем схожим ресурсам на любой системе в гетерогенной среде. Описание ресурса, как правило, состоит из названия, типа и атрибутов. Например, укажем на файл /etc/passwd и установим его атрибуты:

    file { "/etc/passwd":

    Owner => root,

    Group => root,

    Mode => 644,

    Теперь клиенты, подключившись к серверу, скопируют файл /etc/passwd и установят указанные атрибуты. В одном правиле можно определять сразу несколько ресурсов, разделяя их с помощью точки с запятой. А что делать, если конфигурационный файл, используемый на сервере, отличается от клиентских или вообще не используется? Например, такая ситуация может возникнуть при настройках VPN-соединений. В этом случае следует указать на файл директивой source. Здесь два варианта, можно, как обычно указать путь кдругому файлу, а также с помощью поддерживающихся двух URI протоколов: file и puppet. В первом случае используется ссылка на внешний NFS-сервер, во втором варианте насервере Puppet запускается NFS-подобный сервис, который и экспортирует ресурсы. В последнем случае по умолчанию путь указывается относительно корневого каталога puppet– /etc/puppet. То есть ссылка puppet://server.domain.com/config/sshd_config будет соответствовать файлу /etc/puppet/config/sshd_config. Переопределить этот каталог можно спомощью директивы filebucket, хотя более правильно использовать одноименную секцию в файле /etc/puppet/fileserver.conf. В этом случае можно ограничить доступ к сервису только сопределенных адресов. Например, опишем секцию config:

    Path /var/puppet/config

    Allow *.domain.com

    Allow 127.0.0.1

    Allow 192.168.0.*

    Allow 192.168.1.0/24

    Deny *.wireless.domain.com

    А затем обращаемся к этой секции при описании ресурса:

    source => "puppet://server.domain.com/config/sshd_config"

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

    file { "/etc/passwd":

    Alias => passwd

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

    file { sshdconfig:

    Name => $operatingsystem ? {

    Solaris => "/usr/local/etc/ssh/sshd_config",

    Default => "/etc/ssh/sshd_config"

    В этом примере мы столкнулись с возможностью выбора. Отдельно указан файл для Solaris, для всех остальных будет выбран файл /etc/ssh/sshd_config. Теперь к этому ресурсу можно обращаться как к sshdconfig, в зависимости от операционной системы будет выбран нужный путь. Например, укажем, что в случае, если демон sshd запущен и получен новый файл, следует перезапустить сервис:

    service { sshd:

    Ensure => true,

    Subscribe => File

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

    $homeroot = "/home"

    Теперь к файлам конкретного пользователя можно обратиться как:

    ${homeroot}/$name

    В параметр $name будет подставлено учетное имя пользователя. В некоторых случаях удобно определить значение по умолчанию для некоторого типа. Например, для типа exec очень часто указывают каталоги, в которых он должен искать исполняемый файл:

    Exec { path => "/usr/bin:/bin:/usr/sbin:/sbin" }

    В том случае, если нужно указать на несколько вложенных файлов и каталогов, можно использовать параметр recurse:

    file { "/etc/apache2/conf.d":

    Source => "puppet:// puppet://server.domain.com/config/apache/conf.d",

    Recurse => "true"

    Несколько ресурсов могут быть объединены в классы или определения. Классы являются законченным описанием системы или сервиса и используются обособленно:

    class linux {

    File {

    "/etc/passwd": owner => root, group => root, mode => 644;

    "/etc/shadow": owner => root, group => root, mode => 440

    Как и в объектно-ориентированных языках, классы могут переопределяться. Например, в FreeBSD группой-владельцем этих файлов является wheel. Поэтому, чтобы не переписывать ресурс полностью, создадим новый класс freebsd, который будет наследовать класс linux:

    class freebsd inherits linux {

    File["/etc/passwd"] { group => wheel };

    File["/etc/shadow"] { group => wheel }

    Для удобства все классы можно вынести в отдельный файл, который нужно подключать директивой include. Определения могут принимать многочисленные параметры в качестве аргументов, но не поддерживают наследования и используются в том случае, если нужно описать многократно используемые объекты. Например, определим домашний каталог пользователей и команды, необходимые для создания новой учетной записи:

    define user_homedir ($group, $fullname, $ingroups) {

    User { "$name":

    Ensure => present,

    Comment => "$fullname",

    Gid => "$group",

    Groups => $ingroups,

    Membership => minimum,

    Shell => "/bin/bash",

    Home => "/home/$name",

    Require => Group[$group],

    Exec { "$name homedir":

    Command => "/bin/cp -R /etc/skel /home/$name; /bin/chown -R $name:$group /home/$name",

    Creates => "/home/$name",

    Require => User[$name],

    Теперь, чтобы создать новую учетную запись, достаточно обратиться к user_homedir:

    user_homedir { "sergej":

    Group => "sergej",

    Fullname => "Sergej Jaremchuk",

    Ingroups => ["media", " admin]

    Отдельно стоят описания узлов (node), которые поддерживают наследование, как и классы. При подключении клиента к серверу Puppet будет произведен поиск соответствующей секции node и выданы специфические только для этого компьютера настройки. Для описания всех остальных систем можно использовать node default. Описание всех типов приведено в документе «Type Reference», с которым необходимо ознакомиться в любом случае, хотя бы для того, чтобы понять все возможности языка Puppet. Различные типы позволяют выполнять указанные команды, в том числе и при выполнении определенных условий (например, изменение конфигурационного файла), работать с cron, учетными данными и группами пользователей, компьютерами, монтированием ресурсов, запуском и остановкой сервисов, установкой, обновлением и удалением пакетов, работой с SSH-ключами, зонами Solaris и так далее. Вот так просто можно заставить обновлять список пакетов в дистрибутивах, использующих apt, ежедневно между 2 и 4 часами:

    schedule { daily:

    Period => daily,

    Range =>

    exec { "/usr/bin/apt-get update":

    Schedule => daily

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

    Установка Puppet

    Для работы Puppet потребуются Ruby (начиная с версии 1.8.1 и выше) с поддержкой OpenSSL и библиотеками XMLRPC, а также библиотека Faster . В репозитарии Ubuntu 7.04, который использовался при тестовой установке, уже включен пакет puppy:

    $ sudo apt-cache search puppet

    ~$ ruby -rxmlrpc/client -e "puts:yep"

    yep

    Если не получено ошибок, значит, все необходимое уже включено. Файлы, в которых описывается желательная конфигурация систем, в терминологии Puppet называются манифестами (manifests). При запуске демон пытается прочитать файл /etc/puppet/manifests/site.pp, при его отсутствии выдает предупреждающее сообщение. При тестировании можно указать демону на работу в автономном режиме, при котором манифест не требуется:

    $ sudo /usr/bin/puppetmasterd --nonodes

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

    class sudo {

    File { "/etc/sudoers":

    Owner => root,

    Group => root,

    Mode => 440,

    node default {

    Include sudo

    Все конфигурационные файлы, как сервера так и клиентов, расположены в /etc/puppet. Файл fileserver.conf, о котором мы уже говорили, не обязателен и используется только в том случае, когда Puppet будет работать еще и как файл-сервер. В Ubuntu в этом файле экспортируется подкаталог /etc/puppet/files. В подкаталоге ssl расположены сертификаты и ключи, которые будут использоваться для шифрования при подключениях клиентов. Ключи создаются автоматически при первом запуске puppetmasterd, вручную их можно создать командой:

    $ sudo /usr/bin/puppetmasterd --mkusers

    Файлы puppetd.conf и puppetmasterd.conf похожи. В них указываются некоторые параметры работы демонов на клиентской системе и сервере. Клиентский файл отличается только наличием параметра server, указывающего на компьютер, на котором запущен puppetmasterd:

    server = grinder.com

    logdir = /var/log/puppet

    vardir = /var/lib/puppet

    rundir = /var/run

    # отсылаем отчет серверу

    report = true

    Чтобы не печатать все вручную, можно создать шаблон с помощью самого puppetd:

    $ puppetd --genconfig > /etc/puppet/puppetd.conf

    Аналогично можно создать и site.pp на сервере:

    $ puppetd --genmanifest > /etc/puppet/manifests/site.pp

    Еще один файл tagmail.conf, позволяет указать почтовые адреса, на которые будут отсылаться отчеты. В простейшем случае можно использовать одну строку:

    all: [email protected]

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

    Сначала, чтобы сервер узнал о новом компьютере, на клиентской системе вводим команду:

    $ sudo puppetd --server grinder.com --waitforcert 60 –test

    Межсетевой экран должен разрешать соединения на порт 8140.

    На сервере получаем список сертификатов, нуждающихся в подписи:

    $ sudo puppetca –list

    nomad.grinder.com

    И подписываем сертификат клиента:

    $ sudo puppetca –sign nomad.grinder.com

    Теперь клиент может свободно подключаться к серверу и получать настройки.

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

    Удачи!

    1. Сайт проекта BladeLogic – http://www.bladelogic.com .
    2. Сайт проекта OpsWare – http://www.opsware.com .
    3. Сайт проекта Cfengine – http://www.cfengine.org .
    4. Сайт проекта Puppet – http://reductivelabs.com/projects/puppet .
    5. Puppet CookBook – http://www.reductivelabs.com/trac/puppet/tagspuppet%2Crecipe .
    6. Библиотека Faster –