Автоматизация в веб-разработке с Vagrant и SaltStack
Веб разработчикам нужно настраивать сервера. Обычно под каждый проект. С тех пор как я научился делать это без помощи гугла, настройка перестала быть чем-то интересным, и хотелось её максимально автоматизировать.Первой идеей было создание виртуальной машины и копирование её при необходимости. Схожие конфигурации настраивать стало проще, но каждый раз когда что-то в конфигурации менялось, приходилось заходить на сервер и настраивать его. Хотелось большего.Путем проб и ошибок я пришел к связке Vagrant + SaltStack, где Vagrant берет на себя изоляцию окружений, а SaltStack — управление конфигурацией.Vagrant. Vagrant — это менеджер виртуальных машин с настройкой через Vagrantfile, позволяющий в одной точке собрать конфигурацию машины готовую для запуска. Он умеет не только поднимать виртуальные машины, но и заниматься их «обеспечением». Обеспечение делегирует системам, которые для этого предназначены.Формат пакета для разворачивания окружения в Vagrant — .box. Есть сервис для обмена боксами — https://vagrantcloud.com/. На данный момент он в бете, но, за исключением, «битых» ссылок на боксы, ошибок я не видел.Vagrantfile Создать Vagrantfile не составляет труда. Подробности есть в документации, я же перечислю то, что понадобится в примере.Сервер будет работать на debian без предустановленых компонентов SaltStack. На https://vagrantcloud.com/можно найти .box. config.vm.box = «mokote/debian-7» Я использую приватную сеть, внутри которой каждая виртуальная машина получит свой IP. Это позволяет запускать несколько машин одновременно и иметь к ним доступ. config.vm.network «private_network», ip:»192.168.56.107» Настройки виртуальной машины: config.vm.provider «virtualbox» do |v| v.name = «demostand» v.memory = 1024
v.customize [«modifyvm», : id,»--natdnshostresolver1», «on»] v.customize [«setextradata», : id,»--VBoxInternal2/SharedFoldersEnableSymlinksCreate/v-root»,»1»] end Синхронизируем директории с настройками SaltStack и с проектом, который будет развернут на создаваемой машине. Для проекта я использовал nfs в качестве метода синхронизации. Он работает быстрее, чем VirtualBox shared folders, и настраивается всего одним параметром : nfs => true, но требует root доступ. config.vm.synced_folder «salt/roots/»,»/srv/» config.vm.synced_folder »~/Development/web/demostand»,»/var/www/demostand», id: «vagrant-root», : nfs => true Осталось настроить обеспечение хоста конфигурациями SaltStack.salt.minion_config — файл, с которого начинается конфигурация сервера.salt.run_highstate = true — запускать ли обеспечение при старте машины.salt.pillar — данные pillar-хранилища. config.vm.provision: salt do |salt| salt.minion_config = 'salt/minion' salt.run_highstate = true
salt.pillar ({ «database» => { «withUser» => true, «name» => «demostand», «password» => «fm2QTqimWUrk» } })
salt.pillar ({«projectName» => «demostand»}) end Полностью Vagrantfile можно посмотреть тут: https://github.com/ligser/salt-vagrant-demostand/blob/master/Vagrantfile.SaltStack SaltStack позволяет создавать связку master –> minion и инициировать мастером обеспечение minion свежими конфигами. У меня не было такой необходимости, поэтому обеспечение будет выполняться без участия master.Описание конфигурации для SaltStack — это набор утверждений (состояний, в терминологии SaltStack), которые должны быть удовлетворены, чтобы minion считался сконфигурированным успешно.Я опишу возможности SaltStack, которые мне пригодились.salt/minion Для начала найдем файл salt/minion, который указан в Vagrantfile. Это файл с которого начинается конфигурирование машины.Содержимое его крайне лаконично: file_client: local. Тут утверждается, что конфигурация хранится локально на minion, по умолчанию, в директории /srv/salt, в которую мы настроили синхронизацию.Состояния Полный мануал по состояниям есть на сайте проекта: http://docs.saltstack.com/en/latest/topics/tutorials/index.html#states.Состояния хранятся в .sls файлах. Обычно .sls состоит из описания состояний в формате YAML. apache: # ID pkg: # состояние — installed # функция Вызов одной функции можно сокращать: apache: pkg.installed Также, если ID не совпадает с именем объекта состояния — можно указать имя. apache_pkg: pkg: — name: apache — installed pkg — это состояние пакетного менеджера. installed — одна из самых часто используемых функций этого состояния, подразумевающая, что пакет с таким именем должен быть установлен в системе.service — состояние сервисов. При помощи него можно запускать или останавливать сервисы. Состояние останавливающее apache2: apache2: service.dead file — состояние файловой системы.Обычно для работы с ФС используется функция managed.Если ID совпадает с именем файла, нам не нужно указывать параметр name.source — место, откуда берется содержимое файла. salt:// — указатель на /srv/salt, или относительно Vagrantfile: salt/roots/salt.По-умолчанию, файлы не являются шаблонами jinja, поэтому использовать внутри них данные pillar нельзя. Чтобы сделать файл шаблоном, нужно указать template: jinja в параметрах. После этого, файл будет обработан шаблонизатором. jinja используется и в самих .sls файлах.В SaltStack поддерживаются зависимости между состояниями.watch_in указывает, в каких сервисах используется файл, чтобы при его изменении перезапустить их.require поддерживается состоянием pkg и требует установки определенного пакета. /etc/nginx/sites-available/default: file.managed: — source: salt://nginx/default — template: jinja — user: root — group: root — mode: 644 — watch_in: — service: nginx Данные Для хранения данных в SaltStack сущестует две системы.pillar — данные, которых не должно быть в файлах конфига. В Vagrantfile я положил в pillar 2 ключа: database — параметры БД и projectName — имя проекта.grains — статическая информация, которая будет загружена на minion при его запуске.grains я практически не использовал, поэтому не интересовался тонкостями этой системы, если нужно больше информации, она доступна на сайте SaltStack: http://docs.saltstack.com/en/latest/topics/targeting/grains.html.По умолчанию, любой .sls файл обрабатывается шаблонизатором, поэтому в нем можно использовать конструкции:{{ }} — вывод.{% %} — условия, или циклы. {{ pillar['database']['name'] }}: {% if (pillar['database']['withUser']) %} mysql_user.present: — host: localhost — password: {{ pillar['database']['password'] }} — require: — service: mysql — pkg: python-mysqldb {% endif %} В примере выше, из pillar берется значение [database][name], записанное в Vagrantfile, и назначается в качестве ID для состояния mysql_user.present.Значение ['database']['password'] будет использовано в качестве пароля.Top.sls top.sls — файл, с которого SaltStack начнет считывать состояния.Он содержит список подключаемых файлов .sls для данной конфигурации.Готовая конфигурация Готовая конфигурация Vagrant и SaltStack лежит на GitHub. Она позволяет развернуть сервер с PHP, nginx и mysql одной командой: vagrant up --provision При разворачивании нескольких образов одновременно нужно не забывать менять IP в приватной сети.Вывод Автоматизация позволяет сократить объем рутинной работы до небольших правок. Разворачивание обычных серверов сократилось до копипаста типовых настроек и запуска vagrant up. То, на что раньше могло уйти несколько часов, сейчас занимает минуты, большую часть которых сервер сам ставит пакеты.