Вводная часть (со ссылками на все статьи)
В 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 при запуске огромен (проверка и необходимое выполнение руками была бы просто невозможна):
Если кого-то заинтересует конкретная реализация какой-либо из задач: пишите – отпишу реализацию в комменте или добавлю в «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;
- настраивается брандмауэр;
- устанавливается и настраивается большое количество компонентов, необходимых для функционирования проекта или его компонента на данном конкретном узле.
Если кого-то заинтересует конкретная реализация какой-либо из задач: пишите – отпишу реализацию в комменте или добавлю в «Tips».
Puppet активно развивается: явно прослеживается улучшение синтаксиса и унификация поведения классов в зависимости от контекста использования (однако до сих пор остаются некоторые специфичные особенности разрешения переменных в разных контекстах, что иногда приводит к путанице).
Tips
- При разработке модуля не забывать писать код не только для добавления функции, но и для её отключения. При отсутствии такого функционала при переносе компонента на другой сервер у вас их будет 2: на новом и на старом месте — на старом потребуется удалять руками, что противоречит основной задаче по автоматизации управления конфигурациями;
- Хорошие книги по Puppet для начинающих – Learning Puppet и Puppet 4 Essentials;
- Хороший модуль для получения артефактов из nexus sonatype (https://github.com/cescoffier/puppet-nexus);
- Максимальное количество параметров выносите в файлы-данные Hiera для легкости конфигурации узлов и достижения универсальности кода самих модулей.
Спасибо за внимание!
Поделиться с друзьями