В этом посте я хотел бы поделиться своим опытом использования системы управления конфигурациями SaltStack, и, в частности, её применением в Masterless режиме при помощи salt-ssh компонента. По сути, salt-ssh является аналогом системы Ansible. Будут затронуты следующие темы:  Когда я несколько лет назад, вдоволь насытившись puppet (multiple environments, 100+ nodes), для нового проекта выбирал новую же систему управления конфигурациями, то Masterless режим работы был ключевым требованием. Но также хотелось сохранить возможность Master-Slave режима работы. Хотелось хорошей, обширной документации и гибкости. Хотелось уметь управлять облачными инфраструктурами. А еще хотелось построить систему, в которой будут легко уживаться самые разные окружения. Все это удалось сделать при помощи salt-ssh. Salt-ssh это компонент SaltStack, который, как и Ansible, использует ssh для соединения с удаленными машинами и не требует никаких предварительных настроек со стороны удаленных машин. Никаких агентов. Pure ssh! Конечно, при выборе системы я рассматривал и Ansible. Но чаша весов тогда склонилась к SaltStack. В отличие от Ansible, SaltStack использует Jinja2 как для обработки шаблонов, так и для построения логики. Причем эту логику можно построить практически любыми способом. Что с одной стороны и хорошо и плохо. Хорошо т.к. даёт гибкость. Но плохо, т.к. нет одного стандартного способа и подхода к реализации. Мне даже кажется, что SaltStack больше представляет из себя конструктор в этом плане. Также, рендеринг шаблонов и логики происходит на этапе запуска. Полученный пакет шаблонов, настроек и инструкций копируется на удаленный сервер и выполняется. По завершению выполнения salt-ssh выдает в консоль отчет, что было выполнено, а с чем произошли ошибки, если они возникли. Здесь отличие с ansible очень разительно. Последний выполняет задачи\плейбуки поочередно, в режиме shell-скрипта. Не скрою, что наблюдать за ходом выполнения ansible скриптов приятнее, но постепенно все это отходит на второй план, когда число хостов переваливает за несколько десятков. Также, в сравнении с ansible, SaltStack имеет более высокий уровень абстракции.
Как бы то ни было, и ansible и salt-ssh это два очень интересных инструмента, каждый из которых имеет свои плюсы и минусы. SaltStack — это система управления конфигурациями и инфраструктурой. Как на уровне отдельных серверов, так и в различных облачных платформах (SaltCloud). Также это система удаленного выполнения команд. Написана на python. Очень бурно развивается. Имеет множество самых разных модулей и возможностей, в том числе даже такие как Salt-Api и Salt-Syndic (master of masters или система, позволяющая строить иерархию мастер серверов, тобишь синдикат). По умолчанию SaltStack подразумевает Master-Slave режим работы. Обмен сообщениями между нодами происходит через ZeroMQ протокол. Умеет горизонтально масштабироваться при помощи MultiMaster настроек. Но самое приятное, Salt умеет еще работать и в Agentless режиме. Что может быть реализовано при помощи локального запуска стейтов либо при помощи salt-ssh, героя данного топика. Salt master — процесс, работающий на машине, с которой происходит управление подключенными агентами. В случае с salt-ssh можно назвать мастером ту ноду, где лежат наши state и pillar данные
Salt minion — процесс, работающий на управляемых машинах, т.е. slave. В случае с salt-ssh minion это любой удаленный сервер
State — декларативное представление состояния системы (аналог playbooks в ansible)
Grains — статическая информация об удаленном minion (RAM,CPUs,OS,etc)
Pillar — переменые для одного или более minions
top.sls — центральные файлы, реализующие логику какие state и pillar данные какому minion назначить
highstate — все определенные state данные для minion
SLS — так называются все конфигурационные файлы для pillar\states в SaltStack, используется YAML Одним из недостатков системы SaltStack является более высокий порог вхождения. Далее я покажу примеры, чтобы начать работать с этой замечательной системой было проще. Установка salt-ssh происходит тривиально. На сайте https://repo.saltstack.com/ есть все необходимые репозитории и инструкции для подключения их в разнообразных системах. Для установки нужен только сам salt-ssh. sudo apt-get install salt-ssh (На примере Deb систем) Чтобы начать использовать salt-ssh нам достаточно установить его. Как минимум можно управлять своей локальной машиной, либо любым удаленным сервером, что гораздо наглядней. В данном же примере, для тестов я буду использовать две виртуальные машины, созданные при помощи Vagrant. На одной из них будет установлен собственно сам salt-ssh, другая будет чистая, не считая подключенного публичного ключа с первой машины. Сам Vagrantfile и необходимые salt states выложены в репозиторий https://github.com/skandyla/saltssh-intro. Я предполагаю что аудитория знакома с Vagrant, но на всякий случай: Vagrant — это своеобразный фреймворк для систем виртуализации, предназначенный для упрощения процесса разработки и создания его воспроизводимым. Для запуска виртуальных машин нам понадобятся установленными сам Vagrant и Virtualbox. Дальше клонируем репозиторий: и в нем инициализируем Vagrant виртуальные машины: После запуска последних, заходим в saltsshbox: Вся дальнейшая работа будет вестись из данной виртуальной машины. По умолчанию SaltStack предполагает что мы будет действовать от имени root, поэтому сразу делаем:  Целевые хосты прописываются в файл /etc/salt/roster, однако, можно указать любой сторонний roster file. В некотором смысле можно провести аналогии с inventory файлами ansible. Roster файл, представляет собой YAML, с множеством разных опций. Ниже показаны несколько способов записи одного и того же хоста.  Теперь попробуем выполнить команду test.ping применительно ко всем хостам, указанным в нашем ростере. Как видите, salt-ssh слегка ругнулся, что не может зайти на удаленный сервер и предложил туда развернуть ключ, но я отменил это. Остальные два сервера(по факту один под разными именами) ответили положительно. Произошло это потому что мы работает из-под root, для которого никаких ssh-ключей не определено. Поэтому можно просто добавить ключ через ssh-agent и снова повторить команду. Теперь все хорошо! Мало того, можно запросто добавить ключ с паролем через ssh-agent. Но если же вы решите деплоить ключ, который предлагает сам salt, то брать его по умолчанию он будет вот по такому пути: /etc/salt/pki/master/ssh/salt-ssh.rsa Здесь для теста я намеренно работал с отдельным roster файлом, чтобы показать интересные нюансы. Для дальнейшей же работы указывать roster нам будет не нужно, потому что он уже и так через symlink указан в требуемое место(/etc/salt/roster). Ключ -i необходим когда мы начинаем работать с новыми хостами, он просто запрещает StrictHostKeyChecking, давая возможность принять новый host key. Для дальнейшей работы он нам тоже будет не нужен. Напомню, что по умолчанию salt смотрит на roster здесь: /etc/salt/roster в котором у нас сейчас определен только один хост. Теперь когда мы убедились что наша машина с salt-ssh прекрасно видит указанный в roster тестовый сервер, поработаем с ним в стиле ad-hoc. cmd.run это по сути аналог ключа -a в ansible. Также можно использовать встроенные модуля saltstack, например: Последняя команда выдаст документацию об модулях и, главное, примеры их использования. Дополнительно можно посмотреть полный список доступных модулей Saltstack. Grains это мощный механизм, представляющий набор фактов об удаленной системе. В дальнейшем на основе Grains можно также строить различную логику. Но для начала посмотрим как с ними начать работать: Вывод команды урезан. К нужной ветви Grains можно обратиться, непосредственно указав её: Либо даже более конкретно: Теперь пришла пора рассказать про еще один важный файл /etc/salt/master. Вообще он идет в комплекте с пакетом salt-master и определяет некоторые важные опции логирования и директории в которых salt будет искать наши states и pillar данные. По умолчанию для states определена директория /srv/salt. Но на практике часто более рационально использовать другую структуру, в том числе и для этих примеров. /etc/salt/master: state_verbose и state_output это переменные, которые отвечают за отображение статуса выполнения на экране. На мой взгляд такая комбинация наиболее практична, но рекомендую поэкспериментировать. file_roots и pillar_roots указывают пути к нашим state и pillar данным соотвественно. Важно! этих путей может быть несколько. По принципу разных окружений, разных данных и т.д. и т.п., но это тема для отдельной статьи по настройке multi-environment среды, для начала нам же просто необходимо знать, куда нам положить наши state файлы, чтобы salt их нашел. Далее, в каждой из этой директорий (file_roots и pillar_roots) сальт будет искать файлы top.sls, которые определяют уже дальнейшую логику обработки salt файлов. В нашем случае: /srv/saltstack/salt/top.sls: Что означает, для всех хостов применить state common и timezone, а для testserver применить еще и chrony (сервис синхронизации времени). Для pillar также необходим top.sls файл. Который будет определять в каком порядке и как будут назначаться переменные.
/srv/saltstack/pillar/top.sls:  В нашем случае файл этот предельно простой, указано лишь подключить все переменные из файла timezone.sls и еще подключить переменые из файла hosts/testserver для нашего testserver, однако, за этой простотой скрывается мощная концепция, т.к. переменные можно назначить как угодно и на какое угодно окружение. Правда, перекрытие и слияние переменных (Variables Overriding and Merging) это отдельная тема, пока скажу что приоритетность задается сверху вниз. Т.е. если бы у нас здесь в файле hosts/testserver.sls содержались переменные с timezone, то они бы имели преимущество. В файлах top.sls все указывается без расширения .sls. Приступим к простенькому state: /srv/saltstack/salt/packages.sls: Как видно, здесь мы применили и jinja и grains и собственно сам pkg модуль. Попробуем применить этот state в тестовом режиме: И далее уже в реальном: Следующее важное звено — это Pillar. Так в SaltStack называется переменные, или всё что задается со стороны мастера для удаленных систем. Частично они уже вам знакомы из описанного выше, поэтому сразу к делу. Получить все pillar переменные, определенные для хоста: Также как и с Grains можно запросить отдельно взятую переменную: Рассмотрим следующий state: /srv/saltstack/salt/timezone.sls: Здесь мы задали переменную на основе данных из pillar. Причем в этой конструкции: Europe/Dublin — это значение по умолчанию, если по каким-то причинам salt не сможет получить значение из Pillar. И вот, наконец-то, мы добрались уже до реального жизненного примера. Рассмотрим state синхронизации времени — chrony. Находится он у нас здесь: /srv/saltstack/salt/chrony/init.sls Причем init.sls это индекс по умолчанию, salt ищет его автоматически, но можно использовать и любой другой файл. Здесь мы введем еще одну типичную конструкцию для salt — это map.jinja. /srv/saltstack/salt/chrony/map.jinja: Её назначение — это создать необходимый набор статических переменных под нашу систему, но с возможностью слияния с переменными из pillar, если таковые вдруг понадобится указать. Дальше сам /srv/saltstack/salt/chrony/init.sls: Здесь отдельного внимания заслуживает шаблон salt://chrony/files/chrony.conf.jinja формата jinja. /srv/saltstack/salt/chrony/files/chrony.conf.jinja: В этом шаблоне мы также запрашиваем переменные из Pillar и обрабатываем их. Просмотреть как этот state воспринялся salt можно при помощи state.show_sls: Дальше уже просто выполним его: Здесь salt докладывает о 3х выполненных state по суммарному колличеству задействованных модулей. Если выполнить повторно, то видно что никаких изменений не было произведено: Сразу же можно и посмотреть как сформировался конфигурационный файл для chrony: Финально стоит упомянуть еще команду state.highstate. Она применяет все прописанные state для нашего тестового сервера. Итак, мы узнали чтоже из себя представляет salt-ssh из комплекта SaltStack и как его использовать. Узнали ключевые особенности построения окружения, необходимого для работы salt-ssh. Настроили тестовую среду при помощи Vagrant. И планомерно провели эксперименты с фундаментальными концепциями SaltStack, такими как: Grains, States, Pillar. Также мы узнали как писать state от простого к сложному, дойдя до реальных примеров, позволяющих на своей базе уже строить дальнейшую автоматизацию. На этом пока все. За бортом осталось еще множество интересных тем, но я надеюсь что эта информация поможет начать работать с этой замечательной системой управления конфигурациями. Полезная информация: best_practices
walkthrough
starting_states
pillar
formulas
tutorials