СоХабр закрыт.

С 13.05.2019 изменения постов больше не отслеживаются, и новые посты не сохраняются.

| сохранено

H В разрезе: новостной агрегатор на Android с бэкендом. Система контроля конфигураций (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


В моём случае, конечно же, используется децентрализованная система, т.к. она проще для реализации (с точки зрения организации инфраструктуры) и она значительно упрощает скрипты сборки для развёртывания тестового стенда, который у меня создаётся и запускается по несколько десятков раз на дню.

При запуске указанного скрипта:
  1. устанавливается сам клиент Puppet и необходимые пакеты
  2. инсталлируются необходимые модули Puppet
  3. сверяется изменение номера коммита для метки «latest» (делается при успешном интеграционном тестировании новой версии)
  4. заменяется конфигурация (hiera.yaml) БД Hiera Puppet в текущем окружении (переменная $PUPPET_ENV);
  5. заменяются YAML-файлы с данными для БД Hiera Puppet;
  6. копируются с заменой описания моих модулей;
  7. копируется конфигурация с узлами (серверами моей системы);
  8. вызывается применение всех тех настроек, что были скопированы/установлены ($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 для легкости конфигурации узлов и достижения универсальности кода самих модулей.


Спасибо за внимание!

комментарии (0)