![](http://webcf.waybackmachine.org/web/20200109154055im_/https://habrastorage.org/getpro/habr/avatars/ab8/83a/de1/ab883ade1fba2eae8966c9e0e566bd4a.png)
В разрезе: новостной агрегатор на Android с бэкендом. Система контроля конфигураций (Puppet)
Вводная часть (со ссылками на все статьи)
В ITIL (v3) среди описанных процессов есть 2 особенно интересных: «Процесс управления конфигурациями» и «Процесс управления изменениями», предназначенных для анализа и управления изменениями конфигураций систем. Для продолжения повествования нужно определиться, что такое «система». В это понятие входит огромное количество составляющих, влияющих (прямо или косвенно) на предоставление услуги:
Пытаться минимизировать контур системы вашего проекта (тип, резервное копирование не относится к функционированию системы) – значит рыть себе яму, в которую рано или поздно вы провалитесь.
Этот перечень компонентов системы — минимум для большинства проектов, развёрнутых более чем на одном сервере (да даже и на одном). При этом их количество по мере развития проекта меняется и растёт. При отсутствии какого-либо процесса их учёта становится очевидно к чему это приводит: вы имеете тестовый стенд (или стэнд разработки) на котором всё работает идеально, но попытка продублировать его на продуктиве или создать новый стенд приводит к:
В итоге — среда для корректной работы вашего продукта выход из-под вашего контроля и имеющихся средств автоматизации и версионности.
Вещи вроде очевидные, но в большинстве групп по разработке на них закрываются глаза – многие аргументируют это тем, что сервер у них один, настроек мало, компетентностью работников (аргумент «у нас работают профессионалы и никуда уходить не собираются» меня просто свалил), малыми рисками и т.д. и т.п.
Несмотря на кажущуюся сложность и избыточность того, что описано в ITIL (там реально много всего написано) в первую очередь из него брать надо брать требования по автоматизации указанных процессов. Автоматизация сборки, автоматизация тестирования, автоматизация поиска уязвимости – всё это внедрено и рассматривается всеми как необходимый минимум при разработке. Автоматизация ускоряет процесс, вселяет уверенность, обеспечивает прозрачность и гарантированный результат, а так же снимает страх у исполнителей за сроки и результат.
С учётом мощной вводной части в предыдущем абзаце преимущества для разработчика-одиночки опишу доступнее и более кратко:
Не старайтесь брать, из описанных в ITIL процессов, все шаги которые там описаны, — ситуация будет хуже, чем до этого! Я знаю, как подобные шаги внедряются в некоторыъ банковских системах и к чему это приводит (особенно без автоматизации) – бюрократическая машина удушит любой динамично развивающийся проект/систему.
В моём случае был выбран Puppet. При выборе между Chef и Ansible, выбор в пользу него был сделан с учётом хорошей документационной базы, хорошей поддержки, достаточно большого количества модулей (от разработчиков и сообщества), активного развития проекта и реализацией на Ruby (который более-менее мне знаком).
Откровенно говоря, кривая изучения для Puppet была вовсе не пологой. В связи с тем, что в разрабатываемой системе используется большое количество всяких элементов, каждый из них может быть настроен по-разному и всё это может быть развёрнуто на разных стендах – изучение инструмента потребовалось полное и тщательное. По мере изучения инструмента стали очевидны и некоторые его минусы (в большинстве случаев «by-design») и ограничения (хорошая статья о философии Puppet, поясняющая некоторые архитектурные решения). Так же по мере изучения и уже частичной реализации необходимых скриптов чуть больше узнал про Ansible в котором решены некоторые проблемы, имеющиеся в Puppet (что не отменят возможности наличия своих проблем, отсутствующих в Puppet). Так, что последующее повествование это не реклама Puppet, а описание возможностей и опыта использования.
Puppet использует свой собственный конфигурационный язык (DSL), который был разработан что бы быть доступным для системных администраторов. Язык Puppet позиционируется как не требующий формального знания программирования и его синтаксис был сформирован под влияние формата конфигурационных файлов Nagios.
Основная цель языка Puppet – определение ресурсов (ресурсы в Puppet – файлы, каталоги, службы, лимиты, брандмауэры, пользователи и т.д.). Все другие части языка существуют лишь для добавления гибкости и удобства в том, как определяются ресурсы.
Группы ресурсов могут быть организованы в классы, которые являются более крупными единицами конфигурации. В то время как ресурс может описывать единственный файл/каталог или пакет, класс может описывать всё, что нужно для конфигурирования службы или приложения (включая необходимое количество пакетов, конфигурационных файлов, демонов/служб и задач обслуживания). Более маленькие классы могут объединяться в крупные, которые описывают целую системную роль – «сервер базы данных» или «рабочий узел кластера».
Пример класса с ресурсами внутри:
Машины, которые выполняют разные роли должны, в общем случае, получить разный набор классов. Задача конфигурирования того, какие классы будут применены на какие машины – задача узлов Puppet.
Примеры определения узлов Puppet:
Факты и база данных Hiera. Перед тем как выполнить код Puppet выполняется сборка информации об узле, собранная информация оформляется в виде предопределённых фактов – переменных, которые можно использовать где угодно в коде. Hiera это встроенная «key-value» база данных. По-умолчанию в качестве источника данных используются файлы формата YAML или JSON, хотя возможно расширение для использования любого источника данных. В связи с её иерархичностью и возможностью изменения данных в зависимости от узла – её использование является неотъемлемой частью работы большинства модулей/классов.
Модули – самодостаточные блоки кода и данных (классы, шаблоны, файлы, и т.д.). Эти повторно используемые, доступные для общего пользования элементы являются основными строительными блоками Puppet.
Тем, кто планирует использовать Puppet в основном придётся заниматься созданием классов и иногда — модулей.
При внедрении Puppet возможны 2 варианта с централизованным хранением конфигурации и без него:
Мой скрипт выглядит примерно так:
В моём случае, конечно же, используется децентрализованная система, т.к. она проще для реализации (с точки зрения организации инфраструктуры) и она значительно упрощает скрипты сборки для развёртывания тестового стенда, который у меня создаётся и запускается по несколько десятков раз на дню.
При запуске указанного скрипта:
Список задач, которые выполняет клиент Puppet при запуске огромен (проверка и необходимое выполнение руками была бы просто невозможна):
При разработки системы скриптов Puppet для своего стенда я разрабатывал собственные модули, которые копируются на машину/контейнер, на которой выполнялся Puppet код. Модули содержат в себе данные (в большинстве конфигурационные файлы) и Puppet код для настройки. Основные настройки я выносил из скриптов в Hiera — как результат скрипты получались достаточно универсальными и не зависящими от узлов, на которых они выполняются.
Приведу несколько примеров кода и настроек.
Настройка ngnix (не из пакетов, а из родного репозитария) (спрятал в блок спойлер в связи с размерами. Но для заинтересованных — обязателен к просмотру Очень много нюансов видны при его изучении)
Как видите в каждом комментарии перед определением ресурса указано — «при необходимости». Puppet никогда не будет выполнять каких-либо операций если состояние ресурса уже соответствует его определению.
В данном случае видно как с помощью кода
Конфигурационный файл Hiera:
В данном случае видна иерархия (ключ «hierarchy») источник, где каждый источник на более высоком уровне переопределяет значения ключей на боле низком. Это позволяет и иметь ключ, например, «www.server.port» со значением «80» в «common.yaml» и со значением «81» в «nodes/webserver1.yaml» — в итоге мы получим значение данного ключа при выполнении Puppet кода: «81» на узле с именем «webserver1» и «80» на всех остальных.
Hiera's common.yaml
site.pp (файл с определением Puppet узлов)
Если кого-то заинтересует конкретная реализация какой-либо из задач: пишите – отпишу реализацию в комменте или добавлю в «Tips».
Puppet активно развивается: явно прослеживается улучшение синтаксиса и унификация поведения классов в зависимости от контекста использования (однако до сих пор остаются некоторые специфичные особенности разрешения переменных в разных контекстах, что иногда приводит к путанице).
Спасибо за внимание!
В ITIL (v3) среди описанных процессов есть 2 особенно интересных: «Процесс управления конфигурациями» и «Процесс управления изменениями», предназначенных для анализа и управления изменениями конфигураций систем. Для продолжения повествования нужно определиться, что такое «система». В это понятие входит огромное количество составляющих, влияющих (прямо или косвенно) на предоставление услуги:
- серверы
- настройки безопасности (пользователи, группы, права, межсетевые экраны);
- установленные приложения и библиотеки;
- настройки работы приложений (лимиты по дискрипторам, памяти, времени CPU и т.д.);
- резервное копирование;
- системы мониторинга за работой прикладного и системного ПО;
- конфигурационные файлы самого продукта, его компонентов, вспомогательных системных и прикладных приложений
- ...
Пытаться минимизировать контур системы вашего проекта (тип, резервное копирование не относится к функционированию системы) – значит рыть себе яму, в которую рано или поздно вы провалитесь.
Этот перечень компонентов системы — минимум для большинства проектов, развёрнутых более чем на одном сервере (да даже и на одном). При этом их количество по мере развития проекта меняется и растёт. При отсутствии какого-либо процесса их учёта становится очевидно к чему это приводит: вы имеете тестовый стенд (или стэнд разработки) на котором всё работает идеально, но попытка продублировать его на продуктиве или создать новый стенд приводит к:
- очень длительному процессу развёртывания/дублирования (все вспоминают, что и как настроено по мере возникновения сбоев и часто сверяют настройки с имеющимся стендом);
- неожиданно возникают проблемы при эксплуатации развёрнутого продукта (забывают выполнить какие-то настройки, которые на тестовом стенде внесли в последний момент, а на продуктив не перенесли);
- замедляется процесса тестирования (каждая публикация новой сборки, даже для внутренних тестировщиков, — подвиг как по времени, так и по сложности);
- и наконец – появляется страх у разработчиков перед выпуском новой версии и как результат – оттягивание выкладки нового релиза (реально серьёзная проблема о которой открыто никто не скажет, но её эффект будет чувствоваться постоянно).
В итоге — среда для корректной работы вашего продукта выход из-под вашего контроля и имеющихся средств автоматизации и версионности.
Мотивация
Вещи вроде очевидные, но в большинстве групп по разработке на них закрываются глаза – многие аргументируют это тем, что сервер у них один, настроек мало, компетентностью работников (аргумент «у нас работают профессионалы и никуда уходить не собираются» меня просто свалил), малыми рисками и т.д. и т.п.
Несмотря на кажущуюся сложность и избыточность того, что описано в ITIL (там реально много всего написано) в первую очередь из него брать надо брать требования по автоматизации указанных процессов. Автоматизация сборки, автоматизация тестирования, автоматизация поиска уязвимости – всё это внедрено и рассматривается всеми как необходимый минимум при разработке. Автоматизация ускоряет процесс, вселяет уверенность, обеспечивает прозрачность и гарантированный результат, а так же снимает страх у исполнителей за сроки и результат.
Мотивация для разработчика-одиночки
С учётом мощной вводной части в предыдущем абзаце преимущества для разработчика-одиночки опишу доступнее и более кратко:
- т.к. разработка осуществляется не ежедневно, как результат некоторые особенности развёртывания плавно улетучиваются по прошествии пары дней;
- автоматизация для одиночки – самый надёжный напарник;
- скорость выполнения работ, обеспечиваемая автоматизацией, позволяет не потерять «запал» и желание развивать проект (это очень важный специфичный момент).
Важная оговорка про ITIL
Не старайтесь брать, из описанных в ITIL процессов, все шаги которые там описаны, — ситуация будет хуже, чем до этого! Я знаю, как подобные шаги внедряются в некоторыъ банковских системах и к чему это приводит (особенно без автоматизации) – бюрократическая машина удушит любой динамично развивающийся проект/систему.
Puppet
В моём случае был выбран Puppet. При выборе между Chef и Ansible, выбор в пользу него был сделан с учётом хорошей документационной базы, хорошей поддержки, достаточно большого количества модулей (от разработчиков и сообщества), активного развития проекта и реализацией на Ruby (который более-менее мне знаком).
Откровенно говоря, кривая изучения для Puppet была вовсе не пологой. В связи с тем, что в разрабатываемой системе используется большое количество всяких элементов, каждый из них может быть настроен по-разному и всё это может быть развёрнуто на разных стендах – изучение инструмента потребовалось полное и тщательное. По мере изучения инструмента стали очевидны и некоторые его минусы (в большинстве случаев «by-design») и ограничения (хорошая статья о философии Puppet, поясняющая некоторые архитектурные решения). Так же по мере изучения и уже частичной реализации необходимых скриптов чуть больше узнал про Ansible в котором решены некоторые проблемы, имеющиеся в Puppet (что не отменят возможности наличия своих проблем, отсутствующих в Puppet). Так, что последующее повествование это не реклама Puppet, а описание возможностей и опыта использования.
Немного о Puppet
Puppet использует свой собственный конфигурационный язык (DSL), который был разработан что бы быть доступным для системных администраторов. Язык Puppet позиционируется как не требующий формального знания программирования и его синтаксис был сформирован под влияние формата конфигурационных файлов Nagios.
Основная цель языка Puppet – определение ресурсов (ресурсы в Puppet – файлы, каталоги, службы, лимиты, брандмауэры, пользователи и т.д.). Все другие части языка существуют лишь для добавления гибкости и удобства в том, как определяются ресурсы.
Группы ресурсов могут быть организованы в классы, которые являются более крупными единицами конфигурации. В то время как ресурс может описывать единственный файл/каталог или пакет, класс может описывать всё, что нужно для конфигурирования службы или приложения (включая необходимое количество пакетов, конфигурационных файлов, демонов/служб и задач обслуживания). Более маленькие классы могут объединяться в крупные, которые описывают целую системную роль – «сервер базы данных» или «рабочий узел кластера».
Пример класса с ресурсами внутри:
class apache (String $version = 'latest') {
package {'httpd':
ensure => $version, # Using the class parameter from above
before => File['/etc/httpd.conf'],
}
file {'/etc/httpd.conf':
ensure => file,
owner => 'httpd',
content => template('apache/httpd.conf.erb'), # Template from a module
}
service {'httpd':
ensure => running,
enable => true,
subscribe => File['/etc/httpd.conf'],
}
}
Машины, которые выполняют разные роли должны, в общем случае, получить разный набор классов. Задача конфигурирования того, какие классы будут применены на какие машины – задача узлов Puppet.
Примеры определения узлов Puppet:
node 'www1.example.com', 'www2.example.com', 'www3.example.com' {
include common
include apache, squid
}
node /^(foo|bar)\.example\.com$/ {
include common
}
Факты и база данных Hiera. Перед тем как выполнить код Puppet выполняется сборка информации об узле, собранная информация оформляется в виде предопределённых фактов – переменных, которые можно использовать где угодно в коде. Hiera это встроенная «key-value» база данных. По-умолчанию в качестве источника данных используются файлы формата YAML или JSON, хотя возможно расширение для использования любого источника данных. В связи с её иерархичностью и возможностью изменения данных в зависимости от узла – её использование является неотъемлемой частью работы большинства модулей/классов.
Модули – самодостаточные блоки кода и данных (классы, шаблоны, файлы, и т.д.). Эти повторно используемые, доступные для общего пользования элементы являются основными строительными блоками Puppet.
Тем, кто планирует использовать Puppet в основном придётся заниматься созданием классов и иногда — модулей.
Варианты развёртывания
При внедрении Puppet возможны 2 варианта с централизованным хранением конфигурации и без него:
- Централизованное хранение конфигурации: преимущества явно прослеживаются при наличии БОЛЬШОГО количества серверов. В этом случае на клиентские машины передаётся информация, касающиеся только самой машины, что так же обеспечивает некоторый уровень безопасности и минимизирует траффик.
- Децентрализованное хранение конфигурации: обосновано при небольшом количестве серверов, при этом на машин должен быть полный комплект конфигурационных скриптов и файлов и при запуске агентов будет выполнена их компиляция и выполнения части касающейся данной машины. Реализуется обычной cron-задачей, запускаемой каждые 15 минут.
Мой скрипт выглядит примерно так:
#!/bin/sh
PUPPET_BIN='/opt/puppetlabs/bin/puppet'
# Ставим необходимые пакеты для старта
apt-get update && apt-get -y install git mc htop apt-transport-https nano wget lsb-release apt-utils curl python
# Первоначально осуществляем установку `puppet-agent`
if [ ! -d /etc/puppetlabs ]; then
rm *.deb.* *.deb # possible trash
wget https://apt.puppetlabs.com/puppetlabs-release-pc1-xenial.deb && dpkg -i puppetlabs-release-pc1-xenial.deb
apt-get update && apt-get -y install puppet-agent
fi
# Определяем тип `environment`
/opt/puppetlabs/bin/puppet config set environment $PUPPET_ENV
if [ ! -d /etc/puppetlabs/code/environments/$PUPPET_ENV ]; then
cp -r /etc/puppetlabs/code/environments/production /etc/puppetlabs/code/environments/$PUPPET_ENV
fi
# Install puppet modules
$PUPPET_BIN module install puppetlabs-ntp
$PUPPET_BIN module install aco-oracle_java
$PUPPET_BIN module install puppetlabs-firewall
$PUPPET_BIN module install saz-ssh
$PUPPET_BIN module install saz-sudo
$PUPPET_BIN module install saz-limits
$PUPPET_BIN module install thias-sysctl
$PUPPET_BIN module install yo61-logrotate
$PUPPET_BIN module install puppetlabs-apt
$PUPPET_BIN module install puppet-archive
# git pull "deployment" project and go in it only if POVISION_NO_GIT_CLONE set to "true"
if [ ${POVISION_NO_GIT_CLONE:-"false"} = "true" ];
then
echo "do nothing"
else
LOCAL_REV=""
if [ -f local_latest.sha1 ]; then
LOCAL_REV=`cat local_latest.sha1`
fi
REMOTE_REV=`git ls-remote --tags | grep "latest" | awk '{print $1}'`
if [ $LOCAL_REV = $REMOTE_REV ]; then
exit 0
fi
git fetch --all --tags --prune
git checkout -f tags/latest
fi
# replace puppet configs
cp puppet_config/hiera.yaml /etc/puppetlabs/code/environments/$PUPPET_ENV/
# replace hiera db
rm /etc/puppetlabs/code/environments/$PUPPET_ENV/hieradata/*
cp -r $PUPPET_ENV/hieradata/* /etc/puppetlabs/code/environments/$PUPPET_ENV/hieradata
# replace storyline_* modules
rm -r /etc/puppetlabs/code/environments/$PUPPET_ENV/modules/storyline_*
cp -r modules/* /etc/puppetlabs/code/environments/$PUPPET_ENV/modules
# copy site.pp
cp $PUPPET_ENV/site.pp /etc/puppetlabs/code/environments/$PUPPET_ENV/manifests/site.pp
#echo "hostname:"
#hostname
$PUPPET_BIN apply /etc/puppetlabs/code/environments/$PUPPET_ENV/manifests/site.pp
echo $REMOTE_REV > local_latest.sha1
В моём случае, конечно же, используется децентрализованная система, т.к. она проще для реализации (с точки зрения организации инфраструктуры) и она значительно упрощает скрипты сборки для развёртывания тестового стенда, который у меня создаётся и запускается по несколько десятков раз на дню.
При запуске указанного скрипта:
- устанавливается сам клиент Puppet и необходимые пакеты
- инсталлируются необходимые модули Puppet
- сверяется изменение номера коммита для метки «latest» (делается при успешном интеграционном тестировании новой версии)
- заменяется конфигурация (hiera.yaml) БД Hiera Puppet в текущем окружении (переменная $PUPPET_ENV);
- заменяются YAML-файлы с данными для БД Hiera Puppet;
- копируются с заменой описания моих модулей;
- копируется конфигурация с узлами (серверами моей системы);
- вызывается применение всех тех настроек, что были скопированы/установлены ($PUPPET_BIN apply ….)
Список задач, которые выполняет клиент Puppet при запуске огромен (проверка и необходимое выполнение руками была бы просто невозможна):
- выставляются лимиты на открытые файлы, задействованный объем памяти, свапирование и количество соединений;
- настраивается ротация логов (как для системы, так и для моего приложения и необходимых ему сервисов);
- создаются необходимые учётные записи для администрирования с необходимыми группами и полномочиями;
- устанавливается и настраивается NTP-сервер;
- устанавливается и настраивается SSH-сервер;
- устанавливается Oracle JDK;
- настраивается брандмауэр;
- устанавливается и настраивается большое количество компонентов, необходимых для функционирования проекта или его компонента на данном конкретном узле.
Примеры из жизни
При разработки системы скриптов Puppet для своего стенда я разрабатывал собственные модули, которые копируются на машину/контейнер, на которой выполнялся Puppet код. Модули содержат в себе данные (в большинстве конфигурационные файлы) и Puppet код для настройки. Основные настройки я выносил из скриптов в Hiera — как результат скрипты получались достаточно универсальными и не зависящими от узлов, на которых они выполняются.
Приведу несколько примеров кода и настроек.
Настройка ngnix (не из пакетов, а из родного репозитария) (спрятал в блок спойлер в связи с размерами. Но для заинтересованных — обязателен к просмотру Очень много нюансов видны при его изучении)
Класс nginx из модуля storyline_infra
class storyline_infra::nginx () {
$params = lookup({"name" => "storyline_infra.nginx",
"merge" => {"strategy" => "deep"}})
$reverse_port = $params['reverse_port']
$reverse_url = $params['reverse_url']
$pid_file = $params['pid_file']
$init_script = $params['init_script']
$dir_data = $params['dir_data']
$dir_logs = $params['dir_logs']
$version = $params['version']
$enabled_startup = $params['enabled_startup']
$enabled_running = $params['enabled_running']
# topology_configuration
$enabled_topology_configuration = $params['enabled_topology_configuration']
$topology_configuration_port = $params['topology_configuration_port']
# создать соотвествующего пользователя (при необходимости)
user { 'nginx':
ensure => "present",
managehome => true,
}
# создать необходимые каталоги (при необходимости)
exec { "nginx-mkdir":
command => "/bin/mkdir -p /data/db && /bin/mkdir -p /data/logs",
cwd => "/",
unless => '/usr/bin/test -d /data/db -a -d /data/logs',
} ->
# working dir
file { [ $dir_logs, $dir_data] :
ensure => "directory",
recurse => "true",
owner => "nginx",
group=> "nginx",
require => Exec['nginx-mkdir'],
}
# добавить необходимые ключи в менеджер пакетов (при необходимости)
# see by "gpg --verify keyfile"
apt::key { 'nginx-key':
id => '573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62',
source => 'http://nginx.org/keys/nginx_signing.key',
} ->
# добавить источник (при необходимости)
# deb http://nginx.org/packages/ubuntu/ xenial nginx
apt::source { 'nginx-repo':
comment => 'nginx repo',
location => "http://nginx.org/packages/ubuntu/",
release => "xenial",
repos => "nginx",
include => {
'deb' => true,
'deb-src' => true,
},
} ->
# осуществить установку пакета (при необходимости)
package { 'nginx':
ensure => $version,
# notify => Exec['disable_nginx'],
} →
# выполнить копирование конфигурационного файла из данных модуля (при необходимости). При этом сам файл шаблона содержит подстановочные знаки, которые заменяются переменными класса. Крайне удобный функционал!!!
file { "/etc/nginx/nginx.conf":
replace => true,
content => epp('storyline_infra/nginx.epp'),
owner => "nginx",
group=> "nginx",
notify => Service['nginx'],
}->
# выполнить копирование конфигурационного файла из данных модуля (при необходимости)
file { "/etc/nginx/conf.d/default.conf":
replace => true,
content => epp('storyline_infra/nginx_default.epp'),
owner => "nginx",
group=> "nginx",
notify => Service['nginx'],
}→
# выполнить копирование конфигурационного файла из данных модуля (при необходимости)
file { $init_script:
replace => true,
content => epp('storyline_infra/nginx_startup.epp'),
mode=>"ug=rwx,o=r",
notify => Service['nginx'],
}→
# настроить службу/скрипты запуска (при необходимости)
service { 'nginx':
ensure => $enabled_running,
enable => $enabled_startup,
start => "${init_script} start",
stop => "${init_script} stop",
status => "${init_script} status",
restart => "${init_script} restart",
hasrestart => true,
hasstatus => true,
}
# дополнительные настройки nginx (при необходимости)
if $enabled_topology_configuration {
file { "/etc/nginx/conf.d/topology.conf":
replace => true,
content => epp('storyline_infra/nginx_topology.epp'),
mode=>"ug=rwx,o=r",
notify => Service['nginx'],
}
}
# отключение автозапуска встроенными средствами (при необходимости)
if $enabled_startup != true {
exec { "disable_nginx":
require => Package['nginx'],
command => "/bin/systemctl disable nginx",
cwd => "/",
}
}
}
Как видите в каждом комментарии перед определением ресурса указано — «при необходимости». Puppet никогда не будет выполнять каких-либо операций если состояние ресурса уже соответствует его определению.
В данном случае видно как с помощью кода
«$params = lookup({"name" => "storyline_infra.nginx", "merge" => {"strategy" => "deep"}})»
получаются данные из Hiera (примеры её данных я приведу позже), которые в дальнейшем используются для заполнения всех переменных.Конфигурационный файл Hiera:
---
version: 5
defaults:
datadir: "hieradata"
data_hash: yaml_data
hierarchy:
- name: "1"
path: "nodes/%{trusted.certname}.yaml"
- name: "2"
path: "version.yaml"
- name: "3"
path: "common.yaml"
В данном случае видна иерархия (ключ «hierarchy») источник, где каждый источник на более высоком уровне переопределяет значения ключей на боле низком. Это позволяет и иметь ключ, например, «www.server.port» со значением «80» в «common.yaml» и со значением «81» в «nodes/webserver1.yaml» — в итоге мы получим значение данного ключа при выполнении Puppet кода: «81» на узле с именем «webserver1» и «80» на всех остальных.
Hiera's common.yaml
---
limits::entries:
'*/nofile':
both: 1048576
'*/memlock':
both: unlimited
logrotate::config:
su_user: root
su_group: syslog
compress: true
# sysctl
sysctl::base::purge: false
sysctl::base::values:
net.core.somaxconn:
value: '65536'
vm.swappiness:
ensure: absent
fs.file-max:
value: '500000'
vm.max_map_count:
value: '262144'
storyline_base:
oracle_java:
version: "8u92"
storyline_infra:
collectd:
server_address: "XXX.nlp-project.ru"
pid_file: '/data/logs/collectd/collectd.pid'
init_script: '/etc/init.d/collectd'
dir_data: '/data/db/collectd'
dir_logs: '/data/logs/collectd'
version: "1.2.0-1"
enabled_mongodb: false
mongodb_user: "collectd"
mongodb_password: "######"
enabled_storm: false
enabled_elasticsearch: false
elasticsearch_port: "####"
elasticsearch_cluster: "elastic_storyline"
enabled_startup: false
enabled_running: true
influxdb:
port_http: "####"
port_rpc: "####"
pid_file: '/data/logs/influxdb/influxdb.pid'
init_script: '/etc/init.d/influxdb'
dir_data: '/data/db/influxdb'
dir_logs: '/data/logs/influxdb'
version: "present"
enabled_auth: true
enabled_startup: false
enabled_running: true
….
site.pp (файл с определением Puppet узлов)
node "XXX.nlp-project.ru" {
include ::limits
include ::sysctl::base
include ::logrotate
include storyline_base::ntp
include storyline_base::srv_oper
include storyline_base::ssh
include storyline_base::oracle_java
…..
include storyline_infra::monit
include storyline_base::firewall
}
node "YYYY.nlp-project.ru" {
include ::limits
include ::sysctl::base
include ::logrotate
include storyline_base::ntp
include storyline_base::srv_oper
include storyline_base::ssh
include storyline_base::oracle_java
….
include storyline_infra::zookeeper
include storyline_components::server_storm
include storyline_infra::monit
include storyline_base::firewall
}
Если кого-то заинтересует конкретная реализация какой-либо из задач: пишите – отпишу реализацию в комменте или добавлю в «Tips».
Puppet активно развивается: явно прослеживается улучшение синтаксиса и унификация поведения классов в зависимости от контекста использования (однако до сих пор остаются некоторые специфичные особенности разрешения переменных в разных контекстах, что иногда приводит к путанице).
Tips
- При разработке модуля не забывать писать код не только для добавления функции, но и для её отключения. При отсутствии такого функционала при переносе компонента на другой сервер у вас их будет 2: на новом и на старом месте — на старом потребуется удалять руками, что противоречит основной задаче по автоматизации управления конфигурациями;
- Хорошие книги по Puppet для начинающих – Learning Puppet и Puppet 4 Essentials;
- Хороший модуль для получения артефактов из nexus sonatype (https://github.com/cescoffier/puppet-nexus);
- Максимальное количество параметров выносите в файлы-данные Hiera для легкости конфигурации узлов и достижения универсальности кода самих модулей.
Спасибо за внимание!
Комментарии 0
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.