Pull to refresh

Development Environment при помощи Vagrant и Chef

Reading time 9 min
Views 31K





В данной статье я постараюсь познакомить вас с замечательными утилитами Vagrant и Chef на примере автоматического конфигурирования development environment для PHP разработчика (на самом деле, PHP здесь только как пример, все нижеописанное может быть использовано для любого стека технологий).

Что будем делать?



Будем настраивать виртуальную машину (ВМ) с Ubuntu 12.04 для работы над проектом на PHP, а именно:

  • Apache
  • MySql
  • PHP 5.4
  • xDebug
  • Memcached
  • Composer
  • Настроим сразу Virtual Host на определенную папку, доступную как с виртуальной машины, так и с реальной. Всё это параметризируем для удобства создания и использования.
  • и другое..


Довольно занудное занятие, особенно если заниматься этим с некоторой периодичностью, поэтому мы заставим компьютер делать это самостоятельно.

Как это может помочь вам?



  • Вы не хотите «засорять» свою систему множеством утилит, программ
  • Вы хотите тестировать свой код в приближенных к production условиях
  • Вы хотите тестировать свой код на разных версиях той или иной платформы (помните, как Travis тестирует билды в различных конфигурациях, например Symfony на разных версиях PHP)
  • Вы не хотите больше помогать новому человеку на проекте (верстальщик, программист) устанавливать всё с нуля
  • Вы хотите, чтобы у каждого человека в команде была идентичная среда для работы над проектом


Всё это — реальность. Вопрос только «как?».



Vagrant



Vagrant — это утилита, позволяющая создавать виртуальную машину и настраивать её автоматически так, как вы это указали. Из коробки Vagrant работает с VirtualBox, хотя есть поддержка и других решений.

Забегая вперёд, всё, что вам потребуется для того, чтобы развернуть окружение на компьютере — это выполнить одну команду:

vagrant up


Всё будет сделано автоматически. Давайте приступим к выполнению нашей задачи.

Для настройки Vagrant использует всего один файл — Vagrantfile. Именно в нём и описывается все, что нужно сделать при запуске виртуальной машины. Для инициализации Vagrant проекта необходимо выполнить команду

vagrant init


в корне вашего проекта.

Структура директорий у нас будет следующая:
recipes
www
Vagrantfile


Одно из главных понятий в Vagrant, это box. Box — это архив, который содержит в себе образ виртуальной машины и файл с настройками для самого Vagrant.

Воспользуемся box'ом с сайта Vagrant (каждый box в себя включает как минимум установленный Chef, Puppet — это нам очень пригодится чуть позже).

Конечный Vagrantfile файл будет выглядеть следующим образом (стандартные комментарии удалены, смотрите их в документации):

Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant::Config.run do |config|
  # имя box'a
  config.vm.box = "precise64"
  
  # ссылка, откуда можно скачать данный box
  config.vm.box_url = "http://files.vagrantup.com/precise64.box"
  
  # по данному IP можно будет добраться до виртуальной машины
  config.vm.network :hostonly, "11.11.11.11"
  
  # сообщаем о том, что между виртуальной машиной и реальной будут общие папки, автоматически синхронизируемые
  config.vm.share_folder "www", "/var/www", "www", :create => true

  # настраиваем Chef
  config.vm.provision :chef_solo do |chef|
    chef.cookbooks_path = "recipes/cookbooks"
    chef.roles_path = "recipes/roles"
    chef.add_role "web"
    # chef.data_bags_path = "../my-recipes/data_bags"
  
    chef.json = {

        "mysql" => {
            "server_root_password" => "%your_pass0%",			
	    "server_repl_password" => "%your_pass1%",
	    "server_debian_password" => "%your_pass2%"
       }
  }
  end

end




Используется Ruby для описания конфигурационного файла.
Описывать все детали и мелочи Vagrant здесь нет смысла, их можно (и даже нужно) прочитать в документации. Она, к слову, написана хорошо.

В файле мы указываем имя для box'a. Если он еще не был скачан, Vagrant сделает это автоматически и сохранит на жестком диске. Для этого там и указан URL, где box может быть найден. Есть возможность указать и путь в файловой системе.

В свойстве network мы указываем, что ВМ будет доступна по IP 11.11.11.11. Это сделано для того, чтобы иметь возможность создания и использования нескольких проектов, определяя им имена и занося в hosts файл нашего реального компьютера.

Здесь можно использовать также порты: в этом примере

...
config.vm.forward_port 80, 8080
...


мы настраиваем ВМ так, что по порту 8080 из host-машины мы попадаем на 80 порт guest-машины. (в документации Vagrant host-машина — это наш компьютер, guest-машина — виртуальная машина). Подробнее здесь.

Свойство share_folder позволяет настроить общие папки для host-машины и guest-машины. Это очень удобно. Вы открываете свою IDE и работаете с файлами, находящимися на вашем компьютере, а не на ВМ (хотя можно настроить редактор на работу с удаленными файлами), и они моментально синхронизируются. По умолчанию папка с вашим проектом будет доступна на ВМ по пути /vagrant. В нашем случае мы делаем доступной папку www на host-машине по пути /var/www на guest-машине.

Далее идут настройки Chef, которые будут описаны ниже. С помощью Chef и будет установлен весь необходимый софт.
Тут у нас есть выбор, можно использовать:

  1. Chef
  2. Puppet
  3. bash скрипты


Chef



Chef — утилита для управления конфигурациями, деплоя проекта, и многого другого. В связке с Vagrant мы будем использовать Chef для установки всего ПО, а также для создания VirtualHost и папок нового проекта. Ссылки на интересные статьи по использованию Chef в кластерах приведены в конце статьи.

Тут может возникнуть вопрос — как же всё-таки установить столько всего автоматически? Тут на помощь приходит большое сообщество Chef и официальные cookbooks от его создателей.

Cookbook — это совокупность рецептов, шаблонов, атрибутов и других файлов настроек для Chef. Например, есть cookbook Apache2, с помощью которого Chef поставит вам apache на вашу ОС.
Не понятно, что такое рецепты, шаблоны, атрибуты? Не бойтесь, есть отличная статья, которая прольет свет и поможет вам разобраться с Chef очень быстро. Ниже в статье мы создадим свой собственный cookbook и все станет еще прозрачней.

Для установки всего необходимого софта, мы будем использовать следующие существующие cookbooks:

  1. Apache2
  2. MySQL
  3. PHP
  4. Vim
  5. Composer
  6. и другие (некоторые cookbooks зависят от других, поэтому придётся ставить их дополнительно)


Именно для Chef'a в нашей структуре директорий существует папка recipes.

Процесс установки ПО


Для удобства можно установить Chef на host-машине, чтобы использовать knife для генерации базовой структуры папок для нового cookbook. Этот шаг абсолютно необязательный.

Под root'ом запускаем следующую команду:

curl -L https://www.opscode.com/chef/install.sh | bash


В корне нашего проекта делаем конфиг для Knife:

mkdir .chef
echo "cookbook_path [ '/path-to/recipes/cookbooks' ]" > .chef/knife.rb


Создаём наш собственный cookbook. Он будет выполняться после стандартных, когда весь софт уже установлен, и будет создавать VirtualHost с заданным именем домена и с заданным путём к проекту, а также создавать базу данных с заданным именем. Назовем его app.

knife cookbook create app


Наш cookbook будет зависеть от стандартного Database и, естественно, от Apache2, поэтому добавим зависимости:

/path-to/recipes/cookbooks/app/metadata.rb
name             'app'
maintainer       'YOUR_COMPANY_NAME'
maintainer_email 'YOUR_EMAIL'
license          'All rights reserved'
description      'Installs/Configures app'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version          '0.1.0'

depends "apache2"
depends "database"



Установим для примера cookbook database. Так как я установил Chef локально, то могу воспользоваться возможностями knife. В противном случае можно просто скачать с github и скопировать в папку /path-to/recipes/cookbooks:

cd recipes/cookbooks/
knife cookbook site download database
tar zxf database-*.tar.gz
rm *.tar.gz


Так же устанавливается любой другой необходимый нам cookbook.

Создание VirtualHost для Apache


Создаём шаблон:

/path-to/recipes/cookbooks/app/templates/default/vhost.erb
<VirtualHost *:80>
   ServerAdmin <%= @params[:server_email] %>
   ServerName <%= @params[:server_name] %>
   DocumentRoot <%= @params[:docroot] %>
    
   <Directory <%= @params[:docroot] %>>
      Options Indexes FollowSymLinks MultiViews
      AllowOverride ALL
      Order allow,deny
      Allow from all
   </Directory>
  
   ErrorLog ${APACHE_LOG_DIR}/<%= @params[:server_name] %>.log
   LogLevel debug
</VirtualHost>



Как вы заметили, в шаблоне можно использовать переменные (задаются через атрибуты). Значения по умолчанию для них мы сохраним в отдельном файле:

/path-to/recipes/cookbooks/app/attributes/default.rb
default["app"]["database"] = "app"
default["app"]["path"] = "/var/www/vm-app"
default["app"]["server_name"] = "vm-app"
default["app"]["server_email"] = "vm.app@example.com"



И разрешим переопределять все переменный через Vagrantfile.

Vagrantfile
...
chef.json = {
    "app" => {
        "path" => "/var/www/cool-another-app",
        "server_name" => "cool-another-app",
        "server_email" => "cool@another-app.com",
        "database" => "cool_another_app_db"
    },
    "mysql" => {
        "server_root_password" => "%your_path0%",           
        "server_repl_password" => "%your_path1%",
        "server_debian_password" => "%your_path2%"
    }
}
...


Отлично, осталось с помощью Chef создать нужную папку, и создать конкретный файл виртуального хоста. Всё это можно сделать через вспомогательные функции, называемые ресурсами. Данные действия мы непосредственно пишем в рецепте:

/path-to/recipes/cookbooks/app/recipes/default.rb
#
# Cookbook Name:: app
# Recipe:: default
#
# Copyright 2013, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#


include_recipe "mysql::ruby"


# здесь мы создаём папку
directory node["app"]["path"] do
  owner "root"
  group "root"
  mode "0755"
  action :create
  recursive true
end

# а здесь создаём VirtualHost, используя наши переменные (атрибуты)
web_app 'app' do
  template 'vhost.erb'
  docroot node['app']['path']
  server_name node['app']['server_name']
  server_email node['app']['server_email']
end


При этом Chef все сделает автоматически. В нашем случае: добавит сайт в /etc/apache2/sites-available и выполнит a2ensite server_name

Список всех доступных ресурсов можно посмотреть в документации.

Создание БД


Для этого мы просто в файл /path-to/recipes/cookbooks/app/recipes/default.rb добавляем такой код:

mysql_database node['app']['database'] do
  connection ({:host => 'localhost', :username => 'root', :password => node['mysql']['server_root_password']})
  action :create
end


Список всех cookbooks, которые должны выполняться Chef'ом, настраивается в массиве run_list этом в файле:

/path-to/recipes/roles/web.json
{
  "name": "web",
  "default_attributes": { },
  "override_attributes": { },
  "json_class": "Chef::Role",
  "description": "web server role",
  "chef_type": "role",
  "run_list": ["recipe[apt]", "recipe[chef-dotdeb]", "recipe[chef-dotdeb::php54]", "recipe[apache2]", "recipe[apache2::mod_php5]", "recipe[apache2::mod_rewrite]", "recipe[php]", "recipe[mysql]", "recipe[mysql::server]", "recipe[app]", "recipe[composer]", "recipe[sqlite]", "recipe[vim]", "recipe[cron]", "recipe[ntp]"]
}


Вот и всё! Наше окружение готово к проверке. Выполняем в корне проекта:

vagrant up


После этой команды, Vagrant инициализирует указанный box и начинает устанавливать всё необходимое ПО.

Что в итоге мы имеем?



В итоге мы имеем полностью настроенную виртуальную машину. Доступ через SSH. Для этого необходимо просто выполнить

vagrant ssh


После добавления в hosts IP адреса и названия тестового сайта, вы просто открываете его в браузере на host-машине, а код выполняется на ВМ.
Важным моментом является сохранение состояния ВМ. Если этого не делать, то после каждого запуска через vagrant up, софт будет ставиться заново. При этом теряется весь смысл нашей задумки. Для решения этой ситуации, Vagrant имеет следующие команды:

  1. vagrant suspend — сохраняет текущее состояние и после команды vagrant up работа продолжается с сохраненной точки
  2. vagrant halt — выключает ВМ


После выполнения этих команд, можно смело перезагружать ОС и возобновлять работу заново.

Для уничтожения всех ресурсов, связанных с ВМ, используется команда vagrant destroy.
В некоторых статьях советуют держать базу данных на host-машине, чтобы не рисковать потерей данных.

С помощью Vagrant также можно поднимать тестовый кластер, при этом общение виртуальных машин между собой настраивается через свойство конфига network.

Полезные ссылки для чтения



Для тех, кто заинтересовался, предлагаю ознакомиться со следующими ресурсами:

Vagrant + Chef файлы окружения, которое настраивалось в этой статье.

Vagrant:

  1. docs.vagrantup.com/v2 — документация. Обязательна к прочтению.
  2. www.vagrantbox.es — список box'ов на всех популярных ОС
  3. habrahabr.ru/post/140714
  4. net.tutsplus.com/tutorials/setting-up-a-staging-environment — очень классная статья по настройке staging окружения. Обязательна к прочтению.
  5. www.phptherightway.com — php разработчикам


Chef:

  1. docs.opscode.com — официальный сайт
  2. docs.opscode.com/resource_deploy.html — deployment
  3. gettingstartedwithchef.com — обязательна к прочтению. Раскрывает все базовые вещи Chef
  4. habrahabr.ru/company/scalaxy/blog/87302





Спасибо всем, кто дочитал до конца. Надеюсь, статья оказалось полезной и вызвала у вас положительные эмоции, как это бывает с теми, кто слышит, например, про Vagrant впервые.
Заранее прошу прощения за неточности и, возможно, техническую неграмотность в том или ином проявлении.
Tags:
Hubs:
+53
Comments 35
Comments Comments 35

Articles