
Development Environment with Vagrant and Chef
- From the sandbox
- Tutorial


In this article I will try to introduce you to the wonderful Vagrant and Chef utilities by the example of automatic configuration of the development environment for a PHP developer (in fact, PHP is just an example, everything described below can be used for any technology stack).
What do we do?
We will configure the virtual machine (VM) with Ubuntu 12.04 to work on a project in PHP, namely:
- Apache
- Mysql
- PHP 5.4
- xDebug
- Memcached
- Composer
- We will immediately configure Virtual Host on a specific folder, accessible both from a virtual machine and from a real one. All this is parameterized for ease of creation and use.
- and other..
It’s a rather boring task, especially if you do it with some frequency, so we will make the computer do it on its own.
How can this help you?
- You don’t want to “clog” your system with many utilities, programs
- You want to test your code in production-like conditions
- You want to test your code on different versions of a particular platform (remember how Travis tests builds in various configurations, for example Symfony on different versions of PHP)
- You do not want to help a new person on a project (layout designer, programmer) install everything from scratch
- Do you want each person in the team to have an identical environment for working on a project
All this is a reality. The question is "how?"
Vagrant
Vagrant is a utility that allows you to create a virtual machine and configure it automatically as you specified. Out of the box, Vagrant works with VirtualBox, although there is support for other solutions.
Looking ahead, all you need to deploy the environment on the computer is to execute one command:
vagrant up
Everything will be done automatically. Let's get down to our task.
To configure Vagrant uses only one file - Vagrantfile . It is in it that everything that needs to be done when starting the virtual machine is described. To initialize a Vagrant project, you must run the command
vagrant init
at the root of your project.
The directory structure will be as follows:
recipes
www
Vagrantfile
One of the main concepts in Vagrant is box. Box is an archive that contains an image of a virtual machine and a settings file for Vagrant itself.
We will use the box from the Vagrant website (each box includes at least Chef and Puppet installed - this will be very useful to us a bit later).
The final Vagrantfile file will look like this (standard comments are deleted, see them in the documentation):
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
Used by Ruby to describe the configuration file.
It makes no sense to describe all the details and trivia of Vagrant; you can (and even need to) read them in the documentation. She, by the way, is well written.
In the file, we indicate the name for box. If it has not already been downloaded, Vagrant will do this automatically and save it to your hard drive. For this, the URL is indicated where box can be found. It is possible to specify the path in the file system.
In the network property, we indicate that the VM will be available on IP 11.11.11.11. This is done in order to be able to create and use several projects, determining their names and entering the file of our real computer in the hosts.
You can also use ports here: in this example
...
config.vm.forward_port 80, 8080
...
we configure the VM so that on port 8080 from the host machine we get to port 80 of the guest machine. (in the Vagrant documentation, the host machine is our computer, the guest machine is a virtual machine). More details here .
The share_folder property allows you to configure shared folders for the host machine and guest machine. It is very comfortable. You open your IDE and work with files located on your computer, and not on a VM (although you can configure the editor to work with deleted files), and they are instantly synchronized. By default, the folder with your project will be available on the VM along the way
/vagrant
. In our case, we make the folder available www
on the host machine along the path /var/www
on the guest machine.Next come the Chef settings, which will be described below. With Chef, all the necessary software will be installed.
Here we have a choice , you can use:
- Chef
- Puppet
- bash scripts
Chef
Chef - a utility for configuration management, deployment of the project, and much more. In conjunction with Vagrant, we will use Chef to install all the software, as well as to create VirtualHost and the folders of the new project. Links to interesting articles on using Chef in clusters are provided at the end of the article.
This may raise the question - how is it all the same to install so many things automatically? A large Chef community and official cookbooks from its creators come to the rescue .
A cookbook is a collection of recipes, templates, attributes, and other settings files for Chef. For example, there is an Apache2 cookbook with which Chef will install apache on your OS.
It is not clear what recipes, templates, attributes are? Don't be afraid eatA great article that will shed some light and help you deal with Chef very quickly. Later in the article we will create our own cookbook and everything will become even more transparent.
To install all the necessary software, we will use the following existing cookbooks:
- Apache2
- MySQL
- Php
- Vim
- Composer
- and others (some cookbooks depend on others, so you have to install them additionally)
It is for Chef that the recipes folder exists in our directory structure .
Software installation process
For convenience, you can install Chef on the host machine to use knife to generate the basic folder structure for the new cookbook. This step is completely optional.
Under root, run the following command:
curl -L https://www.opscode.com/chef/install.sh | bash
At the root of our project we make a config for Knife:
mkdir .chef
echo "cookbook_path [ '/path-to/recipes/cookbooks' ]" > .chef/knife.rb
We create our own cookbook. It will be executed after the standard ones, when all the software is already installed, and will create VirtualHost with the given domain name and with the given path to the project, as well as create a database with the given name. Call it app .
knife cookbook create app
Our cookbook will depend on the standard Database and, naturally, on Apache2 , so add dependencies:
/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"
Install for example cookbook database . Since I installed Chef locally, I can use the capabilities of knife. Otherwise, you can simply download from github and copy it to the / path-to / recipes / cookbooks folder :
cd recipes/cookbooks/
knife cookbook site download database
tar zxf database-*.tar.gz
rm *.tar.gz
Any other cookbook we need is also installed.
Creating VirtualHost for Apache
Create a template:
/path-to/recipes/cookbooks/app/templates/default/vhost.erb
ServerAdmin <%= @params[:server_email] %>
ServerName <%= @params[:server_name] %>
DocumentRoot <%= @params[:docroot] %>
>
Options Indexes FollowSymLinks MultiViews
AllowOverride ALL
Order allow,deny
Allow from all
ErrorLog ${APACHE_LOG_DIR}/<%= @params[:server_name] %>.log
LogLevel debug
As you noticed, you can use variables in the template (set through attributes). We will save the default values for them in a separate file:
/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"
And let’s override all the variable through 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%"
}
}
...
Great, it remains with Chef to create the desired folder, and create a specific virtual host file. All this can be done through auxiliary functions called resources. We directly write these actions in the recipe:
/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
At the same time, Chef will do everything automatically. In our case: add the site to / etc / apache2 / sites-available and execute a2ensite server_name
A list of all available resources can be found in the documentation .
DB creation
To do this, we simply add the following code to the /path-to/recipes/cookbooks/app/recipes/default.rb file :
mysql_database node['app']['database'] do
connection ({:host => 'localhost', :username => 'root', :password => node['mysql']['server_root_password']})
action :create
end
The list of all cookbooks that should be executed by Chef is configured in the run_list array of this in the file:
/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]"]
}
That's all! Our environment is ready for verification. We execute in the root of the project:
vagrant up
After this command, Vagrant initializes the specified box and starts installing all the necessary software.
What do we have in the end?
As a result, we have a fully configured virtual machine. Access via SSH. To do this, simply execute
vagrant ssh
After adding the IP address and name of the test site to hosts, you simply open it in a browser on the host machine, and the code is executed on the VM.
An important point is maintaining the state of the VM. If this is not done, then after each launch through
vagrant up
, the software will be reinstalled . At the same time, the whole point of our idea is lost. To solve this situation, Vagrant has the following commands:- vagrant suspend - saves the current state and after the command
vagrant up
operation continues from the saved point - vagrant halt - turn off the VM
After executing these commands, you can safely reboot the OS and resume work again.
To destroy all resources associated with the VM, use the vagrant destroy command .
Some articles advise keeping the database on the host machine so as not to risk data loss.
Using Vagrant, you can also raise a test cluster, while the communication of virtual machines with each other is configured through the network config property .
Useful reading links
For those who are interested, I suggest that you familiarize yourself with the following resources:
Vagrant + Chef environment files, which was configured in this article.
Vagrant:
- docs.vagrantup.com/v2 - documentation. Required reading.
- www.vagrantbox.es — список box'ов на всех популярных ОС
- habrahabr.ru/post/140714
- net.tutsplus.com/tutorials/setting-up-a-staging-environment — очень классная статья по настройке staging окружения. Обязательна к прочтению.
- www.phptherightway.com — php разработчикам
Chef:
- docs.opscode.com — официальный сайт
- docs.opscode.com/resource_deploy.html — deployment
- gettingstartedwithchef.com — обязательна к прочтению. Раскрывает все базовые вещи Chef
- habrahabr.ru/company/scalaxy/blog/87302
Thanks to everyone who read to the end. I hope the article turned out to be useful and aroused positive emotions in you, as it happens with those who hear, for example, about Vagrant for the first time.
I apologize in advance for inaccuracies and, possibly, technical illiteracy in one form or another.