Веб разработчикам нужно настраивать сервера. Обычно под каждый проект. С тех пор как я научился делать это без помощи гугла, настройка перестала быть чем-то интересным, и хотелось её максимально автоматизировать.Первой идеей было создание виртуальной машины и копирование её при необходимости. Схожие конфигурации настраивать стало проще, но каждый раз когда что-то в конфигурации менялось, приходилось заходить на сервер и настраивать его. Хотелось большего.
Путем проб и ошибок я пришел к связке
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. То, на что раньше могло уйти несколько часов, сейчас занимает минуты, большую часть которых сервер сам ставит пакеты.